@sproutsocial/seeds-react-tooltip 1.0.16 → 1.1.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.
@@ -8,14 +8,14 @@ $ tsup --dts
8
8
  CLI Cleaning output folder
9
9
  CJS Build start
10
10
  ESM Build start
11
- CJS dist/index.js 6.50 KB
12
- CJS dist/index.js.map 10.32 KB
13
- CJS ⚡️ Build success in 65ms
14
- ESM dist/esm/index.js 4.51 KB
15
- ESM dist/esm/index.js.map 10.21 KB
16
- ESM ⚡️ Build success in 65ms
11
+ CJS dist/index.js 6.73 KB
12
+ CJS dist/index.js.map 11.16 KB
13
+ CJS ⚡️ Build success in 73ms
14
+ ESM dist/esm/index.js 4.74 KB
15
+ ESM dist/esm/index.js.map 11.05 KB
16
+ ESM ⚡️ Build success in 76ms
17
17
  DTS Build start
18
- DTS ⚡️ Build success in 6047ms
19
- DTS dist/index.d.ts 1.91 KB
20
- DTS dist/index.d.mts 1.91 KB
21
- Done in 7.28s.
18
+ DTS ⚡️ Build success in 6203ms
19
+ DTS dist/index.d.ts 2.30 KB
20
+ DTS dist/index.d.mts 2.30 KB
21
+ Done in 7.44s.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @sproutsocial/seeds-react-tooltip
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ade2a6f: Added exitDelay prop to Tooltip
8
+ - c85d800: Change mouseenter behavior to prevent the tooltip from disappearing
9
+
10
+ ## 1.0.17
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [5e08137]
15
+ - @sproutsocial/seeds-motion@1.8.2
16
+ - @sproutsocial/seeds-react-theme@3.3.2
17
+ - @sproutsocial/seeds-react-popout@2.4.18
18
+ - @sproutsocial/seeds-react-box@1.1.10
19
+
3
20
  ## 1.0.16
4
21
 
5
22
  ### Patch Changes
