@thecb/components 4.1.10 → 4.1.12-beta.0
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 +261 -143
- package/package.json +2 -2
- package/src/components/atoms/form-layouts/FormLayouts.theme.js +2 -2
- package/src/components/atoms/form-select/FormSelect.js +50 -15
- package/src/components/atoms/form-select/FormSelect.stories.js +4 -2
- package/src/components/atoms/form-select/FormSelect.styled.js +6 -6
- package/src/components/atoms/form-select/FormSelect.theme.js +52 -0
- package/src/components/molecules/address-form/AddressForm.js +6 -6
- package/src/components/molecules/payment-button-bar/PaymentButtonBar.js +9 -2
- package/src/components/molecules/payment-form-card/PaymentFormCard.js +28 -1
- package/src/components/molecules/payment-form-card/PaymentFormCard.state.js +23 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thecb/components",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.12-beta.0",
|
|
4
4
|
"description": "Common lib for CityBase react components",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"prettier": "^1.19.1",
|
|
49
49
|
"pretty-quick": "^2.0.1",
|
|
50
50
|
"react-redux": "^7.2.0",
|
|
51
|
-
"react-router-dom": "
|
|
51
|
+
"react-router-dom": "^5.2.0",
|
|
52
52
|
"redux": "^4.0.5",
|
|
53
53
|
"rollup": "^1.21.4",
|
|
54
54
|
"rollup-plugin-babel": "^4.3.3",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
CHARADE_GREY,
|
|
3
3
|
MATISSE_BLUE,
|
|
4
4
|
WHITE,
|
|
5
5
|
SEASHELL_WHITE,
|
|
@@ -23,7 +23,7 @@ const inputBackgroundColor = {
|
|
|
23
23
|
disabled: `${SEASHELL_WHITE}`
|
|
24
24
|
};
|
|
25
25
|
const color = { default: `${MINESHAFT_GREY}`, disabled: `${DUSTY_GREY}` };
|
|
26
|
-
const labelColor = { default: `${
|
|
26
|
+
const labelColor = { default: `${CHARADE_GREY}`, disabled: `${CHARADE_GREY}` };
|
|
27
27
|
const borderColor = { default: `${GREY_CHATEAU}`, disabled: `${GREY_CHATEAU}` };
|
|
28
28
|
const lineHeight = { default: "1rem", disabled: "1rem" };
|
|
29
29
|
const fontSize = { default: "0.875rem", disabled: "0.875rem" };
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect } from "react";
|
|
2
2
|
import Dropdown from "../dropdown";
|
|
3
3
|
import Text from "../text";
|
|
4
|
-
import {
|
|
4
|
+
import { ERROR_COLOR } from "../../../constants/colors";
|
|
5
5
|
import { SelectContainer, SelectLabel } from "./FormSelect.styled";
|
|
6
|
+
import { fallbackValues } from "./FormSelect.theme";
|
|
7
|
+
import { themeComponent } from "../../../util/themeUtils";
|
|
8
|
+
import { Box, Cluster } from "../layouts";
|
|
6
9
|
|
|
7
10
|
const FormSelect = ({
|
|
8
11
|
fieldActions,
|
|
@@ -12,7 +15,9 @@ const FormSelect = ({
|
|
|
12
15
|
field,
|
|
13
16
|
showErrors,
|
|
14
17
|
onChange,
|
|
15
|
-
dropdownMaxHeight
|
|
18
|
+
dropdownMaxHeight,
|
|
19
|
+
disabledValues,
|
|
20
|
+
themeValues
|
|
16
21
|
}) => {
|
|
17
22
|
const [open, setOpen] = useState(false);
|
|
18
23
|
const dropdownRef = useRef(null);
|
|
@@ -32,33 +37,63 @@ const FormSelect = ({
|
|
|
32
37
|
|
|
33
38
|
return (
|
|
34
39
|
<SelectContainer ref={dropdownRef}>
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
<Box padding="0" minWidth="100%">
|
|
41
|
+
<Cluster justify="space-between" align="center">
|
|
42
|
+
<Text
|
|
43
|
+
as="label"
|
|
44
|
+
variant="pS"
|
|
45
|
+
color={themeValues.labelColor}
|
|
46
|
+
weight={themeValues.fontWeight}
|
|
47
|
+
extraStyles={`word-break: break-word;
|
|
48
|
+
font-family: Public Sans;
|
|
49
|
+
&::first-letter {
|
|
50
|
+
text-transform: uppercase;
|
|
51
|
+
}`}
|
|
52
|
+
>
|
|
53
|
+
{labelTextWhenNoError}
|
|
54
|
+
</Text>
|
|
55
|
+
</Cluster>
|
|
56
|
+
</Box>
|
|
43
57
|
<Dropdown
|
|
44
58
|
maxHeight={dropdownMaxHeight}
|
|
45
59
|
placeholder={options[0] ? options[0].text : ""}
|
|
46
60
|
options={options}
|
|
47
61
|
value={field.rawValue}
|
|
62
|
+
disabledValues={disabledValues}
|
|
48
63
|
isOpen={open}
|
|
49
|
-
isError={
|
|
64
|
+
isError={
|
|
65
|
+
(field.hasErrors && field.dirty) || (field.hasErrors && showErrors)
|
|
66
|
+
}
|
|
50
67
|
onSelect={
|
|
51
68
|
onChange ? value => onChange(value) : value => fieldActions.set(value)
|
|
52
69
|
}
|
|
53
70
|
onClick={() => setOpen(!open)}
|
|
54
71
|
/>
|
|
55
72
|
<SelectLabel field={field} showErrors={showErrors}>
|
|
56
|
-
{(field.hasErrors && field.dirty) || (field.hasErrors && showErrors)
|
|
57
|
-
|
|
58
|
-
|
|
73
|
+
{(field.hasErrors && field.dirty) || (field.hasErrors && showErrors) ? (
|
|
74
|
+
<Text
|
|
75
|
+
color={ERROR_COLOR}
|
|
76
|
+
variant="pXS"
|
|
77
|
+
weight={themeValues.fontWeight}
|
|
78
|
+
extraStyles={`word-break: break-word;
|
|
79
|
+
font-family: Public Sans;
|
|
80
|
+
&::first-letter {
|
|
81
|
+
text-transform: uppercase;
|
|
82
|
+
}`}
|
|
83
|
+
>
|
|
84
|
+
{errorMessages[field.errors[0]]}
|
|
85
|
+
</Text>
|
|
86
|
+
) : (
|
|
87
|
+
<Text extraStyles={`height: ${themeValues.lineHeight};`} />
|
|
88
|
+
)}
|
|
59
89
|
</SelectLabel>
|
|
60
90
|
</SelectContainer>
|
|
61
91
|
);
|
|
62
92
|
};
|
|
63
93
|
|
|
64
|
-
export default
|
|
94
|
+
export default themeComponent(
|
|
95
|
+
FormSelect,
|
|
96
|
+
"FormSelect",
|
|
97
|
+
fallbackValues,
|
|
98
|
+
"default"
|
|
99
|
+
);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { connect } from "react-redux";
|
|
3
|
-
import { boolean } from "@storybook/addon-knobs";
|
|
4
3
|
import { createFormState, required } from "redux-freeform";
|
|
5
4
|
|
|
6
5
|
import FormSelect from "./FormSelect";
|
|
@@ -18,7 +17,8 @@ const options = [
|
|
|
18
17
|
{ value: "", text: "choose name" },
|
|
19
18
|
{ value: "foo", text: "foo" },
|
|
20
19
|
{ value: "bar", text: "bar" },
|
|
21
|
-
{ value: "baz", text: "baz" }
|
|
20
|
+
{ value: "baz", text: "baz" },
|
|
21
|
+
{ value: "disabled", text: "disabled" }
|
|
22
22
|
];
|
|
23
23
|
|
|
24
24
|
const story = page({
|
|
@@ -32,10 +32,12 @@ const story = page({
|
|
|
32
32
|
|
|
33
33
|
const FormWrapper = ({ fields, actions }) => (
|
|
34
34
|
<FormSelect
|
|
35
|
+
labelTextWhenNoError="Form Select"
|
|
35
36
|
errorMessages={errorMessages}
|
|
36
37
|
options={options}
|
|
37
38
|
field={fields.thing}
|
|
38
39
|
fieldActions={actions.fields.thing}
|
|
40
|
+
disabledValues={["disabled"]}
|
|
39
41
|
/>
|
|
40
42
|
);
|
|
41
43
|
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import styled from "styled-components";
|
|
2
2
|
import {
|
|
3
|
-
MINESHAFT_GREY,
|
|
4
3
|
STORM_GREY,
|
|
5
|
-
WHITE,
|
|
6
|
-
SEASHELL_WHITE,
|
|
7
|
-
DUSTY_GREY,
|
|
8
4
|
GHOST_GREY,
|
|
9
5
|
ERROR_COLOR,
|
|
10
6
|
MATISSE_BLUE
|
|
@@ -17,6 +13,9 @@ export const SelectContainer = styled.div`
|
|
|
17
13
|
flex-direction: column;
|
|
18
14
|
justify-content: space-between;
|
|
19
15
|
align-items: flex-start;
|
|
16
|
+
> * + * {
|
|
17
|
+
margin-top: 0.25rem;
|
|
18
|
+
}
|
|
20
19
|
`;
|
|
21
20
|
|
|
22
21
|
export const SelectLabel = styled.label`
|
|
@@ -53,8 +52,9 @@ export const SelectField = styled.select`
|
|
|
53
52
|
font-family: Public Sans;
|
|
54
53
|
line-height: 2rem;
|
|
55
54
|
font-weight: ${FONT_WEIGHT_REGULAR};
|
|
56
|
-
background-color: ${({
|
|
57
|
-
|
|
55
|
+
background-color: ${({ themeValues }) =>
|
|
56
|
+
themeValues.inputBackgroundColor && themeValues.inputBackgroundColor};
|
|
57
|
+
color: ${({ themeValues }) => themeValues.color && themeValues.color};
|
|
58
58
|
box-shadow: none;
|
|
59
59
|
|
|
60
60
|
&:focus {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CHARADE_GREY,
|
|
3
|
+
MATISSE_BLUE,
|
|
4
|
+
WHITE,
|
|
5
|
+
SEASHELL_WHITE,
|
|
6
|
+
MINESHAFT_GREY,
|
|
7
|
+
DUSTY_GREY,
|
|
8
|
+
GREY_CHATEAU,
|
|
9
|
+
ATHENS_GREY
|
|
10
|
+
} from "../../../constants/colors";
|
|
11
|
+
import { FONT_WEIGHT_REGULAR } from "../../../constants/style_constants";
|
|
12
|
+
|
|
13
|
+
const linkColor = { default: `${MATISSE_BLUE}`, disabled: `${MATISSE_BLUE}` };
|
|
14
|
+
const formBackgroundColor = {
|
|
15
|
+
default: `${WHITE}`,
|
|
16
|
+
disabled: `${WHITE}`,
|
|
17
|
+
checkout: `${ATHENS_GREY}`,
|
|
18
|
+
collapsible: `${ATHENS_GREY}`
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const inputBackgroundColor = {
|
|
22
|
+
default: `${WHITE}`,
|
|
23
|
+
disabled: `${SEASHELL_WHITE}`
|
|
24
|
+
};
|
|
25
|
+
const color = { default: `${MINESHAFT_GREY}`, disabled: `${DUSTY_GREY}` };
|
|
26
|
+
const labelColor = { default: `${CHARADE_GREY}`, disabled: `${CHARADE_GREY}` };
|
|
27
|
+
const borderColor = { default: `${GREY_CHATEAU}`, disabled: `${GREY_CHATEAU}` };
|
|
28
|
+
const lineHeight = { default: "1rem", disabled: "1rem" };
|
|
29
|
+
const fontSize = { default: "0.875rem", disabled: "0.875rem" };
|
|
30
|
+
const errorFontSize = { default: "0.75rem", disabled: "0.75rem" };
|
|
31
|
+
const fontWeight = {
|
|
32
|
+
default: `${FONT_WEIGHT_REGULAR}`,
|
|
33
|
+
disabled: `${FONT_WEIGHT_REGULAR}`
|
|
34
|
+
};
|
|
35
|
+
const hoverFocusStyles = {
|
|
36
|
+
default: `color: #0E506D; outline: none; text-decoration: underline; `,
|
|
37
|
+
disabled: `color: #6E727E;`
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const fallbackValues = {
|
|
41
|
+
linkColor,
|
|
42
|
+
formBackgroundColor,
|
|
43
|
+
inputBackgroundColor,
|
|
44
|
+
color,
|
|
45
|
+
labelColor,
|
|
46
|
+
borderColor,
|
|
47
|
+
lineHeight,
|
|
48
|
+
fontSize,
|
|
49
|
+
errorFontSize,
|
|
50
|
+
fontWeight,
|
|
51
|
+
hoverFocusStyles
|
|
52
|
+
};
|
|
@@ -3,7 +3,7 @@ import { required, hasLength } from "redux-freeform";
|
|
|
3
3
|
import styled from "styled-components";
|
|
4
4
|
import StateProvinceDropdown from "../../atoms/state-province-dropdown";
|
|
5
5
|
import Checkbox from "../../atoms/checkbox";
|
|
6
|
-
|
|
6
|
+
import CountryDropdown from "../../atoms/country-dropdown";
|
|
7
7
|
import { zipFormat } from "../../../util/formats";
|
|
8
8
|
import { noop } from "../../../util/general";
|
|
9
9
|
import {
|
|
@@ -51,16 +51,16 @@ const AddressForm = ({
|
|
|
51
51
|
const stateProvinceErrorMessages = {
|
|
52
52
|
[required.error]: "State or Province is required"
|
|
53
53
|
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const countryErrorMessages = {
|
|
55
|
+
[required.error]: "Country is required"
|
|
56
|
+
};
|
|
57
57
|
|
|
58
58
|
const isUS = fields.country.rawValue === "US";
|
|
59
59
|
|
|
60
60
|
return (
|
|
61
61
|
<FormContainer variant={variant} role="form" aria-label="Address">
|
|
62
62
|
<FormInputColumn>
|
|
63
|
-
|
|
63
|
+
<CountryDropdown
|
|
64
64
|
labelTextWhenNoError="Country"
|
|
65
65
|
errorMessages={countryErrorMessages}
|
|
66
66
|
field={fields.country}
|
|
@@ -76,7 +76,7 @@ const AddressForm = ({
|
|
|
76
76
|
}
|
|
77
77
|
}}
|
|
78
78
|
showErrors={showErrors}
|
|
79
|
-
/>
|
|
79
|
+
/>
|
|
80
80
|
<FormInput
|
|
81
81
|
labelTextWhenNoError="Address"
|
|
82
82
|
errorMessages={street1ErrorMessages}
|
|
@@ -16,7 +16,8 @@ const PaymentButtonBar = ({
|
|
|
16
16
|
cancelURL,
|
|
17
17
|
cancelText = "Cancel",
|
|
18
18
|
redirectURL,
|
|
19
|
-
redirectText = "Return"
|
|
19
|
+
redirectText = "Return",
|
|
20
|
+
buttonFlexOverride
|
|
20
21
|
}) => {
|
|
21
22
|
const { isMobile } = useContext(ThemeContext);
|
|
22
23
|
|
|
@@ -68,7 +69,13 @@ const PaymentButtonBar = ({
|
|
|
68
69
|
<SolidDivider />
|
|
69
70
|
<Box padding="2.5rem 0 3.125rem 0">
|
|
70
71
|
<Cluster
|
|
71
|
-
justify={
|
|
72
|
+
justify={
|
|
73
|
+
buttonFlexOverride
|
|
74
|
+
? buttonFlexOverride
|
|
75
|
+
: !!backButton
|
|
76
|
+
? "space-between"
|
|
77
|
+
: "flex-end"
|
|
78
|
+
}
|
|
72
79
|
align="center"
|
|
73
80
|
childGap="0.75rem"
|
|
74
81
|
>
|
|
@@ -2,8 +2,13 @@ import React, { useEffect, useState } from "react";
|
|
|
2
2
|
import styled from "styled-components";
|
|
3
3
|
import { required, hasLength, matchesRegex } from "redux-freeform";
|
|
4
4
|
import Checkbox from "../../atoms/checkbox";
|
|
5
|
+
import CountryDropdown from "../../atoms/country-dropdown";
|
|
5
6
|
import { checkCardBrand, noop } from "../../../util/general";
|
|
6
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
expirationDateFormat,
|
|
9
|
+
creditCardFormat,
|
|
10
|
+
zipFormat
|
|
11
|
+
} from "../../../util/formats";
|
|
7
12
|
import {
|
|
8
13
|
FormInput,
|
|
9
14
|
FormInputColumn,
|
|
@@ -36,6 +41,9 @@ const zipCodeErrors = {
|
|
|
36
41
|
[required.error]: "Zip code is required",
|
|
37
42
|
[hasLength.error]: "Zip code is invalid"
|
|
38
43
|
};
|
|
44
|
+
const countryErrorMessages = {
|
|
45
|
+
[required.error]: "Country is required"
|
|
46
|
+
};
|
|
39
47
|
|
|
40
48
|
const PaymentFormCard = ({
|
|
41
49
|
variant = "default",
|
|
@@ -61,9 +69,26 @@ const PaymentFormCard = ({
|
|
|
61
69
|
return () => actions.form.clear();
|
|
62
70
|
}
|
|
63
71
|
}, []);
|
|
72
|
+
const isUS = fields.country.rawValue === "US";
|
|
64
73
|
return (
|
|
65
74
|
<FormContainer variant={variant} role="form" aria-label="Card payment">
|
|
66
75
|
<FormInputColumn>
|
|
76
|
+
{!hideZipCode && (
|
|
77
|
+
<CountryDropdown
|
|
78
|
+
labelTextWhenNoError="Country"
|
|
79
|
+
errorMessages={countryErrorMessages}
|
|
80
|
+
field={fields.country}
|
|
81
|
+
onChange={value => {
|
|
82
|
+
actions.fields.country.set(value);
|
|
83
|
+
// temporary measure to not dirty fields until
|
|
84
|
+
// we can write a reset function for fields
|
|
85
|
+
if (fields.zipCode.rawValue) {
|
|
86
|
+
actions.fields.zipCode.set("");
|
|
87
|
+
}
|
|
88
|
+
}}
|
|
89
|
+
showErrors={showErrors}
|
|
90
|
+
/>
|
|
91
|
+
)}
|
|
67
92
|
<FormInput
|
|
68
93
|
labelTextWhenNoError="Name on card"
|
|
69
94
|
errorMessages={nameOnCardErrors}
|
|
@@ -111,6 +136,8 @@ const PaymentFormCard = ({
|
|
|
111
136
|
width={isMobile ? "100%" : "50%"}
|
|
112
137
|
>
|
|
113
138
|
<FormInput
|
|
139
|
+
isNum={isUS}
|
|
140
|
+
formatter={isUS ? zipFormat : null}
|
|
114
141
|
labelTextWhenNoError="Zip code"
|
|
115
142
|
errorMessages={zipCodeErrors}
|
|
116
143
|
field={fields.zipCode}
|
|
@@ -3,12 +3,17 @@ import {
|
|
|
3
3
|
required,
|
|
4
4
|
onlyIntegers,
|
|
5
5
|
hasLength,
|
|
6
|
-
matchesRegex
|
|
6
|
+
matchesRegex,
|
|
7
|
+
validateWhen
|
|
7
8
|
} from "redux-freeform";
|
|
8
9
|
|
|
9
10
|
//TODO: Will make zip code able to have more than 5 digits once we add in the FormattedInput because it will have issues with format of 60606-1111.
|
|
10
11
|
|
|
11
12
|
const formConfig = {
|
|
13
|
+
country: {
|
|
14
|
+
defaultValue: "US",
|
|
15
|
+
validators: [required()]
|
|
16
|
+
},
|
|
12
17
|
nameOnCard: {
|
|
13
18
|
validators: [required()]
|
|
14
19
|
},
|
|
@@ -29,8 +34,23 @@ const formConfig = {
|
|
|
29
34
|
constraints: [onlyIntegers(), hasLength(0, 4)]
|
|
30
35
|
},
|
|
31
36
|
zipCode: {
|
|
32
|
-
validators: [
|
|
33
|
-
|
|
37
|
+
validators: [
|
|
38
|
+
required(),
|
|
39
|
+
validateWhen(
|
|
40
|
+
validateWhen(hasLength(5, 5), hasLength(0, 5)),
|
|
41
|
+
matchesRegex("US"),
|
|
42
|
+
"country"
|
|
43
|
+
),
|
|
44
|
+
validateWhen(
|
|
45
|
+
validateWhen(hasLength(9, 9), hasLength(6, 9)),
|
|
46
|
+
matchesRegex("US"),
|
|
47
|
+
"country"
|
|
48
|
+
)
|
|
49
|
+
],
|
|
50
|
+
constraints: [
|
|
51
|
+
validateWhen(onlyIntegers(), matchesRegex("US"), "country"),
|
|
52
|
+
validateWhen(hasLength(0, 9), matchesRegex("US"), "country")
|
|
53
|
+
]
|
|
34
54
|
}
|
|
35
55
|
};
|
|
36
56
|
|