@thecb/components 11.10.0-beta.2 → 11.10.1-beta.1
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/dist/index.cjs.js +87 -109
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +87 -109
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/atoms/card-type/CardType.js +1 -9
- package/src/components/atoms/formatted-credit-card/FormattedCreditCard.js +7 -10
- package/src/components/atoms/icons/AmExSmallIcon.js +0 -2
- package/src/components/atoms/icons/DiscoverSmallIcon.js +0 -2
- package/src/components/atoms/icons/GenericCardLarge.js +1 -1
- package/src/components/atoms/icons/GenericSmallIcon.js +0 -2
- package/src/components/atoms/icons/MasterCardSmallIcon.js +0 -2
- package/src/components/atoms/icons/VisaSmallIcon.js +0 -2
- package/src/components/molecules/radio-section/InnerRadioSection.js +2 -2
- package/src/components/molecules/tooltip/Tooltip.js +61 -94
- package/src/components/molecules/tooltip/Tooltip.mdx +12 -2
- package/src/components/molecules/tooltip/Tooltip.stories.js +92 -71
- package/src/components/molecules/tooltip/Tooltip.theme.js +15 -5
- package/src/components/molecules/tooltip/index.d.ts +4 -7
package/package.json
CHANGED
|
@@ -34,17 +34,9 @@ const cardBrands = {
|
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
const normalizeType = type => {
|
|
38
|
-
if (!type) return undefined;
|
|
39
|
-
const lower = type.toLowerCase();
|
|
40
|
-
if (lower === "mastercard") return "master_card";
|
|
41
|
-
return lower;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
37
|
const CardType = ({ type, size = "small" }) => {
|
|
45
|
-
const normalizedType = normalizeType(type);
|
|
46
38
|
const { label, [size]: IconComponent } =
|
|
47
|
-
cardBrands[
|
|
39
|
+
cardBrands[type] || cardBrands.default;
|
|
48
40
|
return (
|
|
49
41
|
<span role="img" aria-label={label}>
|
|
50
42
|
<IconComponent />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { Fragment
|
|
2
|
-
import styled
|
|
1
|
+
import React, { Fragment } from "react";
|
|
2
|
+
import styled from "styled-components";
|
|
3
3
|
import CardType from "../card-type";
|
|
4
4
|
import Text from "../text";
|
|
5
5
|
import { Box, Stack } from "../layouts";
|
|
@@ -15,7 +15,7 @@ export const CreditCardWrapper = styled.div`
|
|
|
15
15
|
|
|
16
16
|
export const CCIconWrapper = styled.div`
|
|
17
17
|
margin-right: 16px;
|
|
18
|
-
width:
|
|
18
|
+
width: 30px;
|
|
19
19
|
height: auto;
|
|
20
20
|
display: flex;
|
|
21
21
|
`;
|
|
@@ -27,18 +27,16 @@ const FormattedCreditCard = ({
|
|
|
27
27
|
expireDate,
|
|
28
28
|
expirationStatus,
|
|
29
29
|
themeValues
|
|
30
|
-
}) =>
|
|
31
|
-
const { isMobile } = useContext(ThemeContext);
|
|
32
|
-
return (
|
|
30
|
+
}) => (
|
|
33
31
|
<CreditCardWrapper>
|
|
34
32
|
<CCIconWrapper>
|
|
35
|
-
<CardType type={type}
|
|
33
|
+
<CardType type={type} />
|
|
36
34
|
</CCIconWrapper>
|
|
37
35
|
<Stack childGap="0">
|
|
38
36
|
<Box padding="0">
|
|
39
37
|
<Text
|
|
40
38
|
variant="p"
|
|
41
|
-
padding="0"
|
|
39
|
+
padding="0 0 0 8px"
|
|
42
40
|
color={themeValues.textColor}
|
|
43
41
|
textAlign="left"
|
|
44
42
|
extraStyles={`display: inline-block;`}
|
|
@@ -60,8 +58,7 @@ const FormattedCreditCard = ({
|
|
|
60
58
|
)}
|
|
61
59
|
</Stack>
|
|
62
60
|
</CreditCardWrapper>
|
|
63
|
-
|
|
64
|
-
};
|
|
61
|
+
);
|
|
65
62
|
export default themeComponent(
|
|
66
63
|
FormattedCreditCard,
|
|
67
64
|
"FormattedCreditCard",
|
|
@@ -69,8 +69,8 @@ const InnerRadioSection = ({
|
|
|
69
69
|
`;
|
|
70
70
|
|
|
71
71
|
const RightIcon = styled.img`
|
|
72
|
-
height: ${({ isMobile }) => (isMobile ? "
|
|
73
|
-
width: ${({ isMobile }) => (isMobile ? "
|
|
72
|
+
height: ${({ isMobile }) => (isMobile ? "14px" : "18px")};
|
|
73
|
+
width: ${({ isMobile }) => (isMobile ? "22px" : "28px")};
|
|
74
74
|
${({ fade }) => fade && "opacity: 0.4;"}
|
|
75
75
|
transition: opacity 0.3s ease;
|
|
76
76
|
`;
|
|
@@ -2,34 +2,23 @@ import React, { useContext, useEffect, useRef, useState } from "react";
|
|
|
2
2
|
import { createThemeValues } from "../../../util/themeUtils";
|
|
3
3
|
import { ThemeContext } from "styled-components";
|
|
4
4
|
import Text from "../../atoms/text";
|
|
5
|
-
import Paragraph from "../../atoms/paragraph";
|
|
6
5
|
import { Box } from "../../atoms/layouts";
|
|
7
6
|
import ButtonWithAction from "../../atoms/button-with-action";
|
|
8
7
|
import { noop, arrowBorder } from "../../../util/general";
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
MATISSE_BLUE,
|
|
12
|
-
PEACOCK_BLUE,
|
|
13
|
-
SAPPHIRE_BLUE,
|
|
14
|
-
WHITE
|
|
15
|
-
} from "../../../constants/colors";
|
|
16
|
-
|
|
17
|
-
const TOOLTIP_THEME_SOURCE = "Popover";
|
|
18
|
-
|
|
19
|
-
const fallbackValues = {
|
|
20
|
-
hoverColor: SAPPHIRE_BLUE,
|
|
21
|
-
activeColor: PEACOCK_BLUE,
|
|
22
|
-
popoverTriggerColor: MATISSE_BLUE,
|
|
23
|
-
borderColor: `rgba(255, 255, 255, 0.85)`
|
|
24
|
-
};
|
|
8
|
+
import { TOOLTIP_THEME_SOURCE, fallbackValues } from "./Tooltip.theme";
|
|
25
9
|
|
|
26
10
|
const Tooltip = ({
|
|
27
11
|
tooltipID,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
12
|
+
children,
|
|
13
|
+
hasCustomTrigger = false,
|
|
14
|
+
triggerText = "",
|
|
15
|
+
containerExtraStyles = "",
|
|
16
|
+
triggerButtonVariant = "smallGhost",
|
|
17
|
+
content = "",
|
|
18
|
+
contentExtraStyles = "",
|
|
19
|
+
minWidth = "250px",
|
|
20
|
+
maxWidth = "100%",
|
|
21
|
+
height = "auto",
|
|
33
22
|
contentPosition = {
|
|
34
23
|
top: "-110px",
|
|
35
24
|
right: "auto",
|
|
@@ -42,15 +31,7 @@ const Tooltip = ({
|
|
|
42
31
|
arrowRight: "10px",
|
|
43
32
|
arrowBottom: "-8px",
|
|
44
33
|
arrowLeft: "auto"
|
|
45
|
-
}
|
|
46
|
-
minWidth = "250px",
|
|
47
|
-
maxWidth = "300px",
|
|
48
|
-
height = "auto",
|
|
49
|
-
containerExtraStyles = "",
|
|
50
|
-
triggerExtraStyles = "",
|
|
51
|
-
triggerButtonVariant = "smallGhost",
|
|
52
|
-
contentExtraStyles = "",
|
|
53
|
-
contentBackgroundColor = WHITE
|
|
34
|
+
}
|
|
54
35
|
}) => {
|
|
55
36
|
const closeTimeoutRef = useRef(null);
|
|
56
37
|
const [tooltipOpen, setTooltipOpen] = useState(false);
|
|
@@ -61,23 +42,16 @@ const Tooltip = ({
|
|
|
61
42
|
TOOLTIP_THEME_SOURCE
|
|
62
43
|
);
|
|
63
44
|
|
|
64
|
-
const {
|
|
65
|
-
borderColor,
|
|
66
|
-
popoverTriggerColor: tooltipTriggerColor,
|
|
67
|
-
hoverColor,
|
|
68
|
-
activeColor
|
|
69
|
-
} = themeValues;
|
|
70
|
-
|
|
71
45
|
const { top, right, bottom, left } = contentPosition;
|
|
72
46
|
const { arrowTop, arrowRight, arrowBottom, arrowLeft } = arrowPosition;
|
|
73
47
|
|
|
74
|
-
const handleToggleTooltip =
|
|
75
|
-
if (tooltipOpen !==
|
|
76
|
-
setTooltipOpen(
|
|
48
|
+
const handleToggleTooltip = desiredState => {
|
|
49
|
+
if (tooltipOpen !== desiredState) {
|
|
50
|
+
setTooltipOpen(desiredState);
|
|
77
51
|
}
|
|
78
52
|
};
|
|
79
53
|
|
|
80
|
-
const
|
|
54
|
+
const handleKeyDown = e => {
|
|
81
55
|
if (e.key === "Escape") {
|
|
82
56
|
handleToggleTooltip(false);
|
|
83
57
|
}
|
|
@@ -105,80 +79,73 @@ const Tooltip = ({
|
|
|
105
79
|
};
|
|
106
80
|
}, []);
|
|
107
81
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
82
|
+
const renderTrigger = () => {
|
|
83
|
+
if (hasCustomTrigger && children) {
|
|
84
|
+
return React.cloneElement(React.Children.only(children), {
|
|
85
|
+
"aria-describedby": tooltipID,
|
|
86
|
+
onFocus: () => handleToggleTooltip(true),
|
|
87
|
+
onBlur: () => handleToggleTooltip(false),
|
|
88
|
+
onKeyDown: handleKeyDown
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (
|
|
117
93
|
<ButtonWithAction
|
|
94
|
+
action={noop}
|
|
118
95
|
aria-describedby={tooltipID}
|
|
119
|
-
onKeyDown={
|
|
96
|
+
onKeyDown={handleKeyDown}
|
|
120
97
|
variant={triggerButtonVariant}
|
|
121
98
|
onFocus={() => handleToggleTooltip(true)}
|
|
122
99
|
onBlur={() => handleToggleTooltip(false)}
|
|
123
100
|
onTouchStart={() => handleToggleTooltip(true)}
|
|
124
|
-
data-qa=
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
&:hover {
|
|
146
|
-
color: ${hoverColor};
|
|
147
|
-
}
|
|
148
|
-
&:active,
|
|
149
|
-
&:focus {
|
|
150
|
-
color: ${activeColor};
|
|
151
|
-
}
|
|
152
|
-
${triggerExtraStyles};
|
|
153
|
-
`}
|
|
154
|
-
>
|
|
155
|
-
{triggerText}
|
|
156
|
-
</Text>
|
|
157
|
-
)}
|
|
158
|
-
</ButtonWithAction>
|
|
101
|
+
data-qa={`tooltip-trigger-${tooltipID}`}
|
|
102
|
+
text={triggerText}
|
|
103
|
+
extraStyles={`
|
|
104
|
+
color: ${themeValues.linkColor};
|
|
105
|
+
&:hover { color: ${themeValues.hoverColor}; text-decoration: none;}
|
|
106
|
+
&:active, &:focus { color: ${themeValues.activeColor};text-decoration: none;}
|
|
107
|
+
button, span, &:hover span { text-decoration: none; }
|
|
108
|
+
`}
|
|
109
|
+
/>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<Box
|
|
115
|
+
padding="0"
|
|
116
|
+
extraStyles={`position: relative; ${containerExtraStyles}`}
|
|
117
|
+
onMouseEnter={handleMouseEnter}
|
|
118
|
+
onMouseLeave={handleMouseLeave}
|
|
119
|
+
data-qa={`${tooltipID}-container`}
|
|
120
|
+
>
|
|
121
|
+
{renderTrigger()}
|
|
159
122
|
<Box
|
|
160
123
|
role="tooltip"
|
|
161
124
|
id={tooltipID}
|
|
162
125
|
aria-hidden={!tooltipOpen}
|
|
163
|
-
background={
|
|
126
|
+
background={themeValues.borderColor}
|
|
164
127
|
data-qa="tooltip-contents"
|
|
165
128
|
extraStyles={`
|
|
166
129
|
position: absolute;
|
|
167
130
|
display: ${tooltipOpen ? "block" : "none"};
|
|
168
|
-
top: ${top};
|
|
131
|
+
top: ${top};
|
|
169
132
|
right: ${right};
|
|
170
133
|
bottom: ${bottom};
|
|
171
134
|
left: ${left};
|
|
172
135
|
height: ${height};
|
|
173
136
|
${contentExtraStyles}
|
|
174
|
-
|
|
175
|
-
boxShadow=
|
|
176
|
-
border=
|
|
137
|
+
`}
|
|
138
|
+
boxShadow="0px 2px 14px 0px rgb(246, 246, 249), 0px 3px 8px 0px rgb(202, 206, 216)"
|
|
139
|
+
border="1px solid transparent"
|
|
177
140
|
borderRadius="4px"
|
|
178
141
|
minWidth={minWidth}
|
|
179
142
|
maxWidth={maxWidth}
|
|
180
143
|
>
|
|
181
|
-
|
|
144
|
+
{typeof content === "string" ? (
|
|
145
|
+
<Text color={themeValues.linkColor}>{content}</Text>
|
|
146
|
+
) : (
|
|
147
|
+
content
|
|
148
|
+
)}
|
|
182
149
|
<Box
|
|
183
150
|
padding="0"
|
|
184
151
|
extraStyles={`
|
|
@@ -186,7 +153,7 @@ const Tooltip = ({
|
|
|
186
153
|
content: "";
|
|
187
154
|
width: 0;
|
|
188
155
|
height: 0;
|
|
189
|
-
${arrowBorder(borderColor, arrowDirection, "8px")};
|
|
156
|
+
${arrowBorder(themeValues.borderColor, arrowDirection, "8px")};
|
|
190
157
|
filter: drop-shadow(2px 8px 14px black);
|
|
191
158
|
bottom: ${arrowBottom};
|
|
192
159
|
right: ${arrowRight};
|
|
@@ -6,9 +6,19 @@ import * as TooltipStories from './Tooltip.stories.js';
|
|
|
6
6
|
|
|
7
7
|
<Title />
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Tooltip is an accessible tooltip component implementing the [WAI-ARIA Tooltip Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/). It displays supplemental information when the user hovers over or focuses on a trigger element.
|
|
10
10
|
|
|
11
|
-
The
|
|
11
|
+
The trigger can be either:
|
|
12
|
+
- **Custom children**: Pass any single React element as `children`. It will receive `aria-describedby`, focus, blur, and keyboard handlers automatically.
|
|
13
|
+
- **Default button**: When no `children` are provided, a `ButtonWithAction` is rendered using the `triggerText` prop.
|
|
14
|
+
|
|
15
|
+
The tooltip content (`content` prop) accepts a plain string or a React node for rich content. It is styled similarly to the Popover component, including an arrow pointing toward the trigger.
|
|
16
|
+
|
|
17
|
+
### Accessibility
|
|
18
|
+
- The trigger element has `aria-describedby` referencing the tooltip.
|
|
19
|
+
- The tooltip container has `role="tooltip"`.
|
|
20
|
+
- Pressing **Escape** dismisses the tooltip.
|
|
21
|
+
- Focus stays on the trigger while the tooltip is displayed.
|
|
12
22
|
|
|
13
23
|
<Controls />
|
|
14
24
|
|