@thecb/components 11.8.0-beta.6 → 11.8.0-beta.8

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@thecb/components",
3
- "version": "11.8.0-beta.6",
3
+ "version": "11.8.0-beta.8",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,24 +1,34 @@
1
- import React, { useState } from "react";
2
- import { themeComponent } from "../../../util/themeUtils";
1
+ import React, { useContext, useEffect, useRef, useState } from "react";
2
+ import { createThemeValues } from "../../../util/themeUtils";
3
+ import { ThemeContext } from "styled-components";
3
4
  import Text from "../../atoms/text";
4
5
  import Paragraph from "../../atoms/paragraph";
5
6
  import { Box } from "../../atoms/layouts";
6
7
  import ButtonWithAction from "../../atoms/button-with-action";
7
8
  import { noop, arrowBorder } from "../../../util/general";
8
- import { fallbackValues } from "./Tooltip.theme";
9
9
  import WarningIconXS from "../../atoms/icons/WarningIconXS";
10
+ import {
11
+ MATISSE_BLUE,
12
+ PEACOCK_BLUE,
13
+ SAPPHIRE_BLUE
14
+ } from "../../../constants/colors";
15
+
16
+ const TOOLTIP_THEME_SOURCE = "Popover";
17
+
18
+ const fallbackValues = {
19
+ hoverColor: SAPPHIRE_BLUE,
20
+ activeColor: PEACOCK_BLUE,
21
+ popoverTriggerColor: MATISSE_BLUE,
22
+ borderColor: `rgba(255, 255, 255, 0.85)`
23
+ };
10
24
 
