@thecb/components 6.3.0-beta.2 → 6.3.1-beta.3

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": "6.3.0-beta.2",
3
+ "version": "6.3.1-beta.3",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
@@ -3,23 +3,18 @@ import React, { Fragment } from "react";
3
3
  import { themeComponent } from "../../../util/themeUtils";
4
4
  import withWindowSize from "../../withWindowSize";
5
5
 
6
- import { Box, Stack, Cover } from "../layouts";
6
+ import { Cover } from "../layouts";
7
7
  import BoxWithShadow from "../box-with-shadow";
8
8
  import { fallbackValues } from "./Card.theme";
9
9
 
10
- const CardVariantSwitcher = ({ variant, children }) => {
11
- return variant === "vertical" ? (
12
- <Fragment>{children}</Fragment>
13
- ) : (
14
- <Box padding="0" extraStyles={`width: 100%`}>
15
- <Stack childGap="0" maxWidth="100%" fullHeight>
16
- {children}
17
- </Stack>
18
- </Box>
19
- );
20
- };
21
-
22
- const Card = ({ themeValues, variant, children, extraStyles, ...props }) => {
10
+ const Card = ({
11
+ themeValues,
12
+ variant,
13
+ children,
14
+ extraStyles,
15
+ width = "276px",
16
+ ...props
17
+ }) => {
23
18
  return (
24
19
  <BoxWithShadow
25
20
  variant="baseStandard"
@@ -27,15 +22,11 @@ const Card = ({ themeValues, variant, children, extraStyles, ...props }) => {
27
22
  borderRadius="4px"
28
23
  padding="0"
29
24
  margin="0"
30
- maxWidth={variant !== "vertical" ? "100%" : "276px"}
31
- minHeight="100%"
32
- minWidth={variant !== "vertical" && "276px"}
25
+ minWidth={width}
33
26
  extraStyles={extraStyles}
34
27
  {...props}
35
28
  >
36
- <Cover singleChild fillCenter>
37
- <CardVariantSwitcher variant={variant}>{children}</CardVariantSwitcher>
38
- </Cover>
29
+ <Cover>{children}</Cover>
39
30
  </BoxWithShadow>
40
31
  );
41
32
  };
@@ -3,6 +3,7 @@ import Expand from "../../../util/expand";
3
3
 
4
4
  export interface CardProps {
5
5
  variant?: string;
6
+ width?: string;
6
7
  extraStyles?: string;
7
8
  }
8
9
 
@@ -6,7 +6,8 @@ import Paragraph from "../paragraph";
6
6
  import Cluster from "../layouts/Cluster";
7
7
  import ButtonWithAction from "../button-with-action";
8
8
  import ButtonWithLink from "../button-with-link";
9
- import { WHITE, CHARADE_GREY } from "../../../constants/colors";
9
+ import { WHITE, CHARADE_GREY, STORM_GREY } from "../../../constants/colors";
10
+ import Popover from "../../molecules/popover";
10
11
 
11
12
  const DisplayCard = ({
12
13
  title,
@@ -14,18 +15,34 @@ const DisplayCard = ({
14
15
  buttonText,
15
16
  buttonAction,
16
17
  url,
17
- link = false
18
+ link = false,
19
+ helpText,
20
+ hasPopover = false,
21
+ popoverTriggerText = "",
22
+ popoverContent = "",
23
+ popoverExtraStyles,
24
+ popoverTextExtraStyles
18
25
  }) => (
19
26
  <Box padding="0 0 16px">
20
27
  <Stack childGap="0rem">
21
28
  <Box padding="0 0 8px 0">
22
- <Paragraph
23
- variant="pL"
24
- color={CHARADE_GREY}
25
- extraStyles={`letter-spacing: 0.29px`}
26
- >
27
- {title}
28
- </Paragraph>
29
+ <Cluster justify="space-between" align="center" overflow>
30
+ <Paragraph
31
+ variant="pL"
32
+ color={CHARADE_GREY}
33
+ extraStyles={`letter-spacing: 0.29px`}
34
+ >
35
+ {title}
36
+ </Paragraph>
37
+ {hasPopover && (
38
+ <Popover
39
+ triggerText={popoverTriggerText}
40
+ content={popoverContent}
41
+ popoverExtraStyles={popoverExtraStyles}
42
+ popoverTextExtraStyles={popoverTextExtraStyles}
43
+ />
44
+ )}
45
+ </Cluster>
29
46
  </Box>
30
47
  <Box padding="0">
31
48
  <Box
@@ -37,9 +54,7 @@ const DisplayCard = ({
37
54
  0px 3px 8px 0px rgb(202, 206, 216)"
38
55
  >
39
56
  <Cluster justify="space-between" align="center">
40
- <Text variant="p" color={CHARADE_GREY}>
41
- {item}
42
- </Text>
57
+ <Text color={CHARADE_GREY}>{item}</Text>
43
58
  {link ? (
44
59
  <ButtonWithLink
45
60
  text={buttonText}
@@ -56,6 +71,10 @@ const DisplayCard = ({
56
71
  dataQa={buttonText}
57
72
  extraStyles={`min-width: 0;`}
58
73
  />
74
+ ) : helpText ? (
75
+ <Text color={STORM_GREY} extraStyles={`font-style: italic;`}>
76
+ {helpText}
77
+ </Text>
59
78
  ) : (
60
79
  <Fragment />
61
80
  )}
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import Expand from "../../../util/expand";
3
+
4
+ export interface SwitcherProps {
5
+ breakpoint?: string;
6
+ childGap?: string;
7
+ largeChild?: string;
8
+ largeChildSize?: string;
9
+ maxChildren?: string;
10
+ maxChildrenOnly?: boolean;
11
+ padding?: string;
12
+ extraStyles?: string;
13
+ constrainMobile?: boolean;
14
+ }
15
+
16
+ export const Switcher: React.FC<Expand<SwitcherProps> &
17
+ React.HTMLAttributes<HTMLElement>>;
@@ -3,3 +3,4 @@ export * from "./Center";
3
3
  export * from "./Cluster";
4
4
  export * from "./Cover";
5
5
  export * from "./Stack";
6
+ export * from "./Switcher";
@@ -18,6 +18,7 @@ const Text = ({
18
18
  as,
19
19
  dataQa,
20
20
  children,
21
+ variant = "p",
21
22
  ...rest
22
23
  }) => (
23
24
  <TextSpan
@@ -32,6 +33,7 @@ const Text = ({
32
33
  onKeyPress={onKeyPress}
33
34
  data-qa={dataQa}
34
35
  $textWrap={textWrap}
36
+ $variant={variant}
35
37
  {...rest}
36
38
  >
37
39
  {safeChildren(children, <span />)}
@@ -1,3 +1 @@
1
- export * from "./card-with-header";
2
1
  export * from "./footer-with-subfooter";
3
- export * from "./welcome-card";
@@ -1,5 +1,4 @@
1
1
  export { default as AddressForm } from "./address-form";
2
- export { default as CardWithHeader } from "./card-with-header";
3
2
  export { default as ChangePasswordForm } from "./change-password-form";
4
3
  export { default as CollapsibleSection } from "./collapsible-section";
5
4
  export { default as EditNameForm } from "./edit-name-form";
@@ -22,7 +21,9 @@ export { default as PaymentButtonBar } from "./payment-button-bar";
22
21
  export { default as PaymentDetails } from "./payment-details";
23
22
  export { default as PaymentFormACH } from "./payment-form-ach";
24
23
  export { default as PaymentFormCard } from "./payment-form-card";
24
+ export { default as PeriscopeDashboardIframe } from "./periscope-dashboard-iframe";
25
25
  export { default as PhoneForm } from "./phone-form";
26
+ export { default as Popover } from "./popover";
26
27
  export { default as RadioSection } from "./radio-section";
27
28
  export { default as RegistrationForm } from "./registration-form";
28
29
  export { default as ResetConfirmationForm } from "./reset-confirmation-form";
@@ -33,7 +34,5 @@ export { default as TabSidebar } from "./tab-sidebar";
33
34
  export { default as TermsAndConditions } from "./terms-and-conditions";
34
35
  export { default as TermsAndConditionsModal } from "./terms-and-conditions-modal";
35
36
  export { default as Timeout } from "./timeout";
36
- export { default as WelcomeCard } from "./welcome-card";
37
37
  export { default as WelcomeModule } from "./welcome-module";
38
38
  export { default as WorkflowTile } from "./workflow-tile";
39
- export { default as PeriscopeDashboardIframe } from "./periscope-dashboard-iframe";
@@ -0,0 +1,124 @@
1
+ import React, { useState, useContext } from "react";
2
+ import { themeComponent } from "../../../util/themeUtils";
3
+ import Text from "../../atoms/text";
4
+ import Paragraph from "../../atoms/paragraph";
5
+ import { Box } from "../../atoms/layouts";
6
+ import ButtonWithAction from "../../atoms/button-with-action";
7
+ import { useOutsideClick } from "../../../util";
8
+ import { noop } from "../../../util/general";
9
+ import { fallbackValues } from "./Popover.theme";
10
+
11
+ const Popover = ({
12
+ themeValues,
13
+ triggerText = "",
14
+ content = "",
15
+ hasIcon = false,
16
+ icon: Icon,
17
+ iconHelpText = "", // for screen-readers, required if using an icon for trigger
18
+ popoverID = 0,
19
+ popoverFocus = false,
20
+ extraStyles,
21
+ textExtraStyles,
22
+ minWidth = "250px",
23
+ maxWidth = "300px",
24
+ height = "auto",
25
+ position, // { top: string, right: string, bottom: string, left: string }
26
+ arrowPosition // { top: string, right: string, bottom: string, left: string }
27
+ }) => {
28
+ const { hoverColor, activeColor, popoverTriggerColor } = themeValues;
29
+ const { top = "-110px", right = "auto", bottom = "auto", left = "-225px" } =
30
+ position ?? {};
31
+ const {
32
+ arrowTop = "auto",
33
+ arrowRight = "10px",
34
+ arrowBottom = "-8px",
35
+ arrowLeft = "auto"
36
+ } = arrowPosition ?? {};
37
+
38
+ const [popoverOpen, togglePopover] = useState(false);
39
+
40
+ const handleTogglePopover = popoverState => {
41
+ if (popoverOpen !== popoverState) {
42
+ togglePopover(popoverState);
43
+ }
44
+ };
45
+
46
+ const triggerRef = useOutsideClickHook(() => handleTogglePopover(false));
47
+
48
+ return (
49
+ <Box padding="0" extraStyles={`position: relative; ${extraStyles}`}>
50
+ <ButtonWithAction
51
+ action={() => noop}
52
+ onFocus={() => {
53
+ handleTogglePopover(true);
54
+ }}
55
+ onBlur={() => {
56
+ handleTogglePopover(false);
57
+ }}
58
+ onKeyDown={e => {
59
+ if (e.keyCode === 27) {
60
+ handleTogglePopover(false);
61
+ }
62
+ }}
63
+ onTouchStart={() => handleTogglePopover(true)}
64
+ onTouchEnd={() => handleTogglePopover(false)}
65
+ onMouseEnter={() => handleTogglePopover(true)}
66
+ onMouseLeave={() => handleTogglePopover(false)}
67
+ contentOverride
68
+ variant="smallGhost"
69
+ tabIndex="0"
70
+ id={`btnPopover${popoverID}`}
71
+ aria-expanded={popoverOpen}
72
+ aria-labelledby={`btnPopover${popoverID}_info Disclosure${popoverID}`}
73
+ aria-describedby={`Disclosure${popoverID}`}
74
+ aria-controls={`Disclosed${popoverID}`}
75
+ ref={triggerRef}
76
+ >
77
+ {hasIcon && (
78
+ <>
79
+ <Icon />
80
+ <Box padding="0" srOnly>
81
+ <Text id={`btnPopover${popoverID}_info`}>{iconHelpText}</Text>
82
+ </Box>
83
+ </>
84
+ )}
85
+ {!hasIcon && (
86
+ <Text
87
+ color={popoverTriggerColor}
88
+ extraStyles={`&:active { color: ${activeColor}; } &:hover { color: ${hoverColor} }; ${textExtraStyles}`}
89
+ >
90
+ {triggerText}
91
+ </Text>
92
+ )}
93
+ </ButtonWithAction>
94
+ <Box
95
+ background="white"
96
+ borderRadius="4px"
97
+ boxShadow="0px 2px 14px 0px rgb(246, 246, 249), 0px 3px 8px 0px rgb(202, 206, 216)"
98
+ id={`Disclosed${popoverID}`}
99
+ role={"region"}
100
+ aria-describedby={`Disclosure${popoverID}`}
101
+ tabIndex={popoverFocus && popoverOpen ? "0" : "-1"}
102
+ minWidth={minWidth}
103
+ maxWidth={maxWidth}
104
+ extraStyles={`
105
+ display: ${popoverOpen ? "block" : "none"};
106
+ position: absolute;
107
+ top: ${top};
108
+ right: ${right};
109
+ bottom: ${bottom};
110
+ left: ${left};
111
+ height: ${height}
112
+ `}
113
+ >
114
+ <Paragraph>{content}</Paragraph>
115
+ <Box
116
+ padding="0"
117
+ extraStyles={`position: absolute; content: ""; width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 8px solid rgba(255, 255, 255, 0.85); filter: drop-shadow(2px 8px 14px black); bottom: ${arrowBottom}; right: ${arrowRight}; top: ${arrowTop}; left: ${arrowLeft};`}
118
+ />
119
+ </Box>
120
+ </Box>
121
+ );
122
+ };
123
+
124
+ export default themeComponent(Popover, "Popover", fallbackValues);
@@ -0,0 +1,9 @@
1
+ const hoverColor = "#116285";
2
+ const activeColor = "#0E506D";
3
+ const popoverTriggerColor = "#15749D";
4
+
5
+ export const fallbackValues = {
6
+ hoverColor,
7
+ activeColor,
8
+ popoverTriggerColor
9
+ };
@@ -0,0 +1,3 @@
1
+ import Popover from "./Popover";
2
+
3
+ export default Popover;
package/src/util/index.js CHANGED
@@ -2,5 +2,6 @@ import * as formats from "./formats";
2
2
  import * as general from "./general";
3
3
  import * as theme from "./themeUtils";
4
4
  import useFocusInvalidInput from "./focusFirstInvalidInputHook";
5
+ import useOutsideClick from "./useOutsideClick";
5
6
 
6
- export { formats, general, theme, useFocusInvalidInput };
7
+ export { formats, general, theme, useFocusInvalidInput, useOutsideClick };
@@ -0,0 +1,33 @@
1
+ import { useRef, useEffect } from "react";
2
+
3
+ /*
4
+ Hook that assigns a click event listener to the main document element
5
+ Returns a ref to attach to another element (like an icon/button that triggers a popover)
6
+ If a click event gets captured by the document and the assigned element isn't the target
7
+ hook will run whatever handler is passed (eg a function that closes a popover)
8
+
9
+ See popover component for implementation
10
+
11
+ */
12
+
13
+ const useOutsideClickHook = handler => {
14
+ const ref = useRef();
15
+
16
+ useEffect(() => {
17
+ const handleOutsideClick = e => {
18
+ if (ref.current && !ref.current.contains(e.target)) {
19
+ handler();
20
+ }
21
+
22
+ document.addEventListener("click", handleOutsideClick, true);
23
+
24
+ return () => {
25
+ document.removeEventListener("click", handleOutsideClick, true);
26
+ };
27
+ };
28
+ }, [ref]);
29
+
30
+ return ref;
31
+ };
32
+
33
+ export default useOutsideClickHook;
@@ -1,33 +0,0 @@
1
- import React from "react";
2
-
3
- import { fallbackValues } from "./CardWithHeader.theme";
4
- import { themeComponent } from "../../../util/themeUtils";
5
-
6
- import { Box, Card, Title } from "../../atoms";
7
-
8
- const CardWithHeader = ({
9
- themeValues,
10
- children,
11
- header,
12
- extraStyles,
13
- ...props
14
- }) => {
15
- return (
16
- <Card extraStyles={extraStyles} {...props}>
17
- <Box
18
- padding="24px"
19
- background={themeValues.headerBackgroundColor}
20
- extraStyles={`
21
- border-radius: 4px 4px 0 0;
22
- `}
23
- >
24
- <Title variant="small" color={themeValues.headerTextColor}>
25
- {header}
26
- </Title>
27
- </Box>
28
- <Box padding="24px">{children}</Box>
29
- </Card>
30
- );
31
- };
32
-
33
- export default themeComponent(CardWithHeader, "CardWithHeader", fallbackValues);
@@ -1,9 +0,0 @@
1
- import { STORM_GREY, WHITE } from "../../../constants/colors";
2
-
3
- const headerBackgroundColor = STORM_GREY;
4
- const headerTextColor = WHITE;
5
-
6
- export const fallbackValues = {
7
- headerBackgroundColor,
8
- headerTextColor
9
- };
@@ -1,10 +0,0 @@
1
- import React from "react";
2
- import Expand from "../../../util/expand";
3
-
4
- export interface CardWithHeaderProps {
5
- header: string;
6
- extraStyles?: string;
7
- }
8
-
9
- export const CardWithHeader: React.FC<Expand<CardWithHeaderProps> &
10
- React.HTMLAttributes<HTMLElement>>;
@@ -1,2 +0,0 @@
1
- import CardWithHeader from "./CardWithHeader";
2
- export default CardWithHeader;
@@ -1,63 +0,0 @@
1
- import React from "react";
2
-
3
- import { fallbackValues } from "./WelcomeCard.theme";
4
- import { themeComponent } from "../../../util/themeUtils";
5
-
6
- import {
7
- Box,
8
- ButtonWithLink,
9
- Card,
10
- Cover,
11
- Paragraph,
12
- Title
13
- } from "../../atoms";
14
-
15
- const WelcomeCard = ({
16
- themeValues,
17
- title,
18
- text,
19
- buttonText,
20
- url,
21
- imageSrc,
22
- newTab
23
- }) => {
24
- return (
25
- <Card>
26
- {imageSrc && (
27
- <Cover>
28
- <img
29
- src={imageSrc}
30
- style={{
31
- background: `${themeValues.imageBackgroundColor}`,
32
- objectFit: "none",
33
- height: "150px"
34
- }}
35
- />
36
- </Cover>
37
- )}
38
- <Box padding="24px">
39
- <Title
40
- variant="small"
41
- color={themeValues.titleColor}
42
- weight={themeValues.titleWeight}
43
- >
44
- {title}
45
- </Title>
46
- <Paragraph color={themeValues.textColor}>{text}</Paragraph>
47
- {url && buttonText && (
48
- <Box extraStyles="margin-top: 4rem; padding: 0">
49
- <ButtonWithLink
50
- extraStyles="margin: 0; width: 100%"
51
- linkExtraStyles="text-decoration:none"
52
- url={url}
53
- text={buttonText}
54
- newTab={newTab}
55
- />
56
- </Box>
57
- )}
58
- </Box>
59
- </Card>
60
- );
61
- };
62
-
63
- export default themeComponent(WelcomeCard, "WelcomeCard", fallbackValues);
@@ -1,15 +0,0 @@
1
- import { BRIGHT_GREY, INFO_BLUE } from "../../../constants/colors";
2
-
3
- import { FONT_WEIGHT_BOLD } from "../../../constants/style_constants";
4
-
5
- const titleColor = BRIGHT_GREY;
6
- const textColor = BRIGHT_GREY;
7
- const titleWeight = FONT_WEIGHT_BOLD;
8
- const imageBackgroundColor = INFO_BLUE;
9
-
10
- export const fallbackValues = {
11
- textColor,
12
- titleColor,
13
- titleWeight,
14
- imageBackgroundColor
15
- };
@@ -1,14 +0,0 @@
1
- import React from "react";
2
- import Expand from "../../../util/expand";
3
-
4
- export interface WelcomeCardProps {
5
- title: string;
6
- text: string;
7
- url?: string;
8
- buttonText?: string;
9
- imageSrc?: string;
10
- newTab?: boolean;
11
- }
12
-
13
- export const WelcomeCard: React.FC<Expand<WelcomeCardProps> &
14
- React.HTMLAttributes<HTMLElement>>;
@@ -1,3 +0,0 @@
1
- import WelcomeCard from "./WelcomeCard";
2
-
3
- export default WelcomeCard;