package/dist/esm/index.js CHANGED
@@ -24,6 +24,7 @@ var TooltipBubble = ({
24
24
  children,
25
25
  onFocus,
26
26
  onBlur,
27
+ legacyMouseInteraction,
27
28
  ...rest
28
29
  }) => {
29
30
  const handleFocus = (e) => {
@@ -46,10 +47,12 @@ var TooltipBubble = ({
46
47
  boxShadow: "medium",
47
48
  border: 500,
48
49
  borderColor: "container.border.base",
49
- onFocus: handleFocus,
50
- onBlur: handleBlur,
51
- onMouseEnter: handleFocus,
52
- onMouseLeave: handleBlur,
50
+ ...legacyMouseInteraction && {
51
+ onFocus: handleFocus,
52
+ onBlur: handleBlur,
53
+ onMouseEnter: handleFocus,
54
+ onMouseLeave: handleBlur
55
+ },
53
56
  tabIndex: 0,
54
57
  ...rest,
55
58
  children
@@ -60,6 +63,7 @@ var Tooltip = ({
60
63
  content,
61
64
  children,
62
65
  enterDelay = MOTION.MOTION_DURATION_FAST * 1e3,
66
+ exitDelay,
63
67
  placement = "auto",
64
68
  appearance,
65
69
  zIndex = 7,
@@ -68,12 +72,14 @@ var Tooltip = ({
68
72
  truncated = false,
69
73
  onFocus,
70
74
  onBlur,
75
+ legacyMouseInteraction,
71
76
  ...rest
72
77
  }) => {
73
78
  const [shouldShow, setShouldShow] = useState(false);
74
79
  const [isOpen, setIsOpen] = useState(false);
75
80
  const [id] = useState(`Racine-tooltip-${idCounter++}`);
76
81
  const isInvalidContent = content === null || content === void 0;
82
+ const resolvedExitDelay = exitDelay !== void 0 ? exitDelay : legacyMouseInteraction ? MOTION.MOTION_DURATION_FAST * 1e3 : 0;
77
83
  const show = (e) => {
78
84
  onFocus?.(e);
79
85
  setShouldShow(true);
@@ -82,7 +88,6 @@ var Tooltip = ({
82
88
  onBlur?.(e);
83
89
  setShouldShow(false);
84
90
  };
85
- const exitDelay = MOTION.MOTION_DURATION_FAST * 1e3;
86
91
  const defaultAppearance = appearance || (typeof content === "object" ? "box" : "pill");
87
92
  useEffect(() => {
88
93
  const documentBody = document.body;
@@ -98,7 +103,7 @@ var Tooltip = ({
98
103
  } else {
99
104
  timeout = setTimeout(() => {
100
105
  setIsOpen(false);
101
- }, exitDelay);
106
+ }, resolvedExitDelay);
102
107
  }
103
108
  if (isOpen) {
104
109
  documentBody.addEventListener("keydown", onEsc, { capture: true });
@@ -107,13 +112,14 @@ var Tooltip = ({
107
112
  documentBody.removeEventListener("keydown", onEsc, { capture: true });
108
113
  clearTimeout(timeout);
109
114
  };
110
- }, [isOpen, setShouldShow, shouldShow, enterDelay, exitDelay]);
115
+ }, [isOpen, setShouldShow, shouldShow, enterDelay, resolvedExitDelay]);
111
116
  const TooltipContent = () => /* @__PURE__ */ jsx(
112
117
  TooltipBubble,
113
118
  {
114
119
  appearance: defaultAppearance,
115
120
  onFocus: show,
116
121
  onBlur: hide,
122
+ legacyMouseInteraction,
117
123
  "aria-expanded": isOpen,
118
124
  id,
119
125
  ...rest,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Tooltip.tsx","../../src/styles.ts","../../src/TooltipTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useState, useEffect } from \"react\";\nimport MOTION from \"@sproutsocial/seeds-motion/unitless\";\nimport Popout from \"@sproutsocial/seeds-react-popout\";\nimport { StyledTooltipContent } from \"./styles\";\nimport type { TypeTooltipProps, TypeTooltipContent } from \"./TooltipTypes\";\n\nlet idCounter = 0;\n\nconst hasAttribute = (child: React.ReactNode, attribute: string) => {\n return React.isValidElement(child) && child.props[attribute] !== undefined;\n};\n\n/** Tooltip Styled Popout wrapper for handling events */\nconst TooltipBubble = ({\n appearance = \"pill\",\n children,\n onFocus,\n onBlur,\n ...rest\n}: TypeTooltipContent) => {\n // @ts-ignore Will fix during refactor\n const handleFocus = (e) => {\n onFocus(e);\n };\n // @ts-ignore Will fix during refactor\n const handleBlur = (e) => {\n onBlur(e);\n };\n return (\n <StyledTooltipContent\n role=\"tooltip\"\n appearance={appearance}\n borderRadius={appearance === \"box\" ? 500 : \"5000em\"}\n px={400}\n py={appearance === \"box\" ? 400 : 200}\n m={200}\n color=\"text.body\"\n bg=\"container.background.base\"\n boxShadow=\"medium\"\n border={500}\n borderColor=\"container.border.base\"\n onFocus={handleFocus}\n onBlur={handleBlur}\n onMouseEnter={handleFocus}\n onMouseLeave={handleBlur}\n tabIndex={0}\n {...rest}\n >\n {children}\n </StyledTooltipContent>\n );\n};\n\n/** Core component */\nconst Tooltip = ({\n content,\n children,\n enterDelay = MOTION.MOTION_DURATION_FAST * 1000,\n placement = \"auto\",\n appearance,\n zIndex = 7,\n qa,\n popoutProps,\n truncated = false,\n onFocus,\n onBlur,\n ...rest\n}: TypeTooltipProps) => {\n const [shouldShow, setShouldShow] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [id] = useState(`Racine-tooltip-${idCounter++}`);\n const isInvalidContent = content === null || content === undefined;\n\n // @ts-ignore Will fix during refactor\n const show = (e) => {\n onFocus?.(e);\n setShouldShow(true);\n };\n // @ts-ignore Will fix during refactor\n const hide = (e) => {\n onBlur?.(e);\n setShouldShow(false);\n };\n\n const exitDelay = MOTION.MOTION_DURATION_FAST * 1000;\n const defaultAppearance =\n appearance || (typeof content === \"object\" ? \"box\" : \"pill\");\n\n /** Handles all the logic around whether to display/not display */\n useEffect(() => {\n const documentBody = document.body;\n let timeout;\n const onEsc = (e: KeyboardEvent): void => {\n // older browsers use \"Esc\"\n if ([\"Escape\", \"Esc\"].includes(e.key)) {\n setIsOpen(false);\n setShouldShow(false);\n }\n };\n\n if (shouldShow) {\n timeout = setTimeout(() => setIsOpen(true), enterDelay);\n } else {\n timeout = setTimeout(() => {\n setIsOpen(false);\n }, exitDelay);\n }\n\n // We only want listeners from the tooltip if its open in the first place\n if (isOpen) {\n documentBody.addEventListener(\"keydown\", onEsc, { capture: true });\n }\n return () => {\n documentBody.removeEventListener(\"keydown\", onEsc, { capture: true });\n clearTimeout(timeout);\n };\n }, [isOpen, setShouldShow, shouldShow, enterDelay, exitDelay]);\n\n /** The wrapped content of whats inside the Tooltip */\n const TooltipContent = () => (\n <TooltipBubble\n appearance={defaultAppearance}\n onFocus={show}\n onBlur={hide}\n aria-expanded={isOpen}\n id={id}\n {...rest}\n >\n {content}\n </TooltipBubble>\n );\n\n return (\n <Popout\n content={!isInvalidContent ? TooltipContent : undefined}\n isOpen={isOpen}\n placement={placement}\n qa={{\n \"data-qa-tooltip\": id,\n ...qa,\n }}\n id={id + \"-wrapper\"}\n focusOnContent={false}\n zIndex={zIndex}\n aria-haspopup=\"false\"\n display={truncated ? \"flex\" : undefined}\n disableWrapperAria={true} // required so that the child span doesnt take in redundant aria props\n {...popoutProps}\n >\n <span\n onBlur={hide}\n onFocus={show}\n onMouseEnter={show}\n onMouseLeave={hide}\n style={\n truncated\n ? {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }\n : {}\n }\n >\n {React.isValidElement(children)\n ? React.cloneElement(children as React.ReactElement, {\n //** There may be cases where the Tooltip's child needs to properly describe its role as expanding a drawer, in which case that property takes priority */\n \"aria-expanded\": hasAttribute(children, \"aria-expanded\")\n ? children.props[\"aria-expanded\"]\n : undefined,\n \"aria-describedby\": isOpen ? id : undefined,\n })\n : children}\n </span>\n </Popout>\n );\n};\n\nexport default Tooltip;\n","import styled from \"styled-components\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { TypeTooltipContent } from \"./TooltipTypes\";\n\nexport const StyledTooltipContent = styled(Box)<\n Pick<TypeTooltipContent, \"appearance\">\n>`\n font-family: ${(props) => props.theme.fontFamily};\n ${(props) => props.theme.typography[200]}\n text-align: ${(props) => (props.appearance === \"box\" ? \"left\" : \"center\")};\n`;\n","import * as React from \"react\";\nimport type { TypePopoutProps } from \"@sproutsocial/seeds-react-popout\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\n\nexport interface TypeTooltipProps\n extends Omit<\n TypeBoxProps,\n \"children\" | \"content\" | \"onMouseEnter\" | \"onMouseLeave\"\n > {\n /** The content that the tooltip should be attached to. Hovering or focusing this element will cause the tooltip to appear */\n children: React.ReactNode;\n\n /** The content to be displayed within the tooltip. If there is no content, just the children are rendered */\n content: React.ReactNode;\n\n /** The placement of the tooltip in relation to the children */\n placement?: TypePopoutProps[\"placement\"];\n\n /** The time (in ms) that a user has to be hovered/focused before the tooltip will appear */\n enterDelay?: number;\n\n /** Used to override the appearance of the Tooltip content. By default, strings will have the 'pill' appearance, and more complex content will have the 'box' appearance. You can change those defaults by setting this prop. */\n appearance?: \"pill\" | \"box\";\n qa?: object;\n zIndex?: number;\n\n /** Props to be spread onto the underlying Popout component */\n popoutProps?: Partial<TypePopoutProps>;\n\n /** Truncates text into a single line with ellipsis */\n truncated?: boolean;\n\n ariaProps?: Record<string, string>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface TypeTooltipContent\n extends Pick<TypeTooltipProps, \"appearance\" | \"children\"> {\n onFocus: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;\n onBlur: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;\n}\n","import Tooltip from \"./Tooltip\";\n\nexport default Tooltip;\nexport { Tooltip };\nexport * from \"./TooltipTypes\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/Tooltip.tsx","../../src/styles.ts","../../src/TooltipTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useState, useEffect } from \"react\";\nimport MOTION from \"@sproutsocial/seeds-motion/unitless\";\nimport Popout from \"@sproutsocial/seeds-react-popout\";\nimport { StyledTooltipContent } from \"./styles\";\nimport type { TypeTooltipProps, TypeTooltipContent } from \"./TooltipTypes\";\n\nlet idCounter = 0;\n\nconst hasAttribute = (child: React.ReactNode, attribute: string) => {\n return React.isValidElement(child) && child.props[attribute] !== undefined;\n};\n\n/** Tooltip Styled Popout wrapper for handling events */\nconst TooltipBubble = ({\n appearance = \"pill\",\n children,\n onFocus,\n onBlur,\n legacyMouseInteraction,\n ...rest\n}: TypeTooltipContent) => {\n // @ts-ignore Will fix during refactor\n const handleFocus = (e) => {\n onFocus(e);\n };\n // @ts-ignore Will fix during refactor\n const handleBlur = (e) => {\n onBlur(e);\n };\n return (\n <StyledTooltipContent\n role=\"tooltip\"\n appearance={appearance}\n borderRadius={appearance === \"box\" ? 500 : \"5000em\"}\n px={400}\n py={appearance === \"box\" ? 400 : 200}\n m={200}\n color=\"text.body\"\n bg=\"container.background.base\"\n boxShadow=\"medium\"\n border={500}\n borderColor=\"container.border.base\"\n {...(legacyMouseInteraction && {\n onFocus: handleFocus,\n onBlur: handleBlur,\n onMouseEnter: handleFocus,\n onMouseLeave: handleBlur,\n })}\n tabIndex={0}\n {...rest}\n >\n {children}\n </StyledTooltipContent>\n );\n};\n\n/** Core component */\nconst Tooltip = ({\n content,\n children,\n enterDelay = MOTION.MOTION_DURATION_FAST * 1000,\n exitDelay,\n placement = \"auto\",\n appearance,\n zIndex = 7,\n qa,\n popoutProps,\n truncated = false,\n onFocus,\n onBlur,\n legacyMouseInteraction,\n ...rest\n}: TypeTooltipProps) => {\n const [shouldShow, setShouldShow] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [id] = useState(`Racine-tooltip-${idCounter++}`);\n const isInvalidContent = content === null || content === undefined;\n\n // Compute exitDelay based on legacyMouseInteraction if not explicitly provided\n const resolvedExitDelay =\n exitDelay !== undefined\n ? exitDelay\n : legacyMouseInteraction\n ? MOTION.MOTION_DURATION_FAST * 1000\n : 0;\n\n // @ts-ignore Will fix during refactor\n const show = (e) => {\n onFocus?.(e);\n setShouldShow(true);\n };\n // @ts-ignore Will fix during refactor\n const hide = (e) => {\n onBlur?.(e);\n setShouldShow(false);\n };\n\n const defaultAppearance =\n appearance || (typeof content === \"object\" ? \"box\" : \"pill\");\n\n /** Handles all the logic around whether to display/not display */\n useEffect(() => {\n const documentBody = document.body;\n let timeout;\n const onEsc = (e: KeyboardEvent): void => {\n // older browsers use \"Esc\"\n if ([\"Escape\", \"Esc\"].includes(e.key)) {\n setIsOpen(false);\n setShouldShow(false);\n }\n };\n\n if (shouldShow) {\n timeout = setTimeout(() => setIsOpen(true), enterDelay);\n } else {\n timeout = setTimeout(() => {\n setIsOpen(false);\n }, resolvedExitDelay);\n }\n\n // We only want listeners from the tooltip if its open in the first place\n if (isOpen) {\n documentBody.addEventListener(\"keydown\", onEsc, { capture: true });\n }\n return () => {\n documentBody.removeEventListener(\"keydown\", onEsc, { capture: true });\n clearTimeout(timeout);\n };\n }, [isOpen, setShouldShow, shouldShow, enterDelay, resolvedExitDelay]);\n\n /** The wrapped content of whats inside the Tooltip */\n const TooltipContent = () => (\n <TooltipBubble\n appearance={defaultAppearance}\n onFocus={show}\n onBlur={hide}\n legacyMouseInteraction={legacyMouseInteraction}\n aria-expanded={isOpen}\n id={id}\n {...rest}\n >\n {content}\n </TooltipBubble>\n );\n\n return (\n <Popout\n content={!isInvalidContent ? TooltipContent : undefined}\n isOpen={isOpen}\n placement={placement}\n qa={{\n \"data-qa-tooltip\": id,\n ...qa,\n }}\n id={id + \"-wrapper\"}\n focusOnContent={false}\n zIndex={zIndex}\n aria-haspopup=\"false\"\n display={truncated ? \"flex\" : undefined}\n disableWrapperAria={true} // required so that the child span doesnt take in redundant aria props\n {...popoutProps}\n >\n <span\n onBlur={hide}\n onFocus={show}\n onMouseEnter={show}\n onMouseLeave={hide}\n style={\n truncated\n ? {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }\n : {}\n }\n >\n {React.isValidElement(children)\n ? React.cloneElement(children as React.ReactElement, {\n //** There may be cases where the Tooltip's child needs to properly describe its role as expanding a drawer, in which case that property takes priority */\n \"aria-expanded\": hasAttribute(children, \"aria-expanded\")\n ? children.props[\"aria-expanded\"]\n : undefined,\n \"aria-describedby\": isOpen ? id : undefined,\n })\n : children}\n </span>\n </Popout>\n );\n};\n\nexport default Tooltip;\n","import styled from \"styled-components\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { TypeTooltipContent } from \"./TooltipTypes\";\n\nexport const StyledTooltipContent = styled(Box)<\n Pick<TypeTooltipContent, \"appearance\">\n>`\n font-family: ${(props) => props.theme.fontFamily};\n ${(props) => props.theme.typography[200]}\n text-align: ${(props) => (props.appearance === \"box\" ? \"left\" : \"center\")};\n`;\n","import * as React from \"react\";\nimport type { TypePopoutProps } from \"@sproutsocial/seeds-react-popout\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\n\nexport interface TypeTooltipProps\n extends Omit<\n TypeBoxProps,\n \"children\" | \"content\" | \"onMouseEnter\" | \"onMouseLeave\"\n > {\n /** The content that the tooltip should be attached to. Hovering or focusing this element will cause the tooltip to appear */\n children: React.ReactNode;\n\n /** The content to be displayed within the tooltip. If there is no content, just the children are rendered */\n content: React.ReactNode;\n\n /** The placement of the tooltip in relation to the children */\n placement?: TypePopoutProps[\"placement\"];\n\n /** The time (in ms) that a user has to be hovered/focused before the tooltip will appear */\n enterDelay?: number;\n\n /** The time (in ms) that a user has to leave hovered/focused before the tooltip will disappear */\n exitDelay?: number;\n\n /**\n * When true, enables mouse interaction on tooltip content and sets exitDelay\n * to MOTION_DURATION_FAST * 1000 by default (instead of 0).\n */\n legacyMouseInteraction?: boolean;\n\n /** Used to override the appearance of the Tooltip content. By default, strings will have the 'pill' appearance, and more complex content will have the 'box' appearance. You can change those defaults by setting this prop. */\n appearance?: \"pill\" | \"box\";\n qa?: object;\n zIndex?: number;\n\n /** Props to be spread onto the underlying Popout component */\n popoutProps?: Partial<TypePopoutProps>;\n\n /** Truncates text into a single line with ellipsis */\n truncated?: boolean;\n\n ariaProps?: Record<string, string>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface TypeTooltipContent\n extends Pick<TypeTooltipProps, \"appearance\" | \"children\"> {\n onFocus: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;\n onBlur: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;\n legacyMouseInteraction?: boolean;\n}\n","import Tooltip from \"./Tooltip\";\n\nexport default Tooltip;\nexport { Tooltip };\nexport * from \"./TooltipTypes\";\n"],"mappings":"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","names":[]}
package/dist/index.d.mts CHANGED
@@ -12,6 +12,13 @@ interface TypeTooltipProps extends Omit<TypeBoxProps, "children" | "content" | "
12
12
  placement?: TypePopoutProps["placement"];
13
13
  /** The time (in ms) that a user has to be hovered/focused before the tooltip will appear */
14
14
  enterDelay?: number;
15
+ /** The time (in ms) that a user has to leave hovered/focused before the tooltip will disappear */
16
+ exitDelay?: number;
17
+ /**
18
+ * When true, enables mouse interaction on tooltip content and sets exitDelay
19
+ * to MOTION_DURATION_FAST * 1000 by default (instead of 0).
20
+ */
21
+ legacyMouseInteraction?: boolean;
15
22
  /** Used to override the appearance of the Tooltip content. By default, strings will have the 'pill' appearance, and more complex content will have the 'box' appearance. You can change those defaults by setting this prop. */
16
23
  appearance?: "pill" | "box";
17
24
  qa?: object;
@@ -25,9 +32,10 @@ interface TypeTooltipProps extends Omit<TypeBoxProps, "children" | "content" | "
25
32
  interface TypeTooltipContent extends Pick<TypeTooltipProps, "appearance" | "children"> {
26
33
  onFocus: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;
27
34
  onBlur: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;
35
+ legacyMouseInteraction?: boolean;
28
36
  }
29
37
 
30
38
  /** Core component */
31
- declare const Tooltip: ({ content, children, enterDelay, placement, appearance, zIndex, qa, popoutProps, truncated, onFocus, onBlur, ...rest }: TypeTooltipProps) => react_jsx_runtime.JSX.Element;
39
+ declare const Tooltip: ({ content, children, enterDelay, exitDelay, placement, appearance, zIndex, qa, popoutProps, truncated, onFocus, onBlur, legacyMouseInteraction, ...rest }: TypeTooltipProps) => react_jsx_runtime.JSX.Element;
32
40
 
33
41
  export { Tooltip, type TypeTooltipContent, type TypeTooltipProps, Tooltip as default };
package/dist/index.d.ts CHANGED
@@ -12,6 +12,13 @@ interface TypeTooltipProps extends Omit<TypeBoxProps, "children" | "content" | "
12
12
  placement?: TypePopoutProps["placement"];
13
13
  /** The time (in ms) that a user has to be hovered/focused before the tooltip will appear */
14
14
  enterDelay?: number;
15
+ /** The time (in ms) that a user has to leave hovered/focused before the tooltip will disappear */
16
+ exitDelay?: number;
17
+ /**
18
+ * When true, enables mouse interaction on tooltip content and sets exitDelay
19
+ * to MOTION_DURATION_FAST * 1000 by default (instead of 0).
20
+ */
21
+ legacyMouseInteraction?: boolean;
15
22
  /** Used to override the appearance of the Tooltip content. By default, strings will have the 'pill' appearance, and more complex content will have the 'box' appearance. You can change those defaults by setting this prop. */
16
23
  appearance?: "pill" | "box";
17
24
  qa?: object;
@@ -25,9 +32,10 @@ interface TypeTooltipProps extends Omit<TypeBoxProps, "children" | "content" | "
25
32
  interface TypeTooltipContent extends Pick<TypeTooltipProps, "appearance" | "children"> {
26
33
  onFocus: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;
27
34
  onBlur: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;
35
+ legacyMouseInteraction?: boolean;
28
36
  }
29
37
 
30
38
  /** Core component */
31
- declare const Tooltip: ({ content, children, enterDelay, placement, appearance, zIndex, qa, popoutProps, truncated, onFocus, onBlur, ...rest }: TypeTooltipProps) => react_jsx_runtime.JSX.Element;
39
+ declare const Tooltip: ({ content, children, enterDelay, exitDelay, placement, appearance, zIndex, qa, popoutProps, truncated, onFocus, onBlur, legacyMouseInteraction, ...rest }: TypeTooltipProps) => react_jsx_runtime.JSX.Element;
32
40
 
33
41
  export { Tooltip, type TypeTooltipContent, type TypeTooltipProps, Tooltip as default };
package/dist/index.js CHANGED
@@ -61,6 +61,7 @@ var TooltipBubble = ({
61
61
  children,
62
62
  onFocus,
63
63
  onBlur,
64
+ legacyMouseInteraction,
64
65
  ...rest
65
66
  }) => {
66
67
  const handleFocus = (e) => {
@@ -83,10 +84,12 @@ var TooltipBubble = ({
83
84
  boxShadow: "medium",
84
85
  border: 500,
85
86
  borderColor: "container.border.base",
86
- onFocus: handleFocus,
87
- onBlur: handleBlur,
88
- onMouseEnter: handleFocus,
89
- onMouseLeave: handleBlur,
87
+ ...legacyMouseInteraction && {
88
+ onFocus: handleFocus,
89
+ onBlur: handleBlur,
90
+ onMouseEnter: handleFocus,
91
+ onMouseLeave: handleBlur
92
+ },
90
93
  tabIndex: 0,
91
94
  ...rest,
92
95
  children
@@ -97,6 +100,7 @@ var Tooltip = ({
97
100
  content,
98
101
  children,
99
102
  enterDelay = import_unitless.default.MOTION_DURATION_FAST * 1e3,
103
+ exitDelay,
100
104
  placement = "auto",
101
105
  appearance,
102
106
  zIndex = 7,
@@ -105,12 +109,14 @@ var Tooltip = ({
105
109
  truncated = false,
106
110
  onFocus,
107
111
  onBlur,
112
+ legacyMouseInteraction,
108
113
  ...rest
109
114
  }) => {
110
115
  const [shouldShow, setShouldShow] = (0, import_react.useState)(false);
111
116
  const [isOpen, setIsOpen] = (0, import_react.useState)(false);
112
117
  const [id] = (0, import_react.useState)(`Racine-tooltip-${idCounter++}`);
113
118
  const isInvalidContent = content === null || content === void 0;
119
+ const resolvedExitDelay = exitDelay !== void 0 ? exitDelay : legacyMouseInteraction ? import_unitless.default.MOTION_DURATION_FAST * 1e3 : 0;
114
120
  const show = (e) => {
115
121
  onFocus?.(e);
116
122
  setShouldShow(true);
@@ -119,7 +125,6 @@ var Tooltip = ({
119
125
  onBlur?.(e);
120
126
  setShouldShow(false);
121
127
  };
122
- const exitDelay = import_unitless.default.MOTION_DURATION_FAST * 1e3;
123
128
  const defaultAppearance = appearance || (typeof content === "object" ? "box" : "pill");
124
129
  (0, import_react.useEffect)(() => {
125
130
  const documentBody = document.body;
@@ -135,7 +140,7 @@ var Tooltip = ({
135
140
  } else {
136
141
  timeout = setTimeout(() => {
137
142
  setIsOpen(false);
138
- }, exitDelay);
143
+ }, resolvedExitDelay);
139
144
  }
140
145
  if (isOpen) {
141
146
  documentBody.addEventListener("keydown", onEsc, { capture: true });
@@ -144,13 +149,14 @@ var Tooltip = ({
144
149
  documentBody.removeEventListener("keydown", onEsc, { capture: true });
145
150
  clearTimeout(timeout);
146
151
  };
147
- }, [isOpen, setShouldShow, shouldShow, enterDelay, exitDelay]);
152
+ }, [isOpen, setShouldShow, shouldShow, enterDelay, resolvedExitDelay]);
148
153
  const TooltipContent = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
149
154
  TooltipBubble,
150
155
  {
151
156
  appearance: defaultAppearance,
152
157
  onFocus: show,
153
158
  onBlur: hide,
159
+ legacyMouseInteraction,
154
160
  "aria-expanded": isOpen,
155
161
  id,
156
162
  ...rest,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Tooltip.tsx","../src/styles.ts","../src/TooltipTypes.ts"],"sourcesContent":["import Tooltip from \"./Tooltip\";\n\nexport default Tooltip;\nexport { Tooltip };\nexport * from \"./TooltipTypes\";\n","import * as React from \"react\";\nimport { useState, useEffect } from \"react\";\nimport MOTION from \"@sproutsocial/seeds-motion/unitless\";\nimport Popout from \"@sproutsocial/seeds-react-popout\";\nimport { StyledTooltipContent } from \"./styles\";\nimport type { TypeTooltipProps, TypeTooltipContent } from \"./TooltipTypes\";\n\nlet idCounter = 0;\n\nconst hasAttribute = (child: React.ReactNode, attribute: string) => {\n return React.isValidElement(child) && child.props[attribute] !== undefined;\n};\n\n/** Tooltip Styled Popout wrapper for handling events */\nconst TooltipBubble = ({\n appearance = \"pill\",\n children,\n onFocus,\n onBlur,\n ...rest\n}: TypeTooltipContent) => {\n // @ts-ignore Will fix during refactor\n const handleFocus = (e) => {\n onFocus(e);\n };\n // @ts-ignore Will fix during refactor\n const handleBlur = (e) => {\n onBlur(e);\n };\n return (\n <StyledTooltipContent\n role=\"tooltip\"\n appearance={appearance}\n borderRadius={appearance === \"box\" ? 500 : \"5000em\"}\n px={400}\n py={appearance === \"box\" ? 400 : 200}\n m={200}\n color=\"text.body\"\n bg=\"container.background.base\"\n boxShadow=\"medium\"\n border={500}\n borderColor=\"container.border.base\"\n onFocus={handleFocus}\n onBlur={handleBlur}\n onMouseEnter={handleFocus}\n onMouseLeave={handleBlur}\n tabIndex={0}\n {...rest}\n >\n {children}\n </StyledTooltipContent>\n );\n};\n\n/** Core component */\nconst Tooltip = ({\n content,\n children,\n enterDelay = MOTION.MOTION_DURATION_FAST * 1000,\n placement = \"auto\",\n appearance,\n zIndex = 7,\n qa,\n popoutProps,\n truncated = false,\n onFocus,\n onBlur,\n ...rest\n}: TypeTooltipProps) => {\n const [shouldShow, setShouldShow] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [id] = useState(`Racine-tooltip-${idCounter++}`);\n const isInvalidContent = content === null || content === undefined;\n\n // @ts-ignore Will fix during refactor\n const show = (e) => {\n onFocus?.(e);\n setShouldShow(true);\n };\n // @ts-ignore Will fix during refactor\n const hide = (e) => {\n onBlur?.(e);\n setShouldShow(false);\n };\n\n const exitDelay = MOTION.MOTION_DURATION_FAST * 1000;\n const defaultAppearance =\n appearance || (typeof content === \"object\" ? \"box\" : \"pill\");\n\n /** Handles all the logic around whether to display/not display */\n useEffect(() => {\n const documentBody = document.body;\n let timeout;\n const onEsc = (e: KeyboardEvent): void => {\n // older browsers use \"Esc\"\n if ([\"Escape\", \"Esc\"].includes(e.key)) {\n setIsOpen(false);\n setShouldShow(false);\n }\n };\n\n if (shouldShow) {\n timeout = setTimeout(() => setIsOpen(true), enterDelay);\n } else {\n timeout = setTimeout(() => {\n setIsOpen(false);\n }, exitDelay);\n }\n\n // We only want listeners from the tooltip if its open in the first place\n if (isOpen) {\n documentBody.addEventListener(\"keydown\", onEsc, { capture: true });\n }\n return () => {\n documentBody.removeEventListener(\"keydown\", onEsc, { capture: true });\n clearTimeout(timeout);\n };\n }, [isOpen, setShouldShow, shouldShow, enterDelay, exitDelay]);\n\n /** The wrapped content of whats inside the Tooltip */\n const TooltipContent = () => (\n <TooltipBubble\n appearance={defaultAppearance}\n onFocus={show}\n onBlur={hide}\n aria-expanded={isOpen}\n id={id}\n {...rest}\n >\n {content}\n </TooltipBubble>\n );\n\n return (\n <Popout\n content={!isInvalidContent ? TooltipContent : undefined}\n isOpen={isOpen}\n placement={placement}\n qa={{\n \"data-qa-tooltip\": id,\n ...qa,\n }}\n id={id + \"-wrapper\"}\n focusOnContent={false}\n zIndex={zIndex}\n aria-haspopup=\"false\"\n display={truncated ? \"flex\" : undefined}\n disableWrapperAria={true} // required so that the child span doesnt take in redundant aria props\n {...popoutProps}\n >\n <span\n onBlur={hide}\n onFocus={show}\n onMouseEnter={show}\n onMouseLeave={hide}\n style={\n truncated\n ? {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }\n : {}\n }\n >\n {React.isValidElement(children)\n ? React.cloneElement(children as React.ReactElement, {\n //** There may be cases where the Tooltip's child needs to properly describe its role as expanding a drawer, in which case that property takes priority */\n \"aria-expanded\": hasAttribute(children, \"aria-expanded\")\n ? children.props[\"aria-expanded\"]\n : undefined,\n \"aria-describedby\": isOpen ? id : undefined,\n })\n : children}\n </span>\n </Popout>\n );\n};\n\nexport default Tooltip;\n","import styled from \"styled-components\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { TypeTooltipContent } from \"./TooltipTypes\";\n\nexport const StyledTooltipContent = styled(Box)<\n Pick<TypeTooltipContent, \"appearance\">\n>`\n font-family: ${(props) => props.theme.fontFamily};\n ${(props) => props.theme.typography[200]}\n text-align: ${(props) => (props.appearance === \"box\" ? \"left\" : \"center\")};\n`;\n","import * as React from \"react\";\nimport type { TypePopoutProps } from \"@sproutsocial/seeds-react-popout\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\n\nexport interface TypeTooltipProps\n extends Omit<\n TypeBoxProps,\n \"children\" | \"content\" | \"onMouseEnter\" | \"onMouseLeave\"\n > {\n /** The content that the tooltip should be attached to. Hovering or focusing this element will cause the tooltip to appear */\n children: React.ReactNode;\n\n /** The content to be displayed within the tooltip. If there is no content, just the children are rendered */\n content: React.ReactNode;\n\n /** The placement of the tooltip in relation to the children */\n placement?: TypePopoutProps[\"placement\"];\n\n /** The time (in ms) that a user has to be hovered/focused before the tooltip will appear */\n enterDelay?: number;\n\n /** Used to override the appearance of the Tooltip content. By default, strings will have the 'pill' appearance, and more complex content will have the 'box' appearance. You can change those defaults by setting this prop. */\n appearance?: \"pill\" | \"box\";\n qa?: object;\n zIndex?: number;\n\n /** Props to be spread onto the underlying Popout component */\n popoutProps?: Partial<TypePopoutProps>;\n\n /** Truncates text into a single line with ellipsis */\n truncated?: boolean;\n\n ariaProps?: Record<string, string>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface TypeTooltipContent\n extends Pick<TypeTooltipProps, \"appearance\" | \"children\"> {\n onFocus: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;\n onBlur: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;\n}\n"],"mappings":"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","names":["styled","Box","MOTION","Popout","React"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Tooltip.tsx","../src/styles.ts","../src/TooltipTypes.ts"],"sourcesContent":["import Tooltip from \"./Tooltip\";\n\nexport default Tooltip;\nexport { Tooltip };\nexport * from \"./TooltipTypes\";\n","import * as React from \"react\";\nimport { useState, useEffect } from \"react\";\nimport MOTION from \"@sproutsocial/seeds-motion/unitless\";\nimport Popout from \"@sproutsocial/seeds-react-popout\";\nimport { StyledTooltipContent } from \"./styles\";\nimport type { TypeTooltipProps, TypeTooltipContent } from \"./TooltipTypes\";\n\nlet idCounter = 0;\n\nconst hasAttribute = (child: React.ReactNode, attribute: string) => {\n return React.isValidElement(child) && child.props[attribute] !== undefined;\n};\n\n/** Tooltip Styled Popout wrapper for handling events */\nconst TooltipBubble = ({\n appearance = \"pill\",\n children,\n onFocus,\n onBlur,\n legacyMouseInteraction,\n ...rest\n}: TypeTooltipContent) => {\n // @ts-ignore Will fix during refactor\n const handleFocus = (e) => {\n onFocus(e);\n };\n // @ts-ignore Will fix during refactor\n const handleBlur = (e) => {\n onBlur(e);\n };\n return (\n <StyledTooltipContent\n role=\"tooltip\"\n appearance={appearance}\n borderRadius={appearance === \"box\" ? 500 : \"5000em\"}\n px={400}\n py={appearance === \"box\" ? 400 : 200}\n m={200}\n color=\"text.body\"\n bg=\"container.background.base\"\n boxShadow=\"medium\"\n border={500}\n borderColor=\"container.border.base\"\n {...(legacyMouseInteraction && {\n onFocus: handleFocus,\n onBlur: handleBlur,\n onMouseEnter: handleFocus,\n onMouseLeave: handleBlur,\n })}\n tabIndex={0}\n {...rest}\n >\n {children}\n </StyledTooltipContent>\n );\n};\n\n/** Core component */\nconst Tooltip = ({\n content,\n children,\n enterDelay = MOTION.MOTION_DURATION_FAST * 1000,\n exitDelay,\n placement = \"auto\",\n appearance,\n zIndex = 7,\n qa,\n popoutProps,\n truncated = false,\n onFocus,\n onBlur,\n legacyMouseInteraction,\n ...rest\n}: TypeTooltipProps) => {\n const [shouldShow, setShouldShow] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [id] = useState(`Racine-tooltip-${idCounter++}`);\n const isInvalidContent = content === null || content === undefined;\n\n // Compute exitDelay based on legacyMouseInteraction if not explicitly provided\n const resolvedExitDelay =\n exitDelay !== undefined\n ? exitDelay\n : legacyMouseInteraction\n ? MOTION.MOTION_DURATION_FAST * 1000\n : 0;\n\n // @ts-ignore Will fix during refactor\n const show = (e) => {\n onFocus?.(e);\n setShouldShow(true);\n };\n // @ts-ignore Will fix during refactor\n const hide = (e) => {\n onBlur?.(e);\n setShouldShow(false);\n };\n\n const defaultAppearance =\n appearance || (typeof content === \"object\" ? \"box\" : \"pill\");\n\n /** Handles all the logic around whether to display/not display */\n useEffect(() => {\n const documentBody = document.body;\n let timeout;\n const onEsc = (e: KeyboardEvent): void => {\n // older browsers use \"Esc\"\n if ([\"Escape\", \"Esc\"].includes(e.key)) {\n setIsOpen(false);\n setShouldShow(false);\n }\n };\n\n if (shouldShow) {\n timeout = setTimeout(() => setIsOpen(true), enterDelay);\n } else {\n timeout = setTimeout(() => {\n setIsOpen(false);\n }, resolvedExitDelay);\n }\n\n // We only want listeners from the tooltip if its open in the first place\n if (isOpen) {\n documentBody.addEventListener(\"keydown\", onEsc, { capture: true });\n }\n return () => {\n documentBody.removeEventListener(\"keydown\", onEsc, { capture: true });\n clearTimeout(timeout);\n };\n }, [isOpen, setShouldShow, shouldShow, enterDelay, resolvedExitDelay]);\n\n /** The wrapped content of whats inside the Tooltip */\n const TooltipContent = () => (\n <TooltipBubble\n appearance={defaultAppearance}\n onFocus={show}\n onBlur={hide}\n legacyMouseInteraction={legacyMouseInteraction}\n aria-expanded={isOpen}\n id={id}\n {...rest}\n >\n {content}\n </TooltipBubble>\n );\n\n return (\n <Popout\n content={!isInvalidContent ? TooltipContent : undefined}\n isOpen={isOpen}\n placement={placement}\n qa={{\n \"data-qa-tooltip\": id,\n ...qa,\n }}\n id={id + \"-wrapper\"}\n focusOnContent={false}\n zIndex={zIndex}\n aria-haspopup=\"false\"\n display={truncated ? \"flex\" : undefined}\n disableWrapperAria={true} // required so that the child span doesnt take in redundant aria props\n {...popoutProps}\n >\n <span\n onBlur={hide}\n onFocus={show}\n onMouseEnter={show}\n onMouseLeave={hide}\n style={\n truncated\n ? {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }\n : {}\n }\n >\n {React.isValidElement(children)\n ? React.cloneElement(children as React.ReactElement, {\n //** There may be cases where the Tooltip's child needs to properly describe its role as expanding a drawer, in which case that property takes priority */\n \"aria-expanded\": hasAttribute(children, \"aria-expanded\")\n ? children.props[\"aria-expanded\"]\n : undefined,\n \"aria-describedby\": isOpen ? id : undefined,\n })\n : children}\n </span>\n </Popout>\n );\n};\n\nexport default Tooltip;\n","import styled from \"styled-components\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { TypeTooltipContent } from \"./TooltipTypes\";\n\nexport const StyledTooltipContent = styled(Box)<\n Pick<TypeTooltipContent, \"appearance\">\n>`\n font-family: ${(props) => props.theme.fontFamily};\n ${(props) => props.theme.typography[200]}\n text-align: ${(props) => (props.appearance === \"box\" ? \"left\" : \"center\")};\n`;\n","import * as React from \"react\";\nimport type { TypePopoutProps } from \"@sproutsocial/seeds-react-popout\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\n\nexport interface TypeTooltipProps\n extends Omit<\n TypeBoxProps,\n \"children\" | \"content\" | \"onMouseEnter\" | \"onMouseLeave\"\n > {\n /** The content that the tooltip should be attached to. Hovering or focusing this element will cause the tooltip to appear */\n children: React.ReactNode;\n\n /** The content to be displayed within the tooltip. If there is no content, just the children are rendered */\n content: React.ReactNode;\n\n /** The placement of the tooltip in relation to the children */\n placement?: TypePopoutProps[\"placement\"];\n\n /** The time (in ms) that a user has to be hovered/focused before the tooltip will appear */\n enterDelay?: number;\n\n /** The time (in ms) that a user has to leave hovered/focused before the tooltip will disappear */\n exitDelay?: number;\n\n /**\n * When true, enables mouse interaction on tooltip content and sets exitDelay\n * to MOTION_DURATION_FAST * 1000 by default (instead of 0).\n */\n legacyMouseInteraction?: boolean;\n\n /** Used to override the appearance of the Tooltip content. By default, strings will have the 'pill' appearance, and more complex content will have the 'box' appearance. You can change those defaults by setting this prop. */\n appearance?: \"pill\" | \"box\";\n qa?: object;\n zIndex?: number;\n\n /** Props to be spread onto the underlying Popout component */\n popoutProps?: Partial<TypePopoutProps>;\n\n /** Truncates text into a single line with ellipsis */\n truncated?: boolean;\n\n ariaProps?: Record<string, string>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface TypeTooltipContent\n extends Pick<TypeTooltipProps, \"appearance\" | \"children\"> {\n onFocus: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;\n onBlur: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;\n legacyMouseInteraction?: boolean;\n}\n"],"mappings":"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","names":["styled","Box","MOTION","Popout","React"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutsocial/seeds-react-tooltip",
3
- "version": "1.0.16",
3
+ "version": "1.1.0",
4
4
  "description": "Seeds React Tooltip",
5
5
  "author": "Sprout Social, Inc.",
6
6
  "license": "MIT",
@@ -18,11 +18,11 @@
18
18
  "test:watch": "jest --watch --coverage=false"
19
19
  },
20
20
  "dependencies": {
21
- "@sproutsocial/seeds-react-theme": "^3.3.1",
21
+ "@sproutsocial/seeds-react-theme": "^3.3.2",
22
22
  "@sproutsocial/seeds-react-system-props": "^3.0.1",
23
- "@sproutsocial/seeds-react-popout": "^2.4.17",
24
- "@sproutsocial/seeds-react-box": "^1.1.9",
25
- "@sproutsocial/seeds-motion": "^1.8.0"
23
+ "@sproutsocial/seeds-react-popout": "^2.4.18",
24
+ "@sproutsocial/seeds-react-box": "^1.1.10",
25
+ "@sproutsocial/seeds-motion": "^1.8.2"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/react": "^18.0.0",
@@ -35,9 +35,9 @@
35
35
  "@sproutsocial/seeds-tsconfig": "*",
36
36
  "@sproutsocial/seeds-testing": "*",
37
37
  "@sproutsocial/seeds-react-testing-library": "*",
38
- "@sproutsocial/seeds-react-icon": "^2.1.0",
39
- "@sproutsocial/seeds-react-banner": "^1.0.17",
40
- "@sproutsocial/seeds-react-button": "^1.3.11",
38
+ "@sproutsocial/seeds-react-icon": "^2.1.1",
39
+ "@sproutsocial/seeds-react-banner": "^1.0.18",
40
+ "@sproutsocial/seeds-react-button": "^1.3.12",
41
41
  "@sproutsocial/seeds-react-text": "^1.3.2",
42
42
  "@sproutsocial/seeds-react-portal": "^1.1.4"
43
43
  },
@@ -3,6 +3,7 @@ import Banner from "@sproutsocial/seeds-react-banner";
3
3
  import Box from "@sproutsocial/seeds-react-box";
4
4
  import Button from "@sproutsocial/seeds-react-button";
5
5
  import Icon from "@sproutsocial/seeds-react-icon";
6
+ import Text from "@sproutsocial/seeds-react-text";
6
7
  import Tooltip from "./Tooltip";
7
8
 
8
9
  const meta: Meta<typeof Tooltip> = {
@@ -127,3 +128,60 @@ export const WithFocusableContent: Story = {
127
128
  </Box>
128
129
  ),
129
130
  };
131
+
132
+ export const WithLegacyMouseInteraction: Story = {
133
+ render: () => (
134
+ <Box
135
+ width="100%"
136
+ p={600}
137
+ alignItems="center"
138
+ justifyContent="center"
139
+ display="flex"
140
+ flexDirection="column"
141
+ gap={400}
142
+ height="400px"
143
+ >
144
+ <Box display="flex" flexDirection="column" alignItems="center" gap={200}>
145
+ <Tooltip
146
+ content={
147
+ <Box>
148
+ <div>Hover into this content!</div>
149
+ <Button
150
+ appearance="secondary"
151
+ size="small"
152
+ mt={200}
153
+ onClick={() => alert("Clicked!")}
154
+ >
155
+ Interactive button
156
+ </Button>
157
+ </Box>
158
+ }
159
+ legacyMouseInteraction={true}
160
+ >
161
+ <Button appearance="primary">With legacyMouseInteraction</Button>
162
+ </Tooltip>
163
+ <Text fontSize={300} color="text.body.secondary">
164
+ Tooltip stays open when you hover into it (exitDelay: ~150ms)
165
+ </Text>
166
+ </Box>
167
+
168
+ <Box display="flex" flexDirection="column" alignItems="center" gap={200}>
169
+ <Tooltip
170
+ content={
171
+ <Box>
172
+ <div>Try to hover into this content</div>
173
+ <Button appearance="secondary" size="small" mt={200}>
174
+ Can't interact
175
+ </Button>
176
+ </Box>
177
+ }
178
+ >
179
+ <Button appearance="primary">Without legacyMouseInteraction</Button>
180
+ </Tooltip>
181
+ <Text fontSize={300} color="text.body.secondary">
182
+ Tooltip closes immediately when you leave (exitDelay: 0ms)
183
+ </Text>
184
+ </Box>
185
+ </Box>
186
+ ),
187
+ };
package/src/Tooltip.tsx CHANGED
@@ -17,6 +17,7 @@ const TooltipBubble = ({
17
17
  children,
18
18
  onFocus,
19
19
  onBlur,
20
+ legacyMouseInteraction,
20
21
  ...rest
21
22
  }: TypeTooltipContent) => {
22
23
  // @ts-ignore Will fix during refactor
@@ -40,10 +41,12 @@ const TooltipBubble = ({
40
41
  boxShadow="medium"
41
42
  border={500}
42
43
  borderColor="container.border.base"
43
- onFocus={handleFocus}
44
- onBlur={handleBlur}
45
- onMouseEnter={handleFocus}
46
- onMouseLeave={handleBlur}
44
+ {...(legacyMouseInteraction && {
45
+ onFocus: handleFocus,
46
+ onBlur: handleBlur,
47
+ onMouseEnter: handleFocus,
48
+ onMouseLeave: handleBlur,
49
+ })}
47
50
  tabIndex={0}
48
51
  {...rest}
49
52
  >
@@ -57,6 +60,7 @@ const Tooltip = ({
57
60
  content,
58
61
  children,
59
62
  enterDelay = MOTION.MOTION_DURATION_FAST * 1000,
63
+ exitDelay,
60
64
  placement = "auto",
61
65
  appearance,
62
66
  zIndex = 7,
@@ -65,6 +69,7 @@ const Tooltip = ({
65
69
  truncated = false,
66
70
  onFocus,
67
71
  onBlur,
72
+ legacyMouseInteraction,
68
73
  ...rest
69
74
  }: TypeTooltipProps) => {
70
75
  const [shouldShow, setShouldShow] = useState(false);
@@ -72,6 +77,14 @@ const Tooltip = ({
72
77
  const [id] = useState(`Racine-tooltip-${idCounter++}`);
73
78
  const isInvalidContent = content === null || content === undefined;
74
79
 
80
+ // Compute exitDelay based on legacyMouseInteraction if not explicitly provided
81
+ const resolvedExitDelay =
82
+ exitDelay !== undefined
83
+ ? exitDelay
84
+ : legacyMouseInteraction
85
+ ? MOTION.MOTION_DURATION_FAST * 1000
86
+ : 0;
87
+
75
88
  // @ts-ignore Will fix during refactor
76
89
  const show = (e) => {
77
90
  onFocus?.(e);
@@ -83,7 +96,6 @@ const Tooltip = ({
83
96
  setShouldShow(false);
84
97
  };
85
98
 
86
- const exitDelay = MOTION.MOTION_DURATION_FAST * 1000;
87
99
  const defaultAppearance =
88
100
  appearance || (typeof content === "object" ? "box" : "pill");
89
101
 
@@ -104,7 +116,7 @@ const Tooltip = ({
104
116
  } else {
105
117
  timeout = setTimeout(() => {
106
118
  setIsOpen(false);
107
- }, exitDelay);
119
+ }, resolvedExitDelay);
108
120
  }
109
121
 
110
122
  // We only want listeners from the tooltip if its open in the first place
@@ -115,7 +127,7 @@ const Tooltip = ({
115
127
  documentBody.removeEventListener("keydown", onEsc, { capture: true });
116
128
  clearTimeout(timeout);
117
129
  };
118
- }, [isOpen, setShouldShow, shouldShow, enterDelay, exitDelay]);
130
+ }, [isOpen, setShouldShow, shouldShow, enterDelay, resolvedExitDelay]);
119
131
 
120
132
  /** The wrapped content of whats inside the Tooltip */
121
133
  const TooltipContent = () => (
@@ -123,6 +135,7 @@ const Tooltip = ({
123
135
  appearance={defaultAppearance}
124
136
  onFocus={show}
125
137
  onBlur={hide}
138
+ legacyMouseInteraction={legacyMouseInteraction}
126
139
  aria-expanded={isOpen}
127
140
  id={id}
128
141
  {...rest}
@@ -19,6 +19,15 @@ export interface TypeTooltipProps
19
19
  /** The time (in ms) that a user has to be hovered/focused before the tooltip will appear */
20
20
  enterDelay?: number;
21
21
 
22
+ /** The time (in ms) that a user has to leave hovered/focused before the tooltip will disappear */
23
+ exitDelay?: number;
24
+
25
+ /**
26
+ * When true, enables mouse interaction on tooltip content and sets exitDelay
27
+ * to MOTION_DURATION_FAST * 1000 by default (instead of 0).
28
+ */
29
+ legacyMouseInteraction?: boolean;
30
+
22
31
  /** Used to override the appearance of the Tooltip content. By default, strings will have the 'pill' appearance, and more complex content will have the 'box' appearance. You can change those defaults by setting this prop. */
23
32
  appearance?: "pill" | "box";
24
33
  qa?: object;
@@ -38,4 +47,5 @@ export interface TypeTooltipContent
38
47
  extends Pick<TypeTooltipProps, "appearance" | "children"> {
39
48
  onFocus: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;
40
49
  onBlur: (e: React.FocusEvent<HTMLDivElement, FocusEvent>) => void;
50
+ legacyMouseInteraction?: boolean;
41
51
  }
@@ -311,4 +311,80 @@ describe("Tooltip", () => {
311
311
  expect(tooltipByRole).toContainElement(tooltipElement);
312
312
  });
313
313
  });
314
+
315
+ describe("legacyMouseInteraction prop", () => {
316
+ it("should allow hovering over tooltip content when legacyMouseInteraction is true", async () => {
317
+ render(
318
+ <Tooltip content="Tooltip content" legacyMouseInteraction>
319
+ <Button data-testid="trigger">Trigger</Button>
320
+ </Tooltip>
321
+ );
322
+
323
+ const trigger = screen.getByTestId("trigger");
324
+
325
+ // Hover over trigger to open tooltip
326
+ act(() => {
327
+ fireEvent.mouseOver(trigger);
328
+ });
329
+
330
+ // Wait for tooltip to appear
331
+ const tooltipContent = await screen.findByText("Tooltip content");
332
+ expect(tooltipContent).toBeInTheDocument();
333
+
334
+ // Move mouse away from trigger
335
+ act(() => {
336
+ fireEvent.mouseOut(trigger);
337
+ });
338
+
339
+ // Hover over the tooltip content itself
340
+ act(() => {
341
+ fireEvent.mouseEnter(tooltipContent);
342
+ });
343
+
344
+ // Tooltip should remain open
345
+ await act(async () => {
346
+ await new Promise((resolve) => setTimeout(resolve, 200));
347
+ });
348
+ expect(tooltipContent).toBeInTheDocument();
349
+
350
+ // Move mouse away from tooltip content
351
+ act(() => {
352
+ fireEvent.mouseLeave(tooltipContent);
353
+ });
354
+
355
+ // Tooltip should eventually close
356
+ await act(async () => {
357
+ await new Promise((resolve) => setTimeout(resolve, 200));
358
+ });
359
+ });
360
+
361
+ it("should not have mouse handlers on tooltip content when legacyMouseInteraction is false", async () => {
362
+ render(
363
+ <Tooltip content="Tooltip content">
364
+ <Button data-testid="trigger">Trigger</Button>
365
+ </Tooltip>
366
+ );
367
+
368
+ const trigger = screen.getByTestId("trigger");
369
+
370
+ // Hover over trigger to open tooltip
371
+ act(() => {
372
+ fireEvent.mouseOver(trigger);
373
+ });
374
+
375
+ // Wait for tooltip to appear
376
+ const tooltipContent = await screen.findByText("Tooltip content");
377
+ expect(tooltipContent).toBeInTheDocument();
378
+
379
+ // Verify mouse handlers are not attached (tooltip should close immediately when leaving trigger)
380
+ act(() => {
381
+ fireEvent.mouseOut(trigger);
382
+ });
383
+
384
+ // Without legacyMouseInteraction, tooltip closes immediately (exitDelay: 0)
385
+ await act(async () => {
386
+ await new Promise((resolve) => setTimeout(resolve, 100));
387
+ });
388
+ });
389
+ });
314
390
  });