@thecb/components 9.2.3-beta.3 → 9.2.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.
Files changed (24) hide show
  1. package/dist/index.cjs.js +54 -66
  2. package/dist/index.cjs.js.map +1 -1
  3. package/dist/index.esm.js +54 -66
  4. package/dist/index.esm.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/components/atoms/checkbox/Checkbox.js +1 -3
  7. package/src/components/atoms/checkbox/Checkbox.stories.js +2 -3
  8. package/src/components/atoms/country-dropdown/CountryDropdown.js +2 -2
  9. package/src/components/atoms/country-dropdown/CountryDropdown.stories.js +0 -1
  10. package/src/components/atoms/dropdown/Dropdown.js +5 -8
  11. package/src/components/atoms/form-select/FormSelect.js +9 -20
  12. package/src/components/atoms/form-select/FormSelect.stories.js +2 -2
  13. package/src/components/atoms/radio-button-with-label/RadioButtonWithLabel.js +6 -9
  14. package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.js +0 -1
  15. package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.stories.js +0 -1
  16. package/src/components/molecules/address-form/AddressForm.js +1 -2
  17. package/src/components/molecules/email-form/EmailForm.js +3 -1
  18. package/src/components/molecules/payment-form-ach/PaymentFormACH.js +4 -4
  19. package/src/components/molecules/payment-form-card/PaymentFormCard.js +1 -2
  20. package/src/components/molecules/phone-form/PhoneForm.js +3 -1
  21. package/src/components/molecules/radio-group/RadioGroup.js +1 -1
  22. package/src/components/molecules/radio-section/RadioSection.js +9 -3
  23. package/src/components/molecules/radio-section/RadioSection.stories.js +1 -0
  24. package/src/components/molecules/radio-section/radio-button/RadioButton.js +2 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thecb/components",
