@thecb/components 9.1.4 → 9.1.6-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thecb/components",
3
- "version": "9.1.4",
3
+ "version": "9.1.6-beta.0",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
package/src/.DS_Store ADDED
Binary file
Binary file
Binary file
@@ -10,7 +10,8 @@ const CountryDropdown = ({
10
10
  fieldActions,
11
11
  showErrors,
12
12
  onChange,
13
- dataQa = null
13
+ dataQa = null,
14
+ isRequired = false
14
15
  }) => (
15
16
  <FormSelect
16
17
  options={options}
@@ -22,6 +23,7 @@ const CountryDropdown = ({
22
23
  showErrors={showErrors}
23
24
  onChange={onChange}
24
25
  autocompleteValue="country-name"
26
+ isRequired={isRequired}
25
27
  />
26
28
  );
27
29
  export default CountryDropdown;
@@ -105,7 +105,8 @@ const Dropdown = ({
105
105
  ariaDescribedby,
106
106
  autocompleteValue, // browser autofill value, like country-name
107
107
  smoothScroll = true,
108
- ariaInvalid = false
108
+ ariaInvalid = false,
109
+ isRequired = false
109
110
  }) => {
110
111
  const [inputValue, setInputValue] = useState("");
111
112
  const [optionsState, setOptionsState] = useState([]);
@@ -328,7 +329,7 @@ const Dropdown = ({
328
329
  }}
329
330
  padding="12px"
330
331
  placeholder={getSelection()}
331
- required={options.required}
332
+ required={options.required || isRequired}
332
333
  role="combobox"
333
334
  themeValues={themeValues}
334
335
  title={hasTitles ? getSelection() : null}
@@ -116,6 +116,7 @@ const FormInput = ({
116
116
  extraStyles,
117
117
  removeFromValue, // regex of characters to remove before setting value
118
118
  dataQa = null,
119
+ isRequired = false,
119
120
  ...props
120
121
  }) => {
121
122
  const [showPassword, setShowPassword] = useState(false);
@@ -221,6 +222,7 @@ const FormInput = ({
221
222
  $extraStyles={extraStyles}
222
223
  data-qa={dataQa || labelTextWhenNoError}
223
224
  autoComplete={autocompleteValue}
225
+ required={isRequired}
224
226
  {...props}
225
227
  />
226
228
  ) : (
@@ -247,6 +249,7 @@ const FormInput = ({
247
249
  $extraStyles={extraStyles}
248
250
  data-qa={dataQa || labelTextWhenNoError}
249
251
  autoComplete={autocompleteValue}
252
+ required={isRequired}
250
253
  {...props}
251
254
  />
252
255
  )}
@@ -24,7 +24,8 @@ const FormSelect = ({
24
24
  autocompleteValue, // browser autofill value, like country-name
25
25
  smoothScroll = true, // whether the browser should animate scroll to selected item on first open
26
26
  dataQa = null,
27
- widthFitOptions = false
27
+ widthFitOptions = false,
28
+ isRequired = false
28
29
  }) => {
29
30
  const [open, setOpen] = useState(false);
30
31
  const dropdownRef = useRef(null);
@@ -94,6 +95,7 @@ const FormSelect = ({
94
95
  disabled={disabled}
95
96
  autocompleteValue={autocompleteValue}
96
97
  smoothScroll={smoothScroll}
98
+ required={isRequired}
97
99
  />
98
100
  <Stack direction="row" justify="space-between">
99
101
  <Text
@@ -8,7 +8,7 @@ export const MotionWrapper = styled(motion.div)`
8
8
  padding: ${({ padding }) => padding};
9
9
  border: ${({ borderShorthand }) => borderShorthand};
10
10
  border-color: ${({ borderColor }) => borderColor};
11
- border-size: ${({ borderSize }) => borderSize};
11
+ border-width: ${({ borderSize }) => borderSize};
12
12
  border-style: ${({ borderStyle }) => borderStyle};
13
13
  border-width: ${({ borderWidth }) => borderWidth};
14
14
  border-radius: ${({ borderRadius }) => borderRadius};
@@ -9,7 +9,8 @@ const FormStateDropdown = ({
9
9
  field,
10
10
  fieldActions,
11
11
  showErrors,
12
- countryCode
12
+ countryCode,
13
+ isRequired = false
13
14
  }) => {
14
15
  const placeholder =
15
16
  countryCode === "US" ? placeHolderOptionUS : placeHolderOption;
@@ -23,6 +24,7 @@ const FormStateDropdown = ({
23
24
  errorMessages={errorMessages}
24
25
  showErrors={showErrors}
25
26
  autocompleteValue="address-level1"
27
+ isRequired={isRequired}
26
28
  />
27
29
  );
28
30
  };
@@ -1,4 +1,4 @@
1
- import React, { useEffect } from "react";
1
+ import React, { useCallback, useEffect } from "react";
2
2
  import { required, hasLength } from "redux-freeform";
3
3
  import StateProvinceDropdown from "../../atoms/state-province-dropdown";
4
4
  import Checkbox from "../../atoms/checkbox";
@@ -10,6 +10,7 @@ import {
10
10
  FormContainer,
11
11
  FormInputColumn
12
12
  } from "../../atoms/form-layouts";
13
+ import { getIsRequiredFromValidators } from "../../../util/formUtils";
13
14
 
14
15
  const AddressForm = ({
15
16
  variant = "default",
@@ -71,6 +72,7 @@ const AddressForm = ({
71
72
  }}
72
73
  showErrors={showErrors}
73
74
  dataQa="Country"
75
+ isRequired={getIsRequiredFromValidators(useCallback)(fields.city)}
74
76
  />
75
77
  <FormInput
76
78
  labelTextWhenNoError="Address"
@@ -81,6 +83,7 @@ const AddressForm = ({
81
83
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
82
84
  autocompleteValue="address-line1"
83
85
  dataQa="Address"
86
+ isRequired={getIsRequiredFromValidators(useCallback)(fields.street1)}
84
87
  />
85
88
  <FormInput
86
89
  labelTextWhenNoError="Apt, Suite, Unit, Floor, etc. (Optional)"
@@ -90,6 +93,7 @@ const AddressForm = ({
90
93
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
91
94
  autocompleteValue="address-line2"
92
95
  dataQa="Address Line 2"
96
+ isRequired={getIsRequiredFromValidators(useCallback)(fields.street2)}
93
97
  />
94
98
  <FormInput
95
99
  labelTextWhenNoError="City"
@@ -100,6 +104,7 @@ const AddressForm = ({
100
104
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
101
105
  autocompleteValue="address-level2"
102
106
  dataQa="City"
107
+ isRequired={getIsRequiredFromValidators(useCallback)(fields.city)}
103
108
  />
104
109
  <StateProvinceDropdown
105
110
  labelTextWhenNoError={isUS ? "State" : "State or Province"}
@@ -110,6 +115,9 @@ const AddressForm = ({
110
115
  showErrors={showErrors}
111
116
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
112
117
  dataQa="State or Province"
118
+ isRequired={getIsRequiredFromValidators(useCallback)(
119
+ fields.stateProvince
120
+ )}
113
121
  />
114
122
  <FormInput
115
123
  isNum={isUS}
@@ -122,6 +130,7 @@ const AddressForm = ({
122
130
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
123
131
  autocompleteValue="postal-code"
124
132
  dataQa="Zip code"
133
+ isRequired={getIsRequiredFromValidators(useCallback)(fields.zip)}
125
134
  />
126
135
  {showWalletCheckbox && (
127
136
  <Checkbox
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from "react";
1
+ import React, { useEffect, useState, useCallback } from "react";
2
2
  import Checkbox from "../../atoms/checkbox";
3
3
  import {
4
4
  required,
@@ -16,6 +16,7 @@ import AccountAndRoutingModal from "../account-and-routing-modal";
16
16
  import { noop } from "../../../util/general";
17
17
  import { Cluster, Cover } from "../../atoms/layouts";
18
18
  import TermsAndConditions from "../terms-and-conditions";
19
+ import { getIsRequiredFromValidators } from "../../../util/formUtils";
19
20
 
20
21
  const PaymentFormACH = ({
21
22
  variant = "default",
@@ -50,7 +51,8 @@ const PaymentFormACH = ({
50
51
  };
51
52
  const confirmRoutingNumberErrors = {
52
53
  [matchesField.error]:
53
- "Confirm routing number field must match routing number"
54
+ "Confirm routing number field must match routing number",
55
+ [required.error]: "Confirm routing number is required"
54
56
  };
55
57
  const accountNumberErrors = {
56
58
  [required.error]: "Account number is required",
@@ -58,7 +60,8 @@ const PaymentFormACH = ({
58
60
  };
59
61
  const confirmAccountNumberErrors = {
60
62
  [matchesField.error]:
61
- "Confirm account number field must match account number"
63
+ "Confirm account number field must match account number",
64
+ [required.error]: "Confirm account number is required"
62
65
  };
63
66
  const accountTypeErrors = {
64
67
  [required.error]: "Account type is required"
@@ -76,6 +79,7 @@ const PaymentFormACH = ({
76
79
  showErrors={showErrors}
77
80
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
78
81
  autocompleteValue="name"
82
+ isRequired={getIsRequiredFromValidators(useCallback)(fields.name)}
79
83
  />
80
84
  <FormInput
81
85
  labelTextWhenNoError="Routing number"
@@ -84,6 +88,9 @@ const PaymentFormACH = ({
84
88
  field={fields.routingNumber}
85
89
  fieldActions={actions.fields.routingNumber}
86
90
  showErrors={showErrors}
91
+ isRequired={getIsRequiredFromValidators(useCallback)(
92
+ fields.routingNumber
93
+ )}
87
94
  isNum
88
95
  helperModal={() => (
89
96
  <AccountAndRoutingModal
@@ -106,6 +113,9 @@ const PaymentFormACH = ({
106
113
  fieldActions={actions.fields.confirmRoutingNumber}
107
114
  showErrors={showErrors}
108
115
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
116
+ isRequired={getIsRequiredFromValidators(useCallback)(
117
+ fields.confirmRoutingNumber
118
+ )}
109
119
  isNum
110
120
  />
111
121
  <FormInput
@@ -115,6 +125,9 @@ const PaymentFormACH = ({
115
125
  field={fields.accountNumber}
116
126
  fieldActions={actions.fields.accountNumber}
117
127
  showErrors={showErrors}
128
+ isRequired={getIsRequiredFromValidators(useCallback)(
129
+ fields.accountNumber
130
+ )}
118
131
  isNum
119
132
  helperModal={() => (
120
133
  <AccountAndRoutingModal
@@ -137,6 +150,9 @@ const PaymentFormACH = ({
137
150
  fieldActions={actions.fields.confirmAccountNumber}
138
151
  showErrors={showErrors}
139
152
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
153
+ isRequired={getIsRequiredFromValidators(useCallback)(
154
+ fields.confirmAccountNumber
155
+ )}
140
156
  isNum
141
157
  />
142
158
  {allowBankAccountType && (
@@ -152,6 +168,9 @@ const PaymentFormACH = ({
152
168
  showErrors={showErrors}
153
169
  errorMessages={accountTypeErrors}
154
170
  field={fields.accountType}
171
+ isRequired={getIsRequiredFromValidators(useCallback)(
172
+ fields.accountType
173
+ )}
155
174
  />
156
175
  )}
157
176
  {!hideDefaultPayment && (
@@ -16,7 +16,7 @@ const formConfig = {
16
16
  constraints: [onlyIntegers(), hasLength(0, 9)]
17
17
  },
18
18
  confirmRoutingNumber: {
19
- validators: [matchesField("routingNumber")],
19
+ validators: [matchesField("routingNumber"), required()],
20
20
  constraints: [onlyIntegers(), hasLength(0, 9)]
21
21
  },
22
22
  accountNumber: {
@@ -24,7 +24,7 @@ const formConfig = {
24
24
  constraints: [onlyIntegers(), hasLength(0, 17)]
25
25
  },
26
26
  confirmAccountNumber: {
27
- validators: [matchesField("accountNumber")],
27
+ validators: [matchesField("accountNumber"), required()],
28
28
  constraints: [onlyIntegers(), hasLength(0, 17)]
29
29
  },
30
30
  accountType: {
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useContext, useState } from "react";
1
+ import React, { useEffect, useContext, useCallback } from "react";
2
2
  import { ThemeContext } from "styled-components";
3
3
  import {
4
4
  required,
@@ -29,6 +29,7 @@ import {
29
29
  import { Box, Cluster, Cover } from "../../atoms/layouts";
30
30
  import withWindowSize from "../../withWindowSize";
31
31
  import TermsAndConditions from "../terms-and-conditions";
32
+ import { getIsRequiredFromValidators } from "../../../util/formUtils";
32
33
 
33
34
  const PaymentFormCard = ({
34
35
  variant = "default",
@@ -110,6 +111,9 @@ const PaymentFormCard = ({
110
111
  }}
111
112
  showErrors={showErrors}
112
113
  dataQa="Country"
114
+ isRequired={getIsRequiredFromValidators(useCallback)(
115
+ fields.country
116
+ )}
113
117
  />
114
118
  )}
115
119
  <FormInput
@@ -121,6 +125,9 @@ const PaymentFormCard = ({
121
125
  showErrors={showErrors}
122
126
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
123
127
  autocompleteValue="cc-name"
128
+ isRequired={getIsRequiredFromValidators(useCallback)(
129
+ fields.nameOnCard
130
+ )}
124
131
  />
125
132
  <FormInput
126
133
  labelTextWhenNoError="Credit card number"
@@ -133,6 +140,9 @@ const PaymentFormCard = ({
133
140
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
134
141
  isNum
135
142
  autocompleteValue="cc-number"
143
+ isRequired={getIsRequiredFromValidators(useCallback)(
144
+ fields.creditCardNumber
145
+ )}
136
146
  />
137
147
  <FormInputRow
138
148
  breakpoint={isMobile ? "1000rem" : "21rem"}
@@ -150,6 +160,9 @@ const PaymentFormCard = ({
150
160
  isNum
151
161
  removeFromValue={/\//} // removes "/" from browser autofill
152
162
  autocompleteValue="cc-exp"
163
+ isRequired={getIsRequiredFromValidators(useCallback)(
164
+ fields.expirationDate
165
+ )}
153
166
  />
154
167
  <FormInput
155
168
  labelTextWhenNoError="CVV"
@@ -166,6 +179,7 @@ const PaymentFormCard = ({
166
179
  }
167
180
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
168
181
  autocompleteValue="cc-csc"
182
+ isRequired={getIsRequiredFromValidators(useCallback)(fields.cvv)}
169
183
  />
170
184
  </FormInputRow>
171
185
  {!hideZipCode && (
@@ -184,6 +198,9 @@ const PaymentFormCard = ({
184
198
  showErrors={showErrors}
185
199
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
186
200
  autocompleteValue="billing postal-code"
201
+ isRequired={getIsRequiredFromValidators(useCallback)(
202
+ fields.zipCode
203
+ )}
187
204
  />
188
205
  </Box>
189
206
  )}
@@ -47,7 +47,8 @@ const RadioSection = ({
47
47
  initiallyOpen = true,
48
48
  openHeight = "auto",
49
49
  containerStyles = "",
50
- ariaDescribedBy
50
+ ariaDescribedBy,
51
+ isRequired = false
51
52
  }) => {
52
53
  const handleKeyDown = (id, e) => {
53
54
  if (e?.keyCode === 13 || e?.keyCode === 32) {
@@ -105,7 +106,7 @@ const RadioSection = ({
105
106
  borderRadius="4px"
106
107
  extraStyles={containerStyles}
107
108
  >
108
- <Stack childGap="0" role="radiogroup">
109
+ <Stack childGap="0" role="radiogroup" required={isRequired}>
109
110
  {sections
110
111
  .filter(section => !section.hidden)
111
112
  .map(section => (
@@ -123,7 +124,8 @@ const RadioSection = ({
123
124
  extraStyles={borderStyles}
124
125
  role="radio"
125
126
  aria-checked={openSection === section.id}
126
- aria-disabled={section.disabled}
127
+ disabled={section.disabled}
128
+ required={section?.required}
127
129
  >
128
130
  <Stack childGap="0">
129
131
  <Box
@@ -166,6 +168,8 @@ const RadioSection = ({
166
168
  {!section.hideRadioButton && (
167
169
  <Box padding="0">
168
170
  <RadioButton
171
+ role="radio"
172
+ required={!!section?.required}
169
173
  id={`radio-input-${idString(section)}`}
170
174
  name={idString(section)}
171
175
  ariaDescribedBy={ariaDescribedBy}
@@ -49,10 +49,11 @@ const sections = [
49
49
  title: "New Card",
50
50
  content: <p>The form to add a credit card would go here.</p>,
51
51
  rightIconsLabel: cardIconsLabel,
52
- rightIcons: cardIcons
52
+ rightIcons: cardIcons,
53
+ required: true
53
54
  },
54
- { id: "bar", title: "Bar", content: <div>Content 1</div> },
55
- { id: "baz", title: "Baz", content: <div>Content 2</div> }
55
+ { id: "bar", title: "Bar", content: <div>Content 1</div>, required: true },
56
+ { id: "baz", title: "Baz", content: <div>Content 2</div>, required: true }
56
57
  ];
57
58
 
58
59
  export const radioSection = () => {
@@ -19,7 +19,8 @@ const RadioButton = ({
19
19
  ariaDescribedBy = "",
20
20
  themeValues,
21
21
  ariaLabelledBy = "",
22
- ariaLabel = null
22
+ ariaLabel = null,
23
+ required = false
23
24
  }) => {
24
25
  const buttonBorder = {
25
26
  onFocused: {
@@ -93,6 +94,7 @@ const RadioButton = ({
93
94
  onClick={toggleRadio}
94
95
  aria-describedby={ariaDescribedBy}
95
96
  tabIndex="-1"
97
+ required={required}
96
98
  {...extraProps}
97
99
  />
98
100
  <Motion
@@ -0,0 +1,9 @@
1
+ export const getIsRequiredFromValidators = callbackFn => {
2
+ return callbackFn(
3
+ field =>
4
+ !!field.validators.find(
5
+ validator => validator.type === "validator/REQUIRED"
6
+ ),
7
+ []
8
+ );
9
+ };