@thecb/components 11.10.1-beta.1 → 11.10.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/README.md +8 -4
- package/dist/index.cjs.js +116 -94
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +116 -94
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/atoms/card-type/CardType.js +10 -2
- package/src/components/atoms/dropdown/Dropdown.js +2 -3
- package/src/components/atoms/dropdown/DropdownIcon.js +1 -0
- package/src/components/atoms/dropdown/DropdownIconV2.js +1 -0
- package/src/components/atoms/form-layouts/FormInput.js +1 -1
- package/src/components/atoms/formatted-credit-card/FormattedCreditCard.js +10 -7
- package/src/components/atoms/icons/AmExSmallIcon.js +2 -0
- package/src/components/atoms/icons/DiscoverSmallIcon.js +2 -0
- package/src/components/atoms/icons/GenericCardLarge.js +1 -1
- package/src/components/atoms/icons/GenericSmallIcon.js +2 -0
- package/src/components/atoms/icons/MasterCardSmallIcon.js +2 -0
- package/src/components/atoms/icons/VisaSmallIcon.js +2 -0
- package/src/components/molecules/radio-section/InnerRadioSection.js +2 -2
- package/src/components/molecules/tooltip/Tooltip.js +94 -61
- package/src/components/molecules/tooltip/Tooltip.mdx +2 -12
- package/src/components/molecules/tooltip/Tooltip.stories.js +71 -92
- package/src/components/molecules/tooltip/Tooltip.theme.js +5 -15
- package/src/components/molecules/tooltip/index.d.ts +7 -4
package/package.json
CHANGED
|
@@ -34,11 +34,19 @@ 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
|
+
|
|
37
44
|
const CardType = ({ type, size = "small" }) => {
|
|
45
|
+
const normalizedType = normalizeType(type);
|
|
38
46
|
const { label, [size]: IconComponent } =
|
|
39
|
-
cardBrands[
|
|
47
|
+
cardBrands[normalizedType] || cardBrands.default;
|
|
40
48
|
return (
|
|
41
|
-
<span
|
|
49
|
+
<span>
|
|
42
50
|
<IconComponent />
|
|
43
51
|
</span>
|
|
44
52
|
);
|
|
@@ -13,7 +13,6 @@ import "core-js/proposals/relative-indexing-method";
|
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
15
|
ERROR_COLOR,
|
|
16
|
-
GREY_CHATEAU,
|
|
17
16
|
MINESHAFT_GREY,
|
|
18
17
|
STORM_GREY,
|
|
19
18
|
WHITE
|
|
@@ -35,7 +34,7 @@ const IconWrapper = styled.div`
|
|
|
35
34
|
|
|
36
35
|
const DropdownContentWrapper = styled.div`
|
|
37
36
|
transform-origin: 0 0;
|
|
38
|
-
border: 1px solid ${
|
|
37
|
+
border: 1px solid ${STORM_GREY};
|
|
39
38
|
border-radius: 2px;
|
|
40
39
|
background-color: ${WHITE};
|
|
41
40
|
padding: 8px 0 8px;
|
|
@@ -349,7 +348,7 @@ const Dropdown = ({
|
|
|
349
348
|
? ERROR_COLOR
|
|
350
349
|
: isOpen
|
|
351
350
|
? themeValues.selectedColor
|
|
352
|
-
:
|
|
351
|
+
: STORM_GREY
|
|
353
352
|
}
|
|
354
353
|
dataQa={placeholder}
|
|
355
354
|
extraStyles={
|
|
@@ -148,7 +148,7 @@ const FormInput = ({
|
|
|
148
148
|
<Stack childGap="0.25rem">
|
|
149
149
|
<Box padding="0">
|
|
150
150
|
{helperModal ? (
|
|
151
|
-
<Cluster justify="space-between" align="center">
|
|
151
|
+
<Cluster justify="space-between" align="center" overflow>
|
|
152
152
|
{labelDisplayOverride ? (
|
|
153
153
|
labelDisplayOverride
|
|
154
154
|
) : (
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { Fragment } from "react";
|
|
2
|
-
import styled from "styled-components";
|
|
1
|
+
import React, { Fragment, useContext } from "react";
|
|
2
|
+
import styled, { ThemeContext } 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: 36px;
|
|
19
19
|
height: auto;
|
|
20
20
|
display: flex;
|
|
21
21
|
`;
|
|
@@ -27,16 +27,18 @@ const FormattedCreditCard = ({
|
|
|
27
27
|
expireDate,
|
|
28
28
|
expirationStatus,
|
|
29
29
|
themeValues
|
|
30
|
-
}) =>
|
|
30
|
+
}) => {
|
|
31
|
+
const { isMobile } = useContext(ThemeContext);
|
|
32
|
+
return (
|
|
31
33
|
<CreditCardWrapper>
|
|
32
34
|
<CCIconWrapper>
|
|
33
|
-
<CardType type={type} />
|
|
35
|
+
<CardType type={type} size={isMobile ? "small" : "large"} />
|
|
34
36
|
</CCIconWrapper>
|
|
35
37
|
<Stack childGap="0">
|
|
36
38
|
<Box padding="0">
|
|
37
39
|
<Text
|
|
38
40
|
variant="p"
|
|
39
|
-
padding="0
|
|
41
|
+
padding="0"
|
|
40
42
|
color={themeValues.textColor}
|
|
41
43
|
textAlign="left"
|
|
42
44
|
extraStyles={`display: inline-block;`}
|
|
@@ -58,7 +60,8 @@ const FormattedCreditCard = ({
|
|
|
58
60
|
)}
|
|
59
61
|
</Stack>
|
|
60
62
|
</CreditCardWrapper>
|
|
61
|
-
);
|
|
63
|
+
);
|
|
64
|
+
};
|
|
62
65
|
export default themeComponent(
|
|
63
66
|
FormattedCreditCard,
|
|
64
67
|
"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 ? "16px" : "24px")};
|
|
73
|
+
width: ${({ isMobile }) => (isMobile ? "24px" : "36px")};
|
|
74
74
|
${({ fade }) => fade && "opacity: 0.4;"}
|
|
75
75
|
transition: opacity 0.3s ease;
|
|
76
76
|
`;
|
|
@@ -2,23 +2,34 @@ 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";
|
|
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
|
|
9
|
+
import WarningIconXS from "../../atoms/icons/WarningIconXS";
|
|
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
|
+
};
|
|
9
25
|
|
|
10
26
|
const Tooltip = ({
|
|
11
27
|
tooltipID,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
content = "",
|
|
18
|
-
contentExtraStyles = "",
|
|
19
|
-
minWidth = "250px",
|
|
20
|
-
maxWidth = "100%",
|
|
21
|
-
height = "auto",
|
|
28
|
+
hasIconTrigger = false,
|
|
29
|
+
IconTrigger = WarningIconXS,
|
|
30
|
+
iconHelpText = "Open the tooltip",
|
|
31
|
+
triggerText = "Open the tooltip",
|
|
32
|
+
tooltipContent = "The contents of the tooltip go here.",
|
|
22
33
|
contentPosition = {
|
|
23
34
|
top: "-110px",
|
|
24
35
|
right: "auto",
|
|
@@ -31,7 +42,15 @@ const Tooltip = ({
|
|
|
31
42
|
arrowRight: "10px",
|
|
32
43
|
arrowBottom: "-8px",
|
|
33
44
|
arrowLeft: "auto"
|
|
34
|
-
}
|
|
45
|
+
},
|
|
46
|
+
minWidth = "250px",
|
|
47
|
+
maxWidth = "300px",
|
|
48
|
+
height = "auto",
|
|
49
|
+
containerExtraStyles = "",
|
|
50
|
+
triggerExtraStyles = "",
|
|
51
|
+
triggerButtonVariant = "smallGhost",
|
|
52
|
+
contentExtraStyles = "",
|
|
53
|
+
contentBackgroundColor = WHITE
|
|
35
54
|
}) => {
|
|
36
55
|
const closeTimeoutRef = useRef(null);
|
|
37
56
|
const [tooltipOpen, setTooltipOpen] = useState(false);
|
|
@@ -42,16 +61,23 @@ const Tooltip = ({
|
|
|
42
61
|
TOOLTIP_THEME_SOURCE
|
|
43
62
|
);
|
|
44
63
|
|
|
64
|
+
const {
|
|
65
|
+
borderColor,
|
|
66
|
+
popoverTriggerColor: tooltipTriggerColor,
|
|
67
|
+
hoverColor,
|
|
68
|
+
activeColor
|
|
69
|
+
} = themeValues;
|
|
70
|
+
|
|
45
71
|
const { top, right, bottom, left } = contentPosition;
|
|
46
72
|
const { arrowTop, arrowRight, arrowBottom, arrowLeft } = arrowPosition;
|
|
47
73
|
|
|
48
|
-
const handleToggleTooltip =
|
|
49
|
-
if (tooltipOpen !==
|
|
50
|
-
setTooltipOpen(
|
|
74
|
+
const handleToggleTooltip = desiredTooltipState => {
|
|
75
|
+
if (tooltipOpen !== desiredTooltipState) {
|
|
76
|
+
setTooltipOpen(desiredTooltipState);
|
|
51
77
|
}
|
|
52
78
|
};
|
|
53
79
|
|
|
54
|
-
const
|
|
80
|
+
const handleKeyboardEvent = e => {
|
|
55
81
|
if (e.key === "Escape") {
|
|
56
82
|
handleToggleTooltip(false);
|
|
57
83
|
}
|
|
@@ -79,73 +105,80 @@ const Tooltip = ({
|
|
|
79
105
|
};
|
|
80
106
|
}, []);
|
|
81
107
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return (
|
|
108
|
+
return (
|
|
109
|
+
<Box
|
|
110
|
+
ref={closeTimeoutRef}
|
|
111
|
+
padding="0"
|
|
112
|
+
extraStyles={`position: relative; ${containerExtraStyles}`}
|
|
113
|
+
onMouseEnter={() => handleMouseEnter(true)}
|
|
114
|
+
onMouseLeave={() => handleMouseLeave(false)}
|
|
115
|
+
data-qa="tooltip-container"
|
|
116
|
+
>
|
|
93
117
|
<ButtonWithAction
|
|
94
|
-
action={noop}
|
|
95
118
|
aria-describedby={tooltipID}
|
|
96
|
-
onKeyDown={
|
|
119
|
+
onKeyDown={handleKeyboardEvent}
|
|
97
120
|
variant={triggerButtonVariant}
|
|
98
121
|
onFocus={() => handleToggleTooltip(true)}
|
|
99
122
|
onBlur={() => handleToggleTooltip(false)}
|
|
100
123
|
onTouchStart={() => handleToggleTooltip(true)}
|
|
101
|
-
data-qa=
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
data-qa="tooltip-trigger"
|
|
125
|
+
contentOverride={true}
|
|
126
|
+
>
|
|
127
|
+
{hasIconTrigger === true && (
|
|
128
|
+
<>
|
|
129
|
+
<Box aria-label="Open tooltip">
|
|
130
|
+
<IconTrigger color={tooltipTriggerColor} />
|
|
131
|
+
</Box>
|
|
132
|
+
<Box padding="0" srOnly>
|
|
133
|
+
<Text>{iconHelpText}</Text>
|
|
134
|
+
</Box>
|
|
135
|
+
</>
|
|
136
|
+
)}
|
|
137
|
+
{hasIconTrigger === false && (
|
|
138
|
+
<Text
|
|
139
|
+
color={tooltipTriggerColor}
|
|
140
|
+
extraStyles={`
|
|
141
|
+
color: ${tooltipTriggerColor};
|
|
142
|
+
&:visited {
|
|
143
|
+
color: ${tooltipTriggerColor};
|
|
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>
|
|
122
159
|
<Box
|
|
123
160
|
role="tooltip"
|
|
124
161
|
id={tooltipID}
|
|
125
162
|
aria-hidden={!tooltipOpen}
|
|
126
|
-
background={
|
|
163
|
+
background={contentBackgroundColor}
|
|
127
164
|
data-qa="tooltip-contents"
|
|
128
165
|
extraStyles={`
|
|
129
166
|
position: absolute;
|
|
130
167
|
display: ${tooltipOpen ? "block" : "none"};
|
|
131
|
-
top: ${top};
|
|
168
|
+
top: ${top};
|
|
132
169
|
right: ${right};
|
|
133
170
|
bottom: ${bottom};
|
|
134
171
|
left: ${left};
|
|
135
172
|
height: ${height};
|
|
136
173
|
${contentExtraStyles}
|
|
137
|
-
|
|
138
|
-
boxShadow=
|
|
139
|
-
border=
|
|
174
|
+
`}
|
|
175
|
+
boxShadow={`0px 2px 14px 0px rgb(246, 246, 249), 0px 3px 8px 0px rgb(202, 206, 216)`}
|
|
176
|
+
border={`1px solid transparent`}
|
|
140
177
|
borderRadius="4px"
|
|
141
178
|
minWidth={minWidth}
|
|
142
179
|
maxWidth={maxWidth}
|
|
143
180
|
>
|
|
144
|
-
{
|
|
145
|
-
<Text color={themeValues.linkColor}>{content}</Text>
|
|
146
|
-
) : (
|
|
147
|
-
content
|
|
148
|
-
)}
|
|
181
|
+
<Paragraph>{tooltipContent}</Paragraph>
|
|
149
182
|
<Box
|
|
150
183
|
padding="0"
|
|
151
184
|
extraStyles={`
|
|
@@ -153,7 +186,7 @@ const Tooltip = ({
|
|
|
153
186
|
content: "";
|
|
154
187
|
width: 0;
|
|
155
188
|
height: 0;
|
|
156
|
-
${arrowBorder(
|
|
189
|
+
${arrowBorder(borderColor, arrowDirection, "8px")};
|
|
157
190
|
filter: drop-shadow(2px 8px 14px black);
|
|
158
191
|
bottom: ${arrowBottom};
|
|
159
192
|
right: ${arrowRight};
|
|
@@ -6,19 +6,9 @@ import * as TooltipStories from './Tooltip.stories.js';
|
|
|
6
6
|
|
|
7
7
|
<Title />
|
|
8
8
|
|
|
9
|
-
Tooltip is
|
|
9
|
+
The Tooltip is a fully accessible tooltip widget that displays additional information when a user hovers over or focuses on a specified trigger element. The trigger can either be text supplied using the `triggerText` prop, or a custom Icon component supplied using the `IconTrigger` prop. The trigger is rendered as a `ButtonWithAction` with the `smallGhost` variant.
|
|
10
10
|
|
|
11
|
-
The
|
|
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.
|
|
11
|
+
The Tooltip uses the WAI-ARIA tooltip pattern (`role="tooltip"` and `aria-describedby`) for accessibility. It can be positioned anywhere around the trigger element using the position props. Content and style of the tooltip are customizable.
|
|
22
12
|
|
|
23
13
|
<Controls />
|
|
24
14
|
|