3
- "version": "9.2.3-beta.3",
3
+ "version": "9.2.3",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
@@ -95,8 +95,7 @@ const Checkbox = ({
95
95
  checkboxMargin = "0 16px 0 0",
96
96
  extraStyles,
97
97
  textExtraStyles,
98
- dataQa = null,
99
- isRequired = false
98
+ dataQa = null
100
99
  }) => {
101
100
  const [focused, setFocused] = useState(false);
102
101
 
@@ -143,7 +142,6 @@ const Checkbox = ({
143
142
  disabledStyles={themeValues.disabledStyles}
144
143
  disabledCheckedStyles={themeValues.disabledCheckedStyles}
145
144
  focusedStyles={themeValues.focusedStyles}
146
- aria-required={isRequired}
147
145
  >
148
146
  <CheckboxIcon
149
147
  viewBox="0 0 24 24"
@@ -13,13 +13,12 @@ const groupId = "props";
13
13
  export const checkbox = () => (
14
14
  <Checkbox
15
15
  variant={select(variantsLabel, variants, defaultValue, groupId)}
16
- title={text("title", "Checkbox Title", "props")}
17
- name={text("name", "Checkbox Name", "props")}
16
+ title={text("title", "Checkbox", "props")}
17
+ name={text("name", "Checkbox", "props")}
18
18
  checked={boolean("checked", false, "props")}
19
19
  error={boolean("error", false, "props")}
20
20
  disabled={boolean("disabled", false, "props")}
21
21
  focused={boolean("focused", false, "props")}
22
- isRequired={boolean("isRequired", true, "props")}
23
22
  />
24
23
  );
25
24
 
@@ -10,8 +10,8 @@ const CountryDropdown = ({
10
10
  fieldActions,
11
11
  showErrors,
12
12
  onChange,
13
- dataQa = null,
14
- isRequired = false
13
+ isRequired = false,
14
+ dataQa = null
15
15
  }) => (
16
16
  <FormSelect
17
17
  options={options}
@@ -30,7 +30,6 @@ const CountryFormWrapper = ({ fields, actions }) => (
30
30
  options={options}
31
31
  field={fields.country}
32
32
  fieldActions={actions.fields.country}
33
- isRequired={true}
34
33
  />
35
34
  </Box>
36
35
  );
@@ -136,7 +136,6 @@ const Dropdown = ({
136
136
  ariaInvalid = false,
137
137
  isRequired = false
138
138
  }) => {
139
- const required = options.required || isRequired;
140
139
  const [inputValue, setInputValue] = useState("");
141
140
  const [optionsState, setOptionsState] = useState([]);
142
141
  const [filteredOptions, setFilteredOptions] = useState([]);
@@ -264,13 +263,13 @@ const Dropdown = ({
264
263
  useEffect(() => {
265
264
  if (autoEraseTypeAhead) {
266
265
  clearTimeout(timer);
267
- setTimer(setTimeout(() => setInputValue(""), 3000));
266
+ setTimer(setTimeout(() => setInputValue(""), 20000));
268
267
  }
269
268
  setFilteredOptions(
270
269
  options.filter(
271
270
  option =>
272
- option.value.toLowerCase().startsWith(inputValue.toLowerCase()) ||
273
- option.text.toLowerCase().startsWith(inputValue.toLowerCase())
271
+ option.value.toLowerCase().match(inputValue.toLowerCase()) ||
272
+ option.text.toLowerCase().match(inputValue.toLowerCase())
274
273
  )
275
274
  );
276
275
  }, [inputValue]);
@@ -326,7 +325,7 @@ const Dropdown = ({
326
325
  aria-labelledby={ariaLabelledby}
327
326
  aria-describedby={ariaDescribedby}
328
327
  aria-expanded={isOpen}
329
- aria-required={required}
328
+ aria-required={options.required}
330
329
  aria-invalid={ariaInvalid}
331
330
  background={isOpen ? themeValues.hoverColor : WHITE}
332
331
  borderRadius="2px"
@@ -358,6 +357,7 @@ const Dropdown = ({
358
357
  }}
359
358
  padding="12px"
360
359
  placeholder={getSelection()}
360
+ required={options.required || isRequired}
361
361
  role="combobox"
362
362
  themeValues={themeValues}
363
363
  title={hasTitles ? getSelection() : null}
@@ -365,8 +365,6 @@ const Dropdown = ({
365
365
  tabIndex={0}
366
366
  value={inputValue}
367
367
  width="100%"
368
- /* Non-semantic elements need the aria-* version of the attribute */
369
- aria-disabled={disabledValues.includes(inputValue)}
370
368
  />
371
369
  <IconWrapper open={isOpen} onClick={onClick}>
372
370
  <DropdownIcon />
@@ -381,7 +379,6 @@ const Dropdown = ({
381
379
  tabIndex={0}
382
380
  role="listbox"
383
381
  id={`${ariaLabelledby}_listbox`}
384
- required={required}
385
382
  >
386
383
  <Stack childGap="0" as="ul">
387
384
  {filteredOptions.map((choice, i) => {
@@ -1,4 +1,4 @@
1
- import React, { useState, useMemo, useRef, useEffect } from "react";
1
+ import React, { useState, useRef, useEffect } from "react";
2
2
  import Dropdown from "../dropdown";
3
3
  import Text from "../text";
4
4
  import { ERROR_COLOR } from "../../../constants/colors";
@@ -29,20 +29,6 @@ const FormSelect = ({
29
29
  }) => {
30
30
  const [open, setOpen] = useState(false);
31
31
  const dropdownRef = useRef(null);
32
- const required = options?.required || isRequired;
33
-
34
- const labelId = useMemo(
35
- () => labelTextWhenNoError => createIdFromString(labelTextWhenNoError),
36
- [labelTextWhenNoError]
37
- );
38
-
39
- const descriptionId = useMemo(
40
- () => (field, labelTextWhenNoError) =>
41
- field.hasErrors && field.dirty
42
- ? labelId(labelTextWhenNoError) + "error-message"
43
- : "",
44
- [field, labelTextWhenNoError]
45
- );
46
32
 
47
33
  const handleClickAway = event => {
48
34
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
@@ -60,8 +46,8 @@ const FormSelect = ({
60
46
  return (
61
47
  <SelectContainer
62
48
  ref={dropdownRef}
63
- aria-role="group"
64
49
  disabled={disabled}
50
+ aria-disabled={disabled}
65
51
  data-qa={dataQa}
66
52
  >
67
53
  <Box padding="0" minWidth="100%">
@@ -76,15 +62,18 @@ const FormSelect = ({
76
62
  &::first-letter {
77
63
  text-transform: uppercase;
78
64
  }`}
79
- id={labelId(labelTextWhenNoError)}
65
+ id={createIdFromString(labelTextWhenNoError)}
80
66
  >
81
67
  {labelTextWhenNoError}
82
68
  </Text>
83
69
  </Cluster>
84
70
  </Box>
85
71
  <Dropdown
86
- ariaLabelledby={labelId(labelTextWhenNoError)}
87
- ariaDescribedby={descriptionId(field, labelTextWhenNoError)}
72
+ ariaLabelledby={createIdFromString(labelTextWhenNoError)}
73
+ ariaDescribedby={createIdFromString(
74
+ labelTextWhenNoError,
75
+ "error message"
76
+ )}
88
77
  maxHeight={dropdownMaxHeight}
89
78
  widthFitOptions={widthFitOptions}
90
79
  hasTitles={hasTitles}
@@ -106,7 +95,7 @@ const FormSelect = ({
106
95
  disabled={disabled}
107
96
  autocompleteValue={autocompleteValue}
108
97
  smoothScroll={smoothScroll}
109
- isRequired={required}
98
+ isRequired={isRequired}
110
99
  />
111
100
  <Stack direction="row" justify="space-between">
112
101
  {(field.hasErrors && field.dirty) || (field.hasErrors && showErrors) ? (
@@ -12,7 +12,7 @@ const { mapStateToProps, mapDispatchToProps, reducer } = createFormState({
12
12
  }
13
13
  });
14
14
  const errorMessages = {
15
- [required.error]: "This field is required."
15
+ [required.error]: "thing is required"
16
16
  };
17
17
  const options = [
18
18
  { value: "", text: "choose name" },
@@ -34,7 +34,7 @@ const story = page({
34
34
  const FormWrapper = props => (
35
35
  <FormSelect
36
36
  autocompleteValue={props.autocompleteValue}
37
- labelTextWhenNoError="Form Select Label"
37
+ labelTextWhenNoError="Form Select"
38
38
  errorMessages={errorMessages}
39
39
  options={options}
40
40
  field={props.fields.thing}
@@ -18,7 +18,7 @@ const Circle = styled.div`
18
18
  flex-shrink: 0;
19
19
  margin-right: 8px;
20
20
  width: 1.5rem;
21
- height: 1.5rem;
21
+ height 1.5rem;
22
22
  border: ${({ inactiveBorderColor }) => `1px solid ${inactiveBorderColor}`};
23
23
  border-radius: 50%;
24
24
  box-sizing: border-box;
@@ -30,24 +30,21 @@ const Circle = styled.div`
30
30
  display: block;
31
31
  background: ${({ activeColor }) => activeColor};
32
32
  border-radius: 50%;
33
- transform: scale(0);
34
- }
33
+ transform: scale(0);
34
+ }
35
35
  `;
36
36
 
37
37
  const InputAndLabelContainer = styled(Cluster)`
38
38
  overflow: visible;
39
-
40
39
  ${HiddenRadioInput}:checked + label ${Circle}:after {
41
40
  transform: scale(0.85);
42
41
  transition: transform 0.15s;
43
42
  }
44
-
45
43
  ${HiddenRadioInput}:checked + label ${Circle} {
46
- border: ${({ activeColor }) => "1px solid " + activeColor};
44
+ border: ${({ activeColor }) => `1px solid ${activeColor};`}
47
45
  }
48
-
49
- ${HiddenRadioInput}:focus + label ${Circle} {
50
- box-shadow: ${({ activeColor }) => "0px 0px 2px 1px " + activeColor};
46
+ ${HiddenRadioInput}:focus + label ${Circle} { {
47
+ box-shadow: ${({ activeColor }) => `0px 0px 2px 1px ${activeColor};`}
51
48
  }
52
49
  `;
53
50
 
@@ -15,7 +15,6 @@ const FormStateDropdown = ({
15
15
  const placeholder =
16
16
  countryCode === "US" ? placeHolderOptionUS : placeHolderOption;
17
17
  const options = [placeholder, ...getOptions(countryCode)];
18
-
19
18
  return (
20
19
  <FormSelect
21
20
  options={options}
@@ -39,7 +39,6 @@ const FormWrapper = ({
39
39
  countryCode={countryCode}
40
40
  labelTextWhenNoError={labelTextWhenNoError}
41
41
  showErrors={showErrors}
42
- isRequired={true}
43
42
  />
44
43
  );
45
44
 
@@ -58,7 +58,6 @@ const AddressForm = ({
58
58
  labelTextWhenNoError="Country"
59
59
  errorMessages={countryErrorMessages}
60
60
  field={fields.country}
61
- isRequired={true}
62
61
  onChange={value => {
63
62
  actions.fields.country.set(value);
64
63
  // temporary measure to not dirty fields until
@@ -72,6 +71,7 @@ const AddressForm = ({
72
71
  }}
73
72
  showErrors={showErrors}
74
73
  dataQa="Country"
74
+ isRequired={true}
75
75
  />
76
76
  <FormInput
77
77
  labelTextWhenNoError="Address"
@@ -92,7 +92,6 @@ const AddressForm = ({
92
92
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
93
93
  autocompleteValue="address-line2"
94
94
  dataQa="Address Line 2"
95
- isRequired={false}
96
95
  />
97
96
  <FormInput
98
97
  labelTextWhenNoError="City"
@@ -19,7 +19,8 @@ const EmailForm = ({
19
19
  handleSubmit = noop,
20
20
  showWalletCheckbox,
21
21
  saveToWallet,
22
- walletCheckboxMarked
22
+ walletCheckboxMarked,
23
+ isRequired = false
23
24
  }) => {
24
25
  if (clearOnDismount) {
25
26
  useEffect(() => () => actions.form.clear(), []);
@@ -48,6 +49,7 @@ const EmailForm = ({
48
49
  isEmail
49
50
  autocompleteValue="email"
50
51
  dataQa="Email address"
52
+ isRequired={isRequired}
51
53
  />
52
54
  {showWalletCheckbox && (
53
55
  <Checkbox
@@ -108,8 +108,8 @@ const PaymentFormACH = ({
108
108
  fieldActions={actions.fields.confirmRoutingNumber}
109
109
  showErrors={showErrors}
110
110
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
111
- isRequired={true}
112
111
  isNum
112
+ isRequired={true}
113
113
  />
114
114
  <FormInput
115
115
  labelTextWhenNoError="Account number"
@@ -118,7 +118,6 @@ const PaymentFormACH = ({
118
118
  field={fields.accountNumber}
119
119
  fieldActions={actions.fields.accountNumber}
120
120
  showErrors={showErrors}
121
- isRequired={true}
122
121
  isNum
123
122
  helperModal={() => (
124
123
  <AccountAndRoutingModal
@@ -132,22 +131,22 @@ const PaymentFormACH = ({
132
131
  />
133
132
  )}
134
133
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
134
+ isRequired={true}
135
135
  />
136
136
  <FormInput
137
137
  labelTextWhenNoError="Confirm account number"
138
138
  dataQa="Confirm account number"
139
- isRequired={true}
140
139
  errorMessages={confirmAccountNumberErrors}
141
140
  field={fields.confirmAccountNumber}
142
141
  fieldActions={actions.fields.confirmAccountNumber}
143
142
  showErrors={showErrors}
144
143
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
144
+ isRequired={true}
145
145
  isNum
146
146
  />
147
147
  {allowBankAccountType && (
148
148
  <FormSelect
149
149
  labelTextWhenNoError="Account type"
150
- isRequired={true}
151
150
  dataQa="Account type"
152
151
  options={[
153
152
  { text: "Select account type", value: "" },
@@ -158,6 +157,7 @@ const PaymentFormACH = ({
158
157
  showErrors={showErrors}
159
158
  errorMessages={accountTypeErrors}
160
159
  field={fields.accountType}
160
+ isRequired={true}
161
161
  />
162
162
  )}
163
163
  {!hideDefaultPayment && (
@@ -98,7 +98,6 @@ const PaymentFormCard = ({
98
98
  {!hideZipCode && (
99
99
  <CountryDropdown
100
100
  labelTextWhenNoError="Country"
101
- isRequired={true}
102
101
  errorMessages={countryErrorMessages}
103
102
  field={fields.country}
104
103
  onChange={value => {
@@ -125,7 +124,6 @@ const PaymentFormCard = ({
125
124
  isRequired={true}
126
125
  />
127
126
  <FormInput
128
- isRequired={true}
129
127
  labelTextWhenNoError="Credit card number"
130
128
  dataQa="Credit card number"
131
129
  errorMessages={creditCardNumberErrors}
@@ -136,6 +134,7 @@ const PaymentFormCard = ({
136
134
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
137
135
  isNum
138
136
  autocompleteValue="cc-number"
137
+ isRequired={true}
139
138
  />
140
139
  <FormInputRow
141
140
  breakpoint={isMobile ? "1000rem" : "21rem"}
@@ -19,7 +19,8 @@ const PhoneForm = ({
19
19
  handleSubmit = noop,
20
20
  showWalletCheckbox,
21
21
  saveToWallet,
22
- walletCheckboxMarked
22
+ walletCheckboxMarked,
23
+ isRequired = false
23
24
  }) => {
24
25
  if (clearOnDismount) {
25
26
  useEffect(() => () => actions.form.clear(), []);
@@ -43,6 +44,7 @@ const PhoneForm = ({
43
44
  autocompleteValue="tel-national"
44
45
  dataQa="Phone number"
45
46
  isNum={true}
47
+ isRequired={isRequired}
46
48
  />
47
49
  {showWalletCheckbox && (
48
50
  <Checkbox
@@ -7,7 +7,7 @@ import { noop } from "../../../util/general";
7
7
 
8
8
  const DefaultHeading = styled.div`
9
9
  font-size: 0.875rem;
10
- color: ${colors.CHARADE_GREY};
10
+ color: ${colors.CHARADE_GREY}
11
11
  margin: 0;
12
12
  padding: 8px 0px;
13
13
  `;
@@ -47,7 +47,8 @@ const RadioSection = ({
47
47
  initiallyOpen = true,
48
48
  openHeight = "auto",
49
49
  containerStyles = "",
50
- ariaDescribedBy
50
+ ariaDescribedBy,
51
+ isSectionRequired = false
51
52
  }) => {
52
53
  const handleKeyDown = (id, e) => {
53
54
  if (e?.keyCode === 13 || e?.keyCode === 32) {
@@ -105,7 +106,11 @@ const RadioSection = ({
105
106
  borderRadius="4px"
106
107
  extraStyles={containerStyles}
107
108
  >
108
- <Stack childGap="0" role="radiogroup">
109
+ <Stack
110
+ childGap="0"
111
+ aria-role="radiogroup"
112
+ aria-required={isSectionRequired}
113
+ >
109
114
  {sections
110
115
  .filter(section => !section.hidden)
111
116
  .map(section => (
@@ -124,6 +129,7 @@ const RadioSection = ({
124
129
  role="radio"
125
130
  aria-checked={openSection === section.id}
126
131
  aria-disabled={section.disabled}
132
+ aria-required={section?.required}
127
133
  >
128
134
  <Stack childGap="0">
129
135
  <Box
@@ -177,7 +183,7 @@ const RadioSection = ({
177
183
  : () => toggleOpenSection(section.id)
178
184
  }
179
185
  tabIndex="-1"
180
- required={section?.required}
186
+ isRequired={section?.required}
181
187
  />
182
188
  </Box>
183
189
  )}
@@ -66,6 +66,7 @@ export const radioSection = () => {
66
66
  openSection={openSection}
67
67
  staggeredAnimation={boolean("staggeredAnimation", false, "props")}
68
68
  sections={sections}
69
+ isSectionRequired={true}
69
70
  />
70
71
  );
71
72
  };
@@ -20,7 +20,7 @@ const RadioButton = ({
20
20
  themeValues,
21
21
  ariaLabelledBy = "",
22
22
  ariaLabel = null,
23
- required = false
23
+ isRequired = false
24
24
  }) => {
25
25
  const buttonBorder = {
26
26
  onFocused: {
@@ -91,11 +91,10 @@ const RadioButton = ({
91
91
  type="radio"
92
92
  id={`radio-${name}`}
93
93
  disabled={disabled}
94
- required={required}
95
- aria-required={required}
96
94
  onClick={toggleRadio}
97
95
  aria-describedby={ariaDescribedBy}
98
96
  tabIndex="-1"
97
+ required={isRequired}
99
98
  {...extraProps}
100
99
  />
101
100
  <Motion