@thecb/components 10.7.1-beta.1 → 10.7.2-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thecb/components",
3
- "version": "10.7.1-beta.1",
3
+ "version": "10.7.2-beta.1",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
@@ -73,7 +73,16 @@ const Alert = ({
73
73
  </Box>
74
74
  <Cluster justify="flex-end" align="flex-start">
75
75
  {showQuitLink && (
76
- <Box padding="0" minHeight="100%" onClick={onLinkClick}>
76
+ <Box
77
+ padding="0"
78
+ minHeight="100%"
79
+ onClick={onLinkClick}
80
+ onKeyDown={e => e.key === "Enter" && onLinkClick()}
81
+ role="button"
82
+ tabIndex={0}
83
+ aria-label={`Close Alert: ${heading}`}
84
+ extraStyles="cursor: pointer;"
85
+ >
77
86
  <IconQuit />
78
87
  </Box>
79
88
  )}
@@ -7,6 +7,7 @@ import { ThemeContext } from "styled-components";
7
7
  import Module from "../../molecules/module/Module";
8
8
  import Spinner from "../spinner/Spinner";
9
9
  import { CHARADE_GREY } from "../../../constants/colors";
10
+ import { noop } from "../../../util/general";
10
11
 
11
12
  const WalletName = ({
12
13
  mainText, // left side text
@@ -15,9 +16,7 @@ const WalletName = ({
15
16
  actionText = null, // right side hyperlinked text
16
17
  disableAction = false,
17
18
  linkButtonExtraStyles = "", // hyperlinked text extraStyles
18
- isLoading = false, // shows a spinner on the left when true
19
- dataQa = null,
20
- actionTextPositionMobile = "outside" // whether action text is outside/below box or inside it
19
+ isLoading = false // shows a spinner on the left when true
21
20
  }) => {
22
21
  const { isMobile } = useContext(ThemeContext);
23
22
 
@@ -50,7 +49,7 @@ const WalletName = ({
50
49
  mainText && <Text>{mainText}</Text>
51
50
  )}
52
51
  </Box>
53
- {(actionTextPositionMobile === "inside" || !isMobile) && (
52
+ {!isMobile && (
54
53
  <Box padding="0">
55
54
  {text && <Text variant="pXS">{text}</Text>}
56
55
  {(text || actionText) && <>&nbsp;</>}
@@ -58,7 +57,6 @@ const WalletName = ({
58
57
  <ButtonWithAction
59
58
  disabled={disableAction}
60
59
  text={actionText}
61
- dataQa={dataQa}
62
60
  action={action}
63
61
  variant="smallGhost"
64
62
  extraStyles={`
@@ -73,7 +71,7 @@ const WalletName = ({
73
71
  )}
74
72
  </Cluster>
75
73
  </Module>
76
- {!!isMobile && actionTextPositionMobile === "outside" && (
74
+ {isMobile && (
77
75
  <Cluster
78
76
  align="center"
79
77
  justify={text || actionText ? "flex-end" : "flex-start"}
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import WalletName from "./WalletName";
3
- import { text, object, boolean, select } from "@storybook/addon-knobs";
3
+ import { text, object, boolean } from "@storybook/addon-knobs";
4
4
  import page from "../../../../.storybook/page";
5
5
 
6
6
  export const walletName = () => {
@@ -12,31 +12,6 @@ export const walletName = () => {
12
12
  text={text("text", "Not you?", "props")}
13
13
  disableAction={boolean("disableAction", false, "props")}
14
14
  isLoading={boolean("isLoading", false, "props")}
15
- actionTextPositionMobile={select(
16
- "actionTextPositionMobile",
17
- { inside: "inside", outside: "outside" },
18
- "outside",
19
- "props"
20
- )}
21
- />
22
- );
23
- };
24
-
25
- export const walletNameWithOverrides = () => {
26
- return (
27
- <WalletName
28
- mainText={text("mainText", "Firstname Lastname", "props")}
29
- action={object("action", () => window.alert("action fired!"), "props")}
30
- actionText={text("actionText", "Check out as a guest", "props")}
31
- text={text("text", "Not you?", "props")}
32
- disableAction={boolean("disableAction", false, "props")}
33
- isLoading={boolean("isLoading", false, "props")}
34
- actionTextPositionMobile={select(
35
- "actionTextPositionMobile",
36
- { inside: "inside", outside: "outside" },
37
- "outside",
38
- "props"
39
- )}
40
15
  />
41
16
  );
42
17
  };
@@ -9,8 +9,6 @@ export interface WalletNameProps {
9
9
  text?: string | null;
10
10
  isLoading: boolean;
11
11
  buttonExtraStyles?: string;
12
- dataQa?: string | null;
13
- actionTextPositionMobile?: "inside" | "outside";
14
12
  }
15
13
 
16
14
  export const WalletName: React.FC<Expand<WalletNameProps> &
@@ -15,6 +15,8 @@ import {
15
15
  InactiveControlsModule,
16
16
  InactiveTitleModule
17
17
  } from "./modules";
18
+ import { themeComponent } from "../../../util/themeUtils";
19
+ import { fallbackValues } from "./Obligation.theme";
18
20
 
19
21
  const Obligation = ({
20
22
  config,
@@ -37,7 +39,8 @@ const Obligation = ({
37
39
  inactiveLookupTitle = "",
38
40
  inactiveLookupInput = "Account",
39
41
  inactiveLookupValue = "",
40
- isInCustomerManagement = false
42
+ isInCustomerManagement = false,
43
+ themeValues
41
44
  }) => {
42
45
  /*
43
46
  The value of obligations is always an array. It can contain:
@@ -88,6 +91,7 @@ const Obligation = ({
88
91
  configIconMap={config.iconMap}
89
92
  iconValue={config.iconValue}
90
93
  customAttributes={customAttributes}
94
+ iconColor={themeValues.iconColor}
91
95
  />
92
96
  )}
93
97
  <TitleModule
@@ -194,6 +198,7 @@ const Obligation = ({
194
198
  configIconMap={config.iconMap}
195
199
  iconValue={config.iconValue}
196
200
  customAttributes={customAttributes}
201
+ iconColor={themeValues.iconColor}
197
202
  />
198
203
  <InactiveTitleModule
199
204
  title={inactiveLookupTitle}
@@ -256,4 +261,4 @@ const Obligation = ({
256
261
  return inactive ? inactiveObligation : activeObligation;
257
262
  };
258
263
 
259
- export default Obligation;
264
+ export default themeComponent(Obligation, "Obligation", fallbackValues);
@@ -0,0 +1,7 @@
1
+ import { ROYAL_BLUE_VIVID } from "../../../constants/colors";
2
+
3
+ const iconColor = ROYAL_BLUE_VIVID;
4
+
5
+ export const fallbackValues = {
6
+ iconColor
7
+ };
@@ -4,7 +4,7 @@ import { Box, Stack } from "../../../atoms/layouts";
4
4
  import Text from "../../../atoms/text";
5
5
  import { FONT_WEIGHT_SEMIBOLD } from "../../../../constants/style_constants";
6
6
  import { displayCurrency, noop } from "../../../../util/general";
7
- import { AutopayModalModule } from "./AutopayModalModule";
7
+ import AutopayModalModule from "./AutopayModalModule";
8
8
 
9
9
  const AmountModule = ({
10
10
  totalAmountDue,
@@ -6,11 +6,10 @@ import { AutopayOnIcon } from "../../../atoms/icons";
6
6
  import { Box, Cluster } from "../../../atoms/layouts";
7
7
  import { SEA_GREEN } from "../../../../constants/colors";
8
8
  import { ACH_METHOD, CC_METHOD } from "../../../../constants/general";
9
- import { fallbackValues } from "./AutopayModalModule.theme";
10
- import { themeComponent } from "../../../../util/themeUtils";
11
9
  import { titleCaseString, noop } from "../../../../util/general";
10
+ import { FONT_WEIGHT_REGULAR } from "../../../../constants/style_constants";
12
11
 
13
- const AutopayModal = ({
12
+ const AutopayModalModule = ({
14
13
  autoPayActive,
15
14
  autoPaySchedule,
16
15
  paymentPlanSchedule,
@@ -20,7 +19,6 @@ const AutopayModal = ({
20
19
  navigateToSettings,
21
20
  controlType = "tertiary",
22
21
  isMobile,
23
- themeValues,
24
22
  isPaymentPlan,
25
23
  nextAutopayDate,
26
24
  dueDate,
@@ -75,6 +73,12 @@ const AutopayModal = ({
75
73
  }
76
74
  : navigateToSettings
77
75
  };
76
+ const modalLinkHoverFocus = `
77
+ outline: none;
78
+ cursor: pointer;
79
+ text-decoration: underline;
80
+ text-decoration-color: #317D4F;
81
+ `;
78
82
 
79
83
  const hoverStyles = "text-decoration: underline;";
80
84
  const activeStyles = "text-decoration: underline;";
@@ -142,8 +146,8 @@ const AutopayModal = ({
142
146
  tabIndex="0"
143
147
  dataQa={`${shortPlan} On`}
144
148
  color={SEA_GREEN}
145
- weight={themeValues.fontWeight}
146
- hoverStyles={themeValues.modalLinkHoverFocus}
149
+ weight={FONT_WEIGHT_REGULAR}
150
+ hoverStyles={modalLinkHoverFocus}
147
151
  extraStyles={`padding-left: 0.25rem;`}
148
152
  disabled={disableActions}
149
153
  >
@@ -167,8 +171,4 @@ const AutopayModal = ({
167
171
  );
168
172
  };
169
173
 
170
- export const AutopayModalModule = themeComponent(
171
- AutopayModal,
172
- "AutopayModal",
173
- fallbackValues
174
- );
174
+ export default AutopayModalModule;
@@ -1,10 +1,6 @@
1
1
  import React from "react";
2
2
  import { iconsMap } from "../icons";
3
3
  import { Box, Cluster } from "../../../atoms/layouts";
4
- import { themeComponent } from "../../../../util/themeUtils";
5
- import { fallbackValues } from "../../../atoms/icons/Icons.theme";
6
-
7
- // Uses the theme values (singleIconColor) for the other icons, located in /atoms/icons
8
4
 
9
5
  const IconsModule = ({
10
6
  icon,
@@ -12,7 +8,7 @@ const IconsModule = ({
12
8
  configIconMap,
13
9
  iconValue,
14
10
  customAttributes,
15
- themeValues
11
+ iconColor
16
12
  }) => {
17
13
  let Icon;
18
14
  if (typeof icon === "object") {
@@ -25,10 +21,10 @@ const IconsModule = ({
25
21
  return (
26
22
  <Box padding="0 1rem 0 0">
27
23
  <Cluster justify="center" align="center">
28
- <Icon color={themeValues.singleIconColor} />
24
+ <Icon color={iconColor} />
29
25
  </Cluster>
30
26
  </Box>
31
27
  );
32
28
  };
33
29
 
34
- export default themeComponent(IconsModule, "Icon", fallbackValues, "primary");
30
+ export default IconsModule;
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from "react";
2
2
  import { GHOST_GREY } from "../../../../constants/colors";
3
3
  import { Box, Cluster } from "../../../atoms/layouts";
4
- import { AutopayModalModule } from "./AutopayModalModule";
4
+ import AutopayModalModule from "./AutopayModalModule";
5
5
  import RemoveAccountModalModule from "./RemoveAccountModalModule";
6
6
  import { noop } from "../../../../util/general";
7
7
 
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from "react";
2
2
  import { Box, Cluster } from "../../../atoms/layouts";
3
3
  import ButtonWithAction from "../../../atoms/button-with-action";
4
- import { AutopayModalModule } from "./AutopayModalModule";
4
+ import AutopayModalModule from "./AutopayModalModule";
5
5
  import { GHOST_GREY } from "../../../../constants/colors";
6
6
  import AmountModule from "./AmountModule";
7
7
  import { noop } from "../../../../util/general";
@@ -25,9 +25,7 @@ const PaymentButtonBar = ({
25
25
  hideBackButton = false,
26
26
  buttonGroupStyles,
27
27
  hideAdditionalButton = false,
28
- additionalButton,
29
- nextButtonTestId = null,
30
- backButtonTestId = null
28
+ additionalButton
31
29
  }) => {
32
30
  const { isMobile } = useContext(ThemeContext);
33
31
 
@@ -38,7 +36,7 @@ const PaymentButtonBar = ({
38
36
  url={cancelURL}
39
37
  variant={backButtonVariant}
40
38
  extraStyles={isMobile && "flex-grow: 1"}
41
- dataQa={backButtonTestId || cancelText}
39
+ dataQa={cancelText}
42
40
  aria-labelledby={`${kebabCaseString(cancelText)}-button`}
43
41
  role="link"
44
42
  />
@@ -62,7 +60,7 @@ const PaymentButtonBar = ({
62
60
  text={redirectText}
63
61
  variant={forwardButtonVariant}
64
62
  extraStyles={isMobile && "flex-grow: 1"}
65
- dataQa={nextButtonTestId || redirectText}
63
+ dataQa={redirectText}
66
64
  disabled={isForwardButtonDisabled}
67
65
  aria-labelledby={`${kebabCaseString(redirectText)}-button`}
68
66
  role={forwardButtonAriaRole}
@@ -75,7 +73,7 @@ const PaymentButtonBar = ({
75
73
  action={forwardButtonAction}
76
74
  isLoading={forwardButtonLoading}
77
75
  extraStyles={isMobile && "flex-grow: 1"}
78
- dataQa={nextButtonTestId || forwardButtonText}
76
+ dataQa={forwardButtonText}
79
77
  disabled={isForwardButtonDisabled}
80
78
  aria-labelledby={`${kebabCaseString(forwardButtonText)}-button`}
81
79
  role={forwardButtonAriaRole}
@@ -58,7 +58,6 @@ const RadioSection = ({
58
58
  ariaDescribedBy,
59
59
  isSectionRequired = false,
60
60
  groupedSections,
61
- borderOverride,
62
61
  ...rest
63
62
  }) => {
64
63
  const [focused, setFocused] = useState(null);
@@ -99,7 +98,7 @@ const RadioSection = ({
99
98
  return (
100
99
  <Box
101
100
  padding="1px"
102
- border={borderOverride || `1px solid ${themeValues.borderColor}`}
101
+ border={`1px solid ${themeValues.borderColor}`}
103
102
  borderRadius="4px"
104
103
  extraStyles={containerStyles}
105
104
  role="radiogroup"
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useRef, useEffect } from "react";
2
2
  import { Box, Cluster } from "../../atoms/layouts";
3
3
  import { Paragraph } from "../../atoms";
4
4
  import {
@@ -13,6 +13,7 @@ import {
13
13
  } from "../../../constants/colors";
14
14
  import { FONT_WEIGHT_SEMIBOLD } from "../../../constants/style_constants";
15
15
  import { generateShadows } from "../../../util/generateShadows";
16
+ import { SCREEN_READER_ONLY } from "../../../constants/style_constants";
16
17
 
17
18
  const VARIANTS = {
18
19
  SUCCESS: "success",
@@ -30,55 +31,85 @@ const ToastNotification = ({
30
31
  height = "56px",
31
32
  childGap = "1rem",
32
33
  backgroundColor,
33
- role = "alert",
34
+ role = "status",
34
35
  ariaLive = "polite",
36
+ screenReaderMessage,
37
+ showScreenReaderMessage = true,
35
38
  ...rest
36
- }) => (
37
- <Box
38
- onClick={closeToastNotification}
39
- onKeyDown={e => e.key === "Enter" && closeToastNotification()}
40
- background={
41
- backgroundColor
42
- ? backgroundColor
43
- : variant === VARIANTS.SUCCESS
44
- ? HINT_GREEN
45
- : variant === VARIANTS.ERROR
46
- ? ERROR_BACKGROUND_COLOR
47
- : WHITE
39
+ }) => {
40
+ const screenReaderMessageRef = useRef();
41
+ const LIVEREGION_TRANSITION_DELAY = 1000;
42
+
43
+ useEffect(() => {
44
+ if (showScreenReaderMessage) {
45
+ const timeout = setTimeout(() => {
46
+ if (screenReaderMessageRef.current) {
47
+ screenReaderMessageRef.current.textContent = `${
48
+ screenReaderMessage ? screenReaderMessage : message ? message : ""
49
+ }`;
50
+ }
51
+ }, LIVEREGION_TRANSITION_DELAY);
52
+
53
+ return () => clearTimeout(timeout);
48
54
  }
49
- minWidth={minWidth}
50
- minHeight={height && parseInt(height) < 100 ? height : "100px"}
51
- height={height ? height : "auto"}
52
- tabIndex={toastOpen ? "-1" : "0"}
53
- padding="0rem 1rem"
54
- borderRadius="4px"
55
- boxShadow={generateShadows().standard.base}
56
- extraStyles={`
55
+ }, [showScreenReaderMessage, screenReaderMessage, message]);
56
+
57
+ return (
58
+ <>
59
+ <Box
60
+ onClick={closeToastNotification}
61
+ onKeyDown={e => e.key === "Enter" && closeToastNotification()}
62
+ background={
63
+ backgroundColor
64
+ ? backgroundColor
65
+ : variant === VARIANTS.SUCCESS
66
+ ? HINT_GREEN
67
+ : variant === VARIANTS.ERROR
68
+ ? ERROR_BACKGROUND_COLOR
69
+ : WHITE
70
+ }
71
+ minWidth={minWidth}
72
+ minHeight={height && parseInt(height) < 100 ? height : "100px"}
73
+ height={height ? height : "auto"}
74
+ tabIndex={toastOpen ? "-1" : "0"}
75
+ padding="0rem 1rem"
76
+ borderRadius="4px"
77
+ boxShadow={generateShadows().standard.base}
78
+ extraStyles={`
57
79
  display: ${toastOpen ? "block" : "none"};
58
80
  position: fixed; bottom: 4rem; left: 4rem;
59
81
  ${extraStyles};
60
82
  cursor: pointer;
61
83
  `}
62
- role={role}
63
- aria-live={ariaLive}
64
- {...rest}
65
- >
66
- <Cluster align="center" childGap={childGap} justify="space-between">
67
- <Cluster align="center" childGap={childGap}>
68
- {variant === VARIANTS.SUCCESS && <SuccessfulIconMedium />}
69
- {variant === VARIANTS.ERROR && <ErroredIcon />}
70
- <Box padding="1rem 0" maxWidth={maxWidth}>
71
- <Paragraph
72
- weight={FONT_WEIGHT_SEMIBOLD}
73
- extraStyles={"word-break: break-word;"}
74
- >
75
- {message}
76
- </Paragraph>
77
- </Box>
78
- </Cluster>
79
- <IconQuitLarge />
80
- </Cluster>
81
- </Box>
82
- );
84
+ {...rest}
85
+ >
86
+ <Cluster align="center" childGap={childGap} justify="space-between">
87
+ <Cluster align="center" childGap={childGap}>
88
+ {variant === VARIANTS.SUCCESS && <SuccessfulIconMedium />}
89
+ {variant === VARIANTS.ERROR && <ErroredIcon />}
90
+ <Box padding="1rem 0" maxWidth={maxWidth}>
91
+ <Paragraph
92
+ weight={FONT_WEIGHT_SEMIBOLD}
93
+ extraStyles={"word-break: break-word;"}
94
+ >
95
+ {message}
96
+ </Paragraph>
97
+ </Box>
98
+ </Cluster>
99
+ <IconQuitLarge />
100
+ </Cluster>
101
+ </Box>
102
+ {showScreenReaderMessage && (
103
+ <span
104
+ ref={screenReaderMessageRef}
105
+ style={SCREEN_READER_ONLY}
106
+ role={role}
107
+ aria-live={ariaLive}
108
+ aria-atomic={true}
109
+ ></span>
110
+ )}
111
+ </>
112
+ );
113
+ };
83
114
 
84
115
  export default ToastNotification;
@@ -24,3 +24,15 @@ export const SPACING = {
24
24
  XS: "1.0rem", // Figma: Spacing/XS
25
25
  MD: "1.5rem" // Figma: Spacing/Normal
26
26
  };
27
+ export const SCREEN_READER_ONLY = {
28
+ border: 0,
29
+ clip: "rect(0 0 0 0)",
30
+ clipPath: "inset(50%)",
31
+ height: "1px",
32
+ margin: "-1px",
33
+ overflow: "hidden",
34
+ padding: 0,
35
+ position: "absolute",
36
+ width: "1px",
37
+ whiteSpace: "nowrap"
38
+ };
Binary file
@@ -1,20 +0,0 @@
1
- import { FONT_WEIGHT_REGULAR } from "../../../../constants/style_constants";
2
-
3
- const color = "#15749D";
4
- const hoverColor = "#116285";
5
- const activeColor = "#0E506D";
6
- const linkColor = "#3176AA";
7
- const fontWeight = FONT_WEIGHT_REGULAR;
8
- const modalLinkHoverFocus = `outline: none;
9
- cursor: pointer;
10
- text-decoration: underline;
11
- text-decoration-color: #317D4F;`;
12
-
13
- export const fallbackValues = {
14
- color,
15
- hoverColor,
16
- activeColor,
17
- linkColor,
18
- fontWeight,
19
- modalLinkHoverFocus
20
- };