11
25
  const Tooltip = ({
12
- tooltipContainerExtraStyles = "",
13
- themeValues,
14
- tooltipID = "tooltip-content",
26
+ tooltipID,
15
27
  hasIconTrigger = false,
16
28
  IconTrigger = WarningIconXS,
17
29
  iconHelpText = "Open the tooltip",
18
- tooltipContent = "",
19
- tooltipTriggerText = "",
20
- triggerTextExtraStyles = "",
21
- contentExtraStyles = "",
30
+ triggerText = "Open the tooltip",
31
+ tooltipContent = "The contents of the tooltip go here.",
22
32
  contentPosition = {
23
33
  top: "-110px",
24
34
  right: "auto",
@@ -35,19 +45,32 @@ const Tooltip = ({
35
45
  minWidth = "250px",
36
46
  maxWidth = "300px",
37
47
  height = "auto",
38
- buttonExtraStyles,
39
- backgroundColor = "white",
40
- borderColor = "rgba(255, 255, 255, 0.85)"
48
+ containerExtraStyles = "",
49
+ triggerExtraStyles = "",
50
+ triggerButtonVariant = "smallGhost"
41
51
  }) => {
42
- const { hoverColor, activeColor, tooltipTriggerColor } = themeValues;
43
- const { top, right, bottom, left } = contentPosition ?? {};
44
- const { arrowTop, arrowRight, arrowBottom, arrowLeft } = arrowPosition ?? {};
45
-
52
+ const closeTimeoutRef = useRef(null);
46
53
  const [tooltipOpen, setTooltipOpen] = useState(false);
54
+ const themeContext = useContext(ThemeContext);
55
+ const themeValues = createThemeValues(
56
+ themeContext,
57
+ fallbackValues,
58
+ TOOLTIP_THEME_SOURCE
59
+ );
60
+
61
+ const {
62
+ borderColor,
63
+ popoverTriggerColor: tooltipTriggerColor,
64
+ hoverColor,
65
+ activeColor
66
+ } = themeValues;
67
+
68
+ const { top, right, bottom, left } = contentPosition;
69
+ const { arrowTop, arrowRight, arrowBottom, arrowLeft } = arrowPosition;
47
70
 
48
- const handleToggleTooltip = tooltipState => {
49
- if (tooltipOpen !== tooltipState) {
50
- setTooltipOpen(tooltipState);
71
+ const handleToggleTooltip = desiredTooltipState => {
72
+ if (tooltipOpen !== desiredTooltipState) {
73
+ setTooltipOpen(desiredTooltipState);
51
74
  }
52
75
  };
53
76
 
@@ -57,27 +80,48 @@ const Tooltip = ({
57
80
  }
58
81
  };
59
82
 
83
+ const handleMouseEnter = () => {
84
+ if (closeTimeoutRef.current) {
85
+ clearTimeout(closeTimeoutRef.current);
86
+ closeTimeoutRef.current = null;
87
+ }
88
+ handleToggleTooltip(true);
89
+ };
90
+
91
+ const handleMouseLeave = () => {
92
+ closeTimeoutRef.current = setTimeout(() => {
93
+ handleToggleTooltip(false);
94
+ }, 300);
95
+ };
96
+
97
+ useEffect(() => {
98
+ return () => {
99
+ if (closeTimeoutRef.current) {
100
+ clearTimeout(closeTimeoutRef.current);
101
+ }
102
+ };
103
+ }, []);
104
+
60
105
  return (
61
106
  <Box
107
+ ref={closeTimeoutRef}
62
108
  padding="0"
63
- extraStyles={`position: relative; ${tooltipContainerExtraStyles}`}
109
+ extraStyles={`position: relative; ${containerExtraStyles}`}
110
+ onMouseEnter={() => handleMouseEnter(true)}
111
+ onMouseLeave={() => handleMouseLeave(false)}
112
+ data-qa="tooltip-container"
64
113
  >
65
114
  <ButtonWithAction
66
- action={() => noop}
115
+ aria-describedby={tooltipID}
116
+ onKeyDown={handleKeyboardEvent}
117
+ variant={triggerButtonVariant}
67
118
  onFocus={() => handleToggleTooltip(true)}
68
119
  onBlur={() => handleToggleTooltip(false)}
69
- onKeyDown={handleKeyboardEvent}
70
120
  onTouchStart={() => handleToggleTooltip(true)}
71
- onTouchEnd={() => handleToggleTooltip(false)}
72
- onMouseEnter={() => handleToggleTooltip(true)}
73
- onMouseLeave={() => handleToggleTooltip(false)}
74
- contentOverride
75
- variant="smallGhost"
76
- tabIndex="0"
77
- aria-describedby={tooltipID}
78
- extraStyles={buttonExtraStyles}
121
+ data-qa="tooltip-trigger"
122
+ contentOverride={true}
79
123
  >
80
- {hasIconTrigger && (
124
+ {hasIconTrigger === true && (
81
125
  <>
82
126
  <Box aria-label="Open tooltip">
83
127
  <IconTrigger color={tooltipTriggerColor} />
@@ -87,34 +131,47 @@ const Tooltip = ({
87
131
  </Box>
88
132
  </>
89
133
  )}
90
- {!hasIconTrigger && (
134
+ {hasIconTrigger === false && (
91
135
  <Text
92
- extraStyles={`color: ${tooltipTriggerColor}; &:hover {
93
- ${hoverColor}; &:active ${activeColor}; ${triggerTextExtraStyles}`}
136
+ color={tooltipTriggerColor}
137
+ extraStyles={`
138
+ color: ${tooltipTriggerColor};
139
+ &:visited {
140
+ color: ${tooltipTriggerColor};
141
+ }
142
+ &:hover {
143
+ color: ${hoverColor};
144
+ }
145
+ &:active,
146
+ &:focus {
147
+ color: ${activeColor};
148
+ }
149
+ ${triggerExtraStyles};
150
+ `}
94
151
  >
95
- {tooltipTriggerText}
152
+ {triggerText}
96
153
  </Text>
97
154
  )}
98
155
  </ButtonWithAction>
99
156
  <Box
100
- background={backgroundColor}
101
- borderRadius="4px"
102
- boxShadow="0px 2px 14px 0px rgb(246, 246, 249), 0px 3px 8px 0px rgb(202, 206, 216)"
103
- id={tooltipID}
104
157
  role="tooltip"
105
- minWidth={minWidth}
106
- maxWidth={maxWidth}
158
+ id={tooltipID}
107
159
  aria-hidden={!tooltipOpen}
160
+ data-qa="tooltip-contents"
108
161
  extraStyles={`
109
- display: ${tooltipOpen ? "block" : "none"};
110
- position: absolute;
162
+ position: absolute;
163
+ display: ${tooltipOpen ? "block" : "none"};
111
164
  top: ${top};
112
- right: ${right};
113
- bottom: ${bottom};
165
+ right: ${right};
166
+ bottom: ${bottom};
114
167
  left: ${left};
115
168
  height: ${height};
116
- ${contentExtraStyles};
117
169
  `}
170
+ boxShadow={`0px 2px 14px 0px rgb(246, 246, 249), 0px 3px 8px 0px rgb(202, 206, 216)`}
171
+ border={`1px solid transparent`}
172
+ borderRadius="4px"
173
+ minWidth={minWidth}
174
+ maxWidth={maxWidth}
118
175
  >
119
176
  <Paragraph>{tooltipContent}</Paragraph>
120
177
  <Box
@@ -137,4 +194,4 @@ const Tooltip = ({
137
194
  );
138
195
  };
139
196
 
140
- export default themeComponent(Tooltip, "Tooltip", fallbackValues);
197
+ export default Tooltip;
@@ -1,52 +1,61 @@
1
+ import React from "react";
1
2
  import Tooltip from "./Tooltip";
2
3
  import WarningIconXS from "../../atoms/icons/WarningIconXS";
3
- export default {
4
+
5
+ const meta = {
4
6
  title: "Molecules/Tooltip",
5
7
  component: Tooltip,
6
- tags: ["!autodocs"],
7
8
  parameters: {
8
- layout: "centered",
9
- controls: { expanded: true }
9
+ layout: "centered"
10
10
  },
11
+ tags: ["!autodocs"],
12
+ decorators: [
13
+ Story => (
14
+ <div style={{ padding: "120px 300px" }}>
15
+ <Story />
16
+ </div>
17
+ )
18
+ ],
11
19
  args: {
12
- tooltipTriggerText: "",
13
- tooltipContent: "",
20
+ tooltipID: "tooltip-id",
14
21
  hasIconTrigger: false,
15
22
  IconTrigger: WarningIconXS,
16
23
  iconHelpText: "Open the tooltip",
17
- tooltipID: "tooltip-content",
18
- tooltipContainerExtraStyles: undefined,
19
- triggerTextExtraStyles: undefined,
24
+ triggerText: "Hover me",
25
+ tooltipContent: "The contents of the tooltip go here.",
26
+ contentPosition: {
27
+ top: "-110px",
28
+ right: "auto",
29
+ bottom: "auto",
30
+ left: "-225px"
31
+ },
32
+ arrowDirection: "down",
33
+ arrowPosition: {
34
+ arrowTop: "auto",
35
+ arrowRight: "10px",
36
+ arrowBottom: "-8px",
37
+ arrowLeft: "auto"
38
+ },
20
39
  minWidth: "250px",
21
40
  maxWidth: "300px",
22
41
  height: "auto",
23
- contentPosition: undefined,
24
- arrowPosition: undefined,
25
- arrowDirection: "down",
26
- buttonExtraStyles: undefined,
27
- backgroundColor: "white",
28
- borderColor: "rgba(255, 255, 255, 0.85)",
29
- contentExtraStyles: undefined
42
+ containerExtraStyles: "",
43
+ triggerExtraStyles: "",
44
+ triggerButtonVariant: "smallGhost"
30
45
  },
31
46
  argTypes: {
32
- tooltipTriggerText: {
47
+ tooltipID: {
33
48
  description:
34
- "Text element that tooltip is anchored to. Only used if hasIconTrigger is false.",
49
+ "Unique ID linking the trigger to the tooltip content for accessibility",
35
50
  table: {
36
51
  type: { summary: "string" },
37
- defaultValue: { summary: "" }
38
- }
39
- },
40
- tooltipContent: {
41
- description: "Content of the tooltip",
42
- table: {
43
- type: { summary: "string" },
44
- defaultValue: { summary: "" }
52
+ defaultValue: { summary: undefined }
45
53
  }
46
54
  },
47
55
  hasIconTrigger: {
48
56
  description:
49
- "Whether an icon is the trigger for the tooltip, instead of text",
57
+ "When true, renders an icon as the tooltip trigger instead of text",
58
+ control: { type: "boolean" },
50
59
  table: {
51
60
  type: { summary: "boolean" },
52
61
  defaultValue: { summary: false }
@@ -54,142 +63,173 @@ export default {
54
63
  },
55
64
  IconTrigger: {
56
65
  description:
57
- "The icon component to display. Requires hasIcon to be true.",
66
+ "Icon component rendered as the trigger when hasIconTrigger is true",
58
67
  table: {
59
68
  type: { summary: "React Component" },
60
69
  defaultValue: { summary: "WarningIconXS" }
61
70
  }
62
71
  },
63
72
  iconHelpText: {
64
- description: "Accessible description of the icon",
73
+ description: "Screen reader text for the icon trigger",
65
74
  table: {
66
75
  type: { summary: "string" },
67
76
  defaultValue: { summary: "Open the tooltip" }
68
77
  }
69
78
  },
70
- tooltipID: {
79
+ triggerText: {
71
80
  description:
72
- "ID value for tooltip. Use if displaying multiple tooltips on the same page.",
81
+ "Text rendered as the tooltip trigger when hasIconTrigger is false",
82
+ table: {
83
+ type: { summary: "string | JSX.Element" },
84
+ defaultValue: { summary: "Open the tooltip" }
85
+ }
86
+ },
87
+ tooltipContent: {
88
+ description: "The content displayed inside the tooltip",
73
89
  table: {
74
90
  type: { summary: "string" },
75
- defaultValue: { summary: "tooltip-content" }
91
+ defaultValue: { summary: "The contents of the tooltip go here." }
76
92
  }
77
93
  },
78
- tooltipContainerExtraStyles: {
94
+ contentPosition: {
79
95
  description:
80
- "Extra CSS styles to apply to the wrapper component around the trigger and tooltip",
96
+ "CSS position values (top, right, bottom, left) for the tooltip content box relative to the trigger",
81
97
  table: {
82
- type: { summary: "CSS string" },
83
- defaultValue: { summary: undefined }
98
+ type: { summary: "object" },
99
+ defaultValue: {
100
+ summary: `{ top: "-110px", right: "auto", bottom: "auto", left: "-225px" }`
101
+ }
84
102
  }
85
103
  },
86
- triggerTextExtraStyles: {
87
- description: "Extra styles to apply to the text trigger of the tooltip",
104
+ arrowDirection: {
105
+ description: "Direction the tooltip arrow points (up, down, left, right)",
106
+ control: { type: "select" },
107
+ options: ["up", "down", "left", "right"],
88
108
  table: {
89
- type: { summary: "CSS string" },
90
- defaultValue: { summary: undefined }
109
+ type: { summary: "string" },
110
+ defaultValue: { summary: "down" }
111
+ }
112
+ },
113
+ arrowPosition: {
114
+ description:
115
+ "CSS position values (arrowTop, arrowRight, arrowBottom, arrowLeft) for the arrow element",
116
+ table: {
117
+ type: { summary: "object" },
118
+ defaultValue: {
119
+ summary: `{ arrowTop: "auto", arrowRight: "10px", arrowBottom: "-8px", arrowLeft: "auto" }`
120
+ }
91
121
  }
92
122
  },
93
123
  minWidth: {
94
- description: "Minimum width of the tooltip component",
124
+ description: "Minimum width of the tooltip content box",
95
125
  table: {
96
126
  type: { summary: "string" },
97
127
  defaultValue: { summary: "250px" }
98
128
  }
99
129
  },
100
130
  maxWidth: {
101
- description: "Maximum width of the tooltip component",
131
+ description: "Maximum width of the tooltip content box",
102
132
  table: {
103
133
  type: { summary: "string" },
104
134
  defaultValue: { summary: "300px" }
105
135
  }
106
136
  },
107
137
  height: {
108
- description: "Height of the tooltip component. Default sizes to content.",
138
+ description: "Height of the tooltip content box",
109
139
  table: {
110
140
  type: { summary: "string" },
111
141
  defaultValue: { summary: "auto" }
112
142
  }
113
143
  },
114
- contentPosition: {
144
+ containerExtraStyles: {
115
145
  description:
116
- "Object containing values for top/right/bottom/left position of tooltip relative to trigger",
117
- table: {
118
- type: { summary: "Object" },
119
- defaultValue: { summary: undefined }
120
- }
121
- },
122
- arrowPosition: {
123
- description:
124
- "Object containing values for arrowTop/arrowRight/arrowBottom/arrowLeft position of arrow on tooltip",
125
- table: {
126
- type: { summary: "Object" },
127
- defaultValue: { summary: undefined }
128
- }
129
- },
130
- arrowDirection: {
131
- description: "Direction the tooltip arrow points",
146
+ "Additional CSS string applied to the tooltip container element",
132
147
  table: {
133
148
  type: { summary: "string" },
134
- defaultValue: { summary: "down" }
149
+ defaultValue: { summary: '""' }
135
150
  }
136
151
  },
137
- buttonExtraStyles: {
138
- description:
139
- "Extra styles to apply to the button that wraps tooltip trigger",
152
+ triggerExtraStyles: {
153
+ description: "Additional CSS string applied to the text trigger element",
140
154
  table: {
141
155
  type: { summary: "string" },
142
- defaultValue: { summary: undefined }
156
+ defaultValue: { summary: '""' }
143
157
  }
144
158
  },
145
- backgroundColor: {
146
- description: "Background color of the tooltip",
147
- table: {
148
- type: { summary: "string" },
149
- defaultValue: { summary: "white" }
150
- }
151
- },
152
- borderColor: {
153
- description: "Color of the tooltip arrow",
154
- table: {
155
- type: { summary: "string" },
156
- defaultValue: { summary: "rgba(255, 255, 255, 0.85)" }
157
- }
158
- },
159
- contentExtraStyles: {
160
- description: "Extra styles to apply to the tooltip content box",
159
+ triggerButtonVariant: {
160
+ description:
161
+ "Button variant applied to the trigger ButtonWithAction element",
161
162
  table: {
162
163
  type: { summary: "string" },
163
- defaultValue: { summary: undefined }
164
+ defaultValue: { summary: "smallGhost" }
164
165
  }
165
166
  }
166
167
  }
167
168
  };
168
169
 
169
- export const BasicTooltip = {
170
+ export default meta;
171
+
172
+ export const Basic = {
170
173
  args: {
171
- tooltipTriggerText: "Help",
174
+ tooltipID: "tooltip-basic",
175
+ triggerText: "How basic is this?",
172
176
  tooltipContent:
173
- "Contact support at 1-800-CTY-VILL for help with your account balance."
177
+ "This is a detailed explanation of a feature or term that the user may need more context about."
174
178
  }
175
179
  };
176
180
 
177
- export const IconTooltip = {
181
+ export const TooltipBelow = {
178
182
  args: {
179
- hasIconTrigger: true,
180
- IconTrigger: WarningIconXS,
181
- tooltipContent:
182
- "Contact support at 1-800-CTY-VILL for help with your account balance."
183
+ tooltipID: "tooltip-below",
184
+ contentPosition: {
185
+ top: "50px",
186
+ right: "auto",
187
+ bottom: "auto",
188
+ left: "-225px"
189
+ },
190
+ arrowDirection: "up",
191
+ arrowPosition: {
192
+ arrowTop: "-8px",
193
+ arrowRight: "10px",
194
+ arrowBottom: "auto",
195
+ arrowLeft: "auto"
196
+ }
183
197
  }
184
198
  };
185
199
 
186
- export const UnderneathTooltip = {
200
+ export const TooltipRight = {
187
201
  args: {
188
- tooltipTriggerText: "What's this?",
202
+ tooltipID: "tooltip-right",
203
+ contentPosition: {
204
+ top: "-40px",
205
+ right: "auto",
206
+ bottom: "auto",
207
+ left: "calc(100% + 12px)"
208
+ },
209
+ arrowDirection: "left",
210
+ arrowPosition: {
211
+ arrowTop: "50%",
212
+ arrowRight: "auto",
213
+ arrowBottom: "auto",
214
+ arrowLeft: "-8px"
215
+ }
216
+ }
217
+ };
218
+
219
+ export const CustomContent = {
220
+ args: {
221
+ tooltipID: "tooltip-custom-content",
222
+ triggerText: "What is this?",
189
223
  tooltipContent:
190
- "Contact support at 1-800-CTY-VILL for help with your account balance.",
191
- contentPosition: { top: "50px", left: "-100px" },
192
- arrowPosition: { arrowTop: "-8px", arrowLeft: "50%" },
193
- arrowDirection: "up"
224
+ "This is a detailed explanation of a feature or term that the user may need more context about."
225
+ }
226
+ };
227
+
228
+ export const CustomWidth = {
229
+ args: {
230
+ tooltipID: "tooltip-custom-width",
231
+ minWidth: "150px",
232
+ maxWidth: "200px",
233
+ tooltipContent: "A narrower tooltip."
194
234
  }
195
235
  };
@@ -1,31 +1,31 @@
1
1
  import React from "react";
2
2
  import Expand from "../../../util/expand";
3
-
4
3
  export interface TooltipProps {
4
+ tooltipID: string;
5
+ hasIconTrigger?: boolean;
6
+ IconTrigger?: React.FC<React.SVGProps<SVGSVGElement>>;
7
+ iconHelpText?: string;
5
8
  triggerText?: string | JSX.Element;
6
- content?: string | JSX.Element;
7
- extraStyles?: string;
8
- textExtraStyles?: string;
9
- minWidth?: string;
10
- maxWidth?: string;
11
- height?: string;
12
- position?: { top: string; right: string; bottom: string; left: string };
9
+ tooltipContent: string;
10
+ contentPosition?: {
11
+ top: string;
12
+ right: string;
13
+ bottom: string;
14
+ left: string;
15
+ };
16
+ arrowDirection?: string;
13
17
  arrowPosition?: {
14
18
  arrowTop: string;
15
19
  arrowRight: string;
16
20
  arrowBottom: string;
17
21
  arrowLeft: string;
18
22
  };
19
- arrowDirection?: "left" | "right" | "top" | "bottom";
20
- buttonExtraStyles?: string;
21
- borderColor?: string;
22
- backgroundColor?: string;
23
- hasIconTrigger?: boolean;
24
- IconTrigger?: React.FC<React.SVGProps<SVGSVGElement>>;
25
- iconHelpText?: string;
26
- iconColor?: string;
27
- tooltipID: string;
28
- tooltipContentExtraStyles?: string;
23
+ minWidth?: string;
24
+ maxWidth?: string;
25
+ height?: string;
26
+ containerExtraStyles?: string;
27
+ triggerExtraStyles?: string;
28
+ triggerButtonVariant?: string;
29
29
  }
30
30
 
31
31
  export const Tooltip: React.FC<Expand<TooltipProps> &