@thecb/components 9.3.0-beta.2 → 9.3.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.
Files changed (75) hide show
  1. package/dist/index.cjs.js +840 -617
  2. package/dist/index.cjs.js.map +1 -1
  3. package/dist/index.d.ts +171 -60
  4. package/dist/index.esm.js +837 -617
  5. package/dist/index.esm.js.map +1 -1
  6. package/package.json +1 -1
  7. package/src/.DS_Store +0 -0
  8. package/src/components/atoms/button-with-action/ButtonWithAction.js +76 -70
  9. package/src/components/atoms/checkbox/Checkbox.js +9 -4
  10. package/src/components/atoms/checkbox/Checkbox.stories.js +3 -3
  11. package/src/components/atoms/country-dropdown/CountryDropdown.js +2 -2
  12. package/src/components/atoms/country-dropdown/CountryDropdown.stories.js +0 -1
  13. package/src/components/atoms/dropdown/Dropdown.js +77 -44
  14. package/src/components/atoms/dropdown/Dropdown.theme.js +8 -2
  15. package/src/components/atoms/form-layouts/FormInput.js +2 -3
  16. package/src/components/atoms/form-select/FormSelect.js +25 -34
  17. package/src/components/atoms/form-select/FormSelect.stories.js +2 -2
  18. package/src/components/atoms/icons/AccountNumberImage.js +2 -0
  19. package/src/components/atoms/icons/BankIcon.js +2 -0
  20. package/src/components/atoms/icons/CheckmarkIcon.js +2 -0
  21. package/src/components/atoms/icons/GenericCard.js +2 -0
  22. package/src/components/atoms/icons/GenericCardLarge.js +2 -0
  23. package/src/components/atoms/icons/KebabMenuIcon.d.ts +1 -0
  24. package/src/components/atoms/icons/KebabMenuIcon.js +38 -0
  25. package/src/components/atoms/icons/RoutingNumberImage.js +2 -0
  26. package/src/components/atoms/icons/TrashIcon.js +42 -40
  27. package/src/components/atoms/icons/icons.stories.js +3 -1
  28. package/src/components/atoms/icons/index.d.ts +1 -0
  29. package/src/components/atoms/icons/index.js +3 -1
  30. package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.js +0 -1
  31. package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.stories.js +0 -1
  32. package/src/components/molecules/address-form/AddressForm.js +1 -2
  33. package/src/components/molecules/email-form/EmailForm.js +3 -1
  34. package/src/components/molecules/index.d.ts +1 -0
  35. package/src/components/molecules/index.js +1 -0
  36. package/src/components/molecules/modal/Modal.js +2 -1
  37. package/src/components/molecules/payment-form-ach/PaymentFormACH.js +4 -5
  38. package/src/components/molecules/payment-form-card/PaymentFormCard.js +0 -2
  39. package/src/components/molecules/phone-form/PhoneForm.js +3 -1
  40. package/src/components/molecules/popover/Popover.js +1 -1
  41. package/src/components/molecules/popup-menu/PopupMenu.js +152 -0
  42. package/src/components/molecules/popup-menu/PopupMenu.stories.js +40 -0
  43. package/src/components/molecules/popup-menu/PopupMenu.styled.js +20 -0
  44. package/src/components/molecules/popup-menu/PopupMenu.theme.js +11 -0
  45. package/src/components/molecules/popup-menu/index.d.ts +25 -0
  46. package/src/components/molecules/popup-menu/index.js +3 -0
  47. package/src/components/molecules/popup-menu/popup-menu-item/PopupMenuItem.js +79 -0
  48. package/src/components/molecules/popup-menu/popup-menu-item/PopupMenuItem.styled.js +27 -0
  49. package/src/components/molecules/popup-menu/popup-menu-item/PopupMenuItem.theme.js +23 -0
  50. package/src/components/molecules/radio-section/RadioSection.js +10 -4
  51. package/src/components/molecules/radio-section/RadioSection.stories.js +1 -0
  52. package/src/components/molecules/radio-section/radio-button/RadioButton.js +2 -3
  53. package/src/components/molecules/terms-and-conditions/TermsAndConditions.stories.js +3 -1
  54. package/src/components/molecules/terms-and-conditions/TermsAndConditionsControlV1.js +0 -1
  55. package/src/components/molecules/terms-and-conditions/TermsAndConditionsControlV2.js +5 -2
  56. package/src/components/molecules/toast-notification/ToastNotification.js +75 -0
  57. package/src/components/molecules/toast-notification/ToastNotification.stories.js +67 -0
  58. package/src/components/molecules/toast-notification/index.d.ts +18 -0
  59. package/src/components/molecules/toast-notification/index.js +3 -0
  60. package/src/constants/colors.d.ts +1 -0
  61. package/src/constants/colors.js +5 -1
  62. package/src/hooks/index.js +3 -0
  63. package/src/hooks/use-toast-notification/index.d.ts +23 -0
  64. package/src/hooks/use-toast-notification/index.js +38 -0
  65. package/src/index.d.ts +2 -1
  66. package/src/index.js +2 -1
  67. package/src/types/common/ToastVariants.ts +6 -0
  68. package/src/types/common/index.ts +1 -0
  69. package/src/util/index.js +10 -2
  70. package/dist/src/apps/checkout/pages/payment/sub-pages/payment-amount/PaymentAmount_old.js +0 -49322
  71. package/src/components/.DS_Store +0 -0
  72. package/src/components/atoms/.DS_Store +0 -0
  73. package/src/components/atoms/icons/.DS_Store +0 -0
  74. /package/src/{util/useOutsideClick.js → hooks/use-outside-click/index.js} +0 -0
  75. /package/src/{util/useScrollTo.js → hooks/use-scroll-to/index.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thecb/components",
3
- "version": "9.3.0-beta.2",
3
+ "version": "9.3.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 CHANGED
Binary file
@@ -1,4 +1,4 @@
1
- import React, { useContext } from "react";
1
+ import React, { useContext, forwardRef } from "react";
2
2
  import styled, { ThemeContext } from "styled-components";
3
3
  import posed from "react-pose";
4
4
  import { linear } from "@popmotion/easing";
@@ -60,32 +60,36 @@ const Spinner = ({ color, isMobile }) => (
60
60
 
61
61
  */
62
62
 
63
- const ButtonWithAction = ({
64
- action = noop,
65
- variant = "primary",
66
- text,
67
- textWrap = false,
68
- isLoading = false,
69
- loadingColor = "white",
70
- dataQa = null,
71
- textExtraStyles,
72
- contentOverride = false,
73
- extraStyles = "",
74
- tabIndex,
75
- children,
76
- extraDisabledStyles,
77
- ...rest
78
- }) => {
79
- const themeContext = useContext(ThemeContext);
80
- const themeValues = createThemeValues(
81
- themeContext,
82
- fallbackValues,
83
- "Button",
84
- variant
85
- );
86
- const { isMobile } = themeContext;
63
+ const ButtonWithAction = forwardRef(
64
+ (
65
+ {
66
+ action = noop,
67
+ variant = "primary",
68
+ text,
69
+ textWrap = false,
70
+ isLoading = false,
71
+ loadingColor = "white",
72
+ dataQa = null,
73
+ textExtraStyles,
74
+ contentOverride = false,
75
+ extraStyles = "",
76
+ tabIndex,
77
+ children,
78
+ extraDisabledStyles,
79
+ ...rest
80
+ },
81
+ ref
82
+ ) => {
83
+ const themeContext = useContext(ThemeContext);
84
+ const themeValues = createThemeValues(
85
+ themeContext,
86
+ fallbackValues,
87
+ "Button",
88
+ variant
89
+ );
90
+ const { isMobile } = themeContext;
87
91
 
88
- const hoverStyles = `
92
+ const hoverStyles = `
89
93
  outline: none;
90
94
  background-color: ${themeValues.hoverBackgroundColor};
91
95
  border-color: ${themeValues.hoverBorderColor};
@@ -95,7 +99,7 @@ const ButtonWithAction = ({
95
99
  };
96
100
  cursor: pointer;
97
101
  `;
98
- const activeStyles = `
102
+ const activeStyles = `
99
103
  outline: none;
100
104
  background-color: ${themeValues.activeBackgroundColor};
101
105
  border-color: ${themeValues.activeBorderColor};
@@ -104,7 +108,7 @@ const ButtonWithAction = ({
104
108
  variant === "ghost" || variant === "smallGhost" ? "underline" : "none"
105
109
  };
106
110
  `;
107
- const disabledStyles = `
111
+ const disabledStyles = `
108
112
  background-color: #6D717E;
109
113
  border-color: #6D717E;
110
114
  color: #FFFFFF;
@@ -116,47 +120,49 @@ const ButtonWithAction = ({
116
120
  ${extraDisabledStyles}
117
121
  `;
118
122
 
119
- return (
120
- <Box
121
- variant={variant}
122
- padding={themeValues.padding}
123
- minHeight={themeValues.height}
124
- minWidth={themeValues.minWidth}
125
- background={themeValues.backgroundColor}
126
- border={themeValues.border}
127
- hoverStyles={hoverStyles}
128
- activeStyles={activeStyles}
129
- disabledStyles={disabledStyles}
130
- as="button"
131
- onClick={isLoading ? undefined : action}
132
- borderRadius="2px"
133
- theme={themeContext}
134
- extraStyles={`margin: 0.5rem; ${extraStyles}`}
135
- dataQa={dataQa}
136
- tabIndex={tabIndex}
137
- {...rest}
138
- >
139
- {contentOverride ? (
140
- children
141
- ) : (
142
- <Center intrinsic>
143
- {isLoading ? (
144
- <Spinner color={loadingColor} isMobile={isMobile} />
145
- ) : (
146
- <Text
147
- weight={themeValues.fontWeight}
148
- variant={themeValues.fontSizeVariant}
149
- color={themeValues.color}
150
- textWrap={textWrap}
151
- extraStyles={textExtraStyles}
152
- >
153
- {text}
154
- </Text>
155
- )}
156
- </Center>
157
- )}
158
- </Box>
159
- );
160
- };
123
+ return (
124
+ <Box
125
+ ref={ref}
126
+ variant={variant}
127
+ padding={themeValues.padding}
128
+ minHeight={themeValues.height}
129
+ minWidth={themeValues.minWidth}
130
+ background={themeValues.backgroundColor}
131
+ border={themeValues.border}
132
+ hoverStyles={hoverStyles}
133
+ activeStyles={activeStyles}
134
+ disabledStyles={disabledStyles}
135
+ as="button"
136
+ onClick={isLoading ? undefined : action}
137
+ borderRadius="2px"
138
+ theme={themeContext}
139
+ extraStyles={`margin: 0.5rem; ${extraStyles}`}
140
+ dataQa={dataQa}
141
+ tabIndex={tabIndex}
142
+ {...rest}
143
+ >
144
+ {contentOverride ? (
145
+ children
146
+ ) : (
147
+ <Center intrinsic>
148
+ {isLoading ? (
149
+ <Spinner color={loadingColor} isMobile={isMobile} />
150
+ ) : (
151
+ <Text
152
+ weight={themeValues.fontWeight}
153
+ variant={themeValues.fontSizeVariant}
154
+ color={themeValues.color}
155
+ textWrap={textWrap}
156
+ extraStyles={textExtraStyles}
157
+ >
158
+ {text}
159
+ </Text>
160
+ )}
161
+ </Center>
162
+ )}
163
+ </Box>
164
+ );
165
+ }
166
+ );
161
167
 
162
168
  export default ButtonWithAction;
@@ -95,8 +95,8 @@ const Checkbox = ({
95
95
  checkboxMargin = "0 16px 0 0",
96
96
  extraStyles,
97
97
  textExtraStyles,
98
- dataQa = null,
99
- isRequired = false
98
+ labelledById,
99
+ dataQa = null
100
100
  }) => {
101
101
  const [focused, setFocused] = useState(false);
102
102
 
@@ -106,6 +106,10 @@ const Checkbox = ({
106
106
  }
107
107
  };
108
108
 
109
+ const titleId = title ? `checkboxlabel-${name}` : undefined;
110
+ const ariaLabelledById = labelledById ?? titleId;
111
+ const ariaLabel = ariaLabelledById ? undefined : name;
112
+
109
113
  return (
110
114
  <Box
111
115
  padding="0"
@@ -123,7 +127,8 @@ const Checkbox = ({
123
127
  id={`checkbox-${name}`}
124
128
  disabled={disabled}
125
129
  name={name}
126
- aria-label={name}
130
+ aria-label={ariaLabel}
131
+ aria-labelledby={ariaLabelledById}
127
132
  checked={checked}
128
133
  onChange={onChange}
129
134
  tabIndex="-1"
@@ -143,7 +148,6 @@ const Checkbox = ({
143
148
  disabledStyles={themeValues.disabledStyles}
144
149
  disabledCheckedStyles={themeValues.disabledCheckedStyles}
145
150
  focusedStyles={themeValues.focusedStyles}
146
- aria-required={isRequired}
147
151
  >
148
152
  <CheckboxIcon
149
153
  viewBox="0 0 24 24"
@@ -157,6 +161,7 @@ const Checkbox = ({
157
161
  </CheckboxContainer>
158
162
  {title && (
159
163
  <Text
164
+ id={titleId}
160
165
  variant="p"
161
166
  weight={themeValues.textFontWeight}
162
167
  color={themeValues.textColor}
@@ -13,13 +13,13 @@ 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")}
22
+ labelledById={text("labelledById", undefined, "props")}
23
23
  />
24
24
  );
25
25
 
@@ -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
  );
@@ -12,11 +12,11 @@ import styled from "styled-components";
12
12
  import "core-js/proposals/relative-indexing-method";
13
13
 
14
14
  import {
15
- WHITE,
15
+ ERROR_COLOR,
16
16
  GREY_CHATEAU,
17
- STORM_GREY,
18
17
  MINESHAFT_GREY,
19
- ERROR_COLOR
18
+ STORM_GREY,
19
+ WHITE
20
20
  } from "../../../constants/colors";
21
21
  import { fallbackValues } from "./Dropdown.theme";
22
22
  import { themeComponent } from "../../../util/themeUtils";
@@ -55,37 +55,65 @@ const DropdownContentWrapper = styled.div`
55
55
  `;
56
56
 
57
57
  const DropdownItemWrapper = styled.li`
58
- background-color: ${({ selected, themeValues }) =>
59
- selected ? themeValues.selectedColor : WHITE};
60
58
  text-align: start;
61
- border-width: 0px;
62
- border-color: transparent;
59
+ border-width: 2px;
60
+ border-style: solid;
61
+ border-color: ${({ selected, themeValues }) =>
62
+ selected ? themeValues.selectedColor : WHITE};
63
63
  box-shadow: none;
64
- padding: 1rem;
65
64
  box-sizing: border-box;
66
65
  width: 100%;
67
66
  list-style: none;
68
67
  cursor: ${({ disabled }) => (disabled ? "default" : "pointer")};
69
68
 
70
69
  &:hover {
71
- background-color: ${({ selected, disabled, themeValues }) =>
70
+ border-color: ${({ disabled, selected, themeValues }) =>
72
71
  selected
73
- ? themeValues.selectedColor
72
+ ? themeValues.focusColor
74
73
  : disabled
75
74
  ? WHITE
76
75
  : themeValues.hoverColor};
76
+ > * {
77
+ background: ${({ selected, disabled, themeValues }) =>
78
+ selected
79
+ ? themeValues.focusColor
80
+ : disabled
81
+ ? WHITE
82
+ : themeValues.hoverColor};
83
+ border-color: ${({ selected, disabled, themeValues }) =>
84
+ selected
85
+ ? themeValues.focusColor
86
+ : disabled
87
+ ? WHITE
88
+ : themeValues.hoverColor};
89
+ }
77
90
  }
78
91
  &:focus {
79
- background-color: ${({ selected, disabled, themeValues }) =>
80
- selected
81
- ? themeValues.selectedColor
82
- : disabled
83
- ? WHITE
84
- : themeValues.hoverColor};
85
92
  outline: none;
93
+ border-color: ${({ themeValues }) => themeValues.selectedColor};
94
+ > * {
95
+ background: ${({ selected, disabled, themeValues }) =>
96
+ selected
97
+ ? themeValues.focusColor
98
+ : disabled
99
+ ? WHITE
100
+ : themeValues.hoverColor};
101
+ border-color: white;
102
+ outline: none;
103
+ }
86
104
  }
87
105
  `;
88
106
 
107
+ const DropdownItemBorder = styled.div`
108
+ background: ${({ selected, themeValues }) =>
109
+ selected ? themeValues.selectedColor : WHITE};
110
+ border-color: ${({ selected, themeValues }) =>
111
+ selected ? themeValues.selectedColor : WHITE};
112
+ border-width: 2px;
113
+ border-style: solid;
114
+ padding: 12px;
115
+ `;
116
+
89
117
  const Dropdown = ({
90
118
  placeholder,
91
119
  options,
@@ -108,7 +136,6 @@ const Dropdown = ({
108
136
  ariaInvalid = false,
109
137
  isRequired = false
110
138
  }) => {
111
- const required = options.required || isRequired;
112
139
  const [inputValue, setInputValue] = useState("");
113
140
  const [optionsState, setOptionsState] = useState([]);
114
141
  const [filteredOptions, setFilteredOptions] = useState([]);
@@ -236,13 +263,15 @@ const Dropdown = ({
236
263
  useEffect(() => {
237
264
  if (autoEraseTypeAhead) {
238
265
  clearTimeout(timer);
239
- setTimer(setTimeout(() => setInputValue(""), 3000));
266
+ setTimer(setTimeout(() => setInputValue(""), 20000));
240
267
  }
268
+
241
269
  setFilteredOptions(
242
270
  options.filter(
243
271
  option =>
244
- option.value.toLowerCase().startsWith(inputValue.toLowerCase()) ||
245
- option.text.toLowerCase().startsWith(inputValue.toLowerCase())
272
+ option?.value?.toLowerCase()?.indexOf(inputValue?.toLowerCase()) >=
273
+ 0 ||
274
+ option.text?.toLowerCase()?.indexOf(inputValue?.toLowerCase()) >= 0
246
275
  )
247
276
  );
248
277
  }, [inputValue]);
@@ -298,8 +327,7 @@ const Dropdown = ({
298
327
  aria-labelledby={ariaLabelledby}
299
328
  aria-describedby={ariaDescribedby}
300
329
  aria-expanded={isOpen}
301
- aria-required={required}
302
- required={required}
330
+ aria-required={options.required}
303
331
  aria-invalid={ariaInvalid}
304
332
  background={isOpen ? themeValues.hoverColor : WHITE}
305
333
  borderRadius="2px"
@@ -331,6 +359,7 @@ const Dropdown = ({
331
359
  }}
332
360
  padding="12px"
333
361
  placeholder={getSelection()}
362
+ required={options.required || isRequired}
334
363
  role="combobox"
335
364
  themeValues={themeValues}
336
365
  title={hasTitles ? getSelection() : null}
@@ -338,7 +367,6 @@ const Dropdown = ({
338
367
  tabIndex={0}
339
368
  value={inputValue}
340
369
  width="100%"
341
- disabled={disabledValues.includes(inputValue)}
342
370
  />
343
371
  <IconWrapper open={isOpen} onClick={onClick}>
344
372
  <DropdownIcon />
@@ -353,7 +381,6 @@ const Dropdown = ({
353
381
  tabIndex={0}
354
382
  role="listbox"
355
383
  id={`${ariaLabelledby}_listbox`}
356
- required={required}
357
384
  >
358
385
  <Stack childGap="0" as="ul">
359
386
  {filteredOptions.map((choice, i) => {
@@ -389,27 +416,33 @@ const Dropdown = ({
389
416
  role="option"
390
417
  onFocus={() => setFocusedRef(optionRefs.current[i])}
391
418
  >
392
- <Text
393
- variant="p"
394
- color={
395
- choice.value === value
396
- ? WHITE
397
- : disabledValues.includes(choice.value)
398
- ? STORM_GREY
399
- : MINESHAFT_GREY
400
- }
401
- extraStyles={`padding-left: 16px;
402
- cursor: ${
403
- disabledValues.includes(choice.value)
404
- ? "default"
405
- : "pointer"
406
- };
407
- white-space: nowrap;
408
- overflow: hidden;
409
- text-overflow: ellipsis;`}
419
+ <DropdownItemBorder
420
+ disabled={disabledValues.includes(choice.value)}
421
+ selected={choice.value === value}
422
+ themeValues={themeValues}
410
423
  >
411
- {choice.text}
412
- </Text>
424
+ <Text
425
+ variant="p"
426
+ color={
427
+ choice.value === value
428
+ ? WHITE
429
+ : disabledValues.includes(choice.value)
430
+ ? STORM_GREY
431
+ : MINESHAFT_GREY
432
+ }
433
+ extraStyles={`padding-left: 16px;
434
+ cursor: ${
435
+ disabledValues.includes(choice.value)
436
+ ? "default"
437
+ : "pointer"
438
+ };
439
+ white-space: nowrap;
440
+ overflow: hidden;
441
+ text-overflow: ellipsis;`}
442
+ >
443
+ {choice.text}
444
+ </Text>
445
+ </DropdownItemBorder>
413
446
  </DropdownItemWrapper>
414
447
  );
415
448
  })}
@@ -1,9 +1,15 @@
1
- import { HOVER_LIGHT_BLUE, MATISSE_BLUE } from "../../../constants/colors";
1
+ import {
2
+ HOVER_LIGHT_BLUE,
3
+ MATISSE_BLUE,
4
+ MATISSE_BLUE_DARK
5
+ } from "../../../constants/colors";
2
6
 
3
7
  const selectedColor = `${MATISSE_BLUE}`;
4
8
  const hoverColor = `${HOVER_LIGHT_BLUE}`;
9
+ const focusColor = `${MATISSE_BLUE_DARK}`;
5
10
 
6
11
  export const fallbackValues = {
7
12
  selectedColor,
8
- hoverColor
13
+ hoverColor,
14
+ focusColor
9
15
  };
@@ -119,7 +119,6 @@ const FormInput = ({
119
119
  isRequired = false,
120
120
  ...props
121
121
  }) => {
122
- const required = isRequired || props?.required;
123
122
  const [showPassword, setShowPassword] = useState(false);
124
123
  const { isMobile } = useContext(ThemeContext);
125
124
  const setValue = value => {
@@ -223,7 +222,7 @@ const FormInput = ({
223
222
  $extraStyles={extraStyles}
224
223
  data-qa={dataQa || labelTextWhenNoError}
225
224
  autoComplete={autocompleteValue}
226
- required={required}
225
+ required={isRequired}
227
226
  {...props}
228
227
  />
229
228
  ) : (
@@ -250,7 +249,7 @@ const FormInput = ({
250
249
  $extraStyles={extraStyles}
251
250
  data-qa={dataQa || labelTextWhenNoError}
252
251
  autoComplete={autocompleteValue}
253
- required={required}
252
+ required={isRequired}
254
253
  {...props}
255
254
  />
256
255
  )}
@@ -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,29 +95,31 @@ 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
- <Text
113
- color={ERROR_COLOR}
114
- variant="pXS"
115
- weight={themeValues.fontWeight}
116
- extraStyles={`
101
+ {(field.hasErrors && field.dirty) || (field.hasErrors && showErrors) ? (
102
+ <Text
103
+ color={ERROR_COLOR}
104
+ variant="pXS"
105
+ weight={themeValues.fontWeight}
106
+ extraStyles={`
117
107
  word-break: break-word;
118
108
  font-family: Public Sans;
119
109
  &::first-letter {
120
110
  text-transform: uppercase;
121
111
  }
122
112
  `}
123
- id={createIdFromString(labelTextWhenNoError, "error message")}
124
- aria-live="polite"
125
- aria-atomic={true}
126
- data-qa={createIdFromString(labelTextWhenNoError, "error message")}
127
- >
128
- {(field.hasErrors && field.dirty) || (field.hasErrors && showErrors)
129
- ? errorMessages[field.errors[0]]
130
- : ""}
131
- </Text>
113
+ id={createIdFromString(labelTextWhenNoError, "error message")}
114
+ aria-live="polite"
115
+ aria-atomic={true}
116
+ data-qa={createIdFromString(labelTextWhenNoError, "error message")}
117
+ >
118
+ {errorMessages[field.errors[0]]}
119
+ </Text>
120
+ ) : (
121
+ <Text extraStyles={`height: ${themeValues.lineHeight};`} />
122
+ )}
132
123
  </Stack>
133
124
  </SelectContainer>
134
125
  );
@@ -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}
@@ -7,6 +7,8 @@ const AccountNumberImage = () => {
7
7
  width="371"
8
8
  height="164"
9
9
  viewBox="0 0 371 164"
10
+ role="img"
11
+ aria-label="A check with the account number highlighted in the bottom center"
10
12
  >
11
13
  <g fill="none" fillRule="evenodd" stroke="none" strokeWidth="1">
12
14
  <g transform="translate(-364 -546)">
@@ -8,6 +8,8 @@ export const BankIcon = () => {
8
8
  viewBox="0 0 28 18"
9
9
  fill="none"
10
10
  xmlns="http://www.w3.org/2000/svg"
11
+ role="img"
12
+ aria-label="Check Payment"
11
13
  >
12
14
  <path
13
15
  d="M0 2.25C0 1.00736 1.04467 0 2.33333 0H25.6667C26.9553 0 28 1.00736 28 2.25V15.75C28 16.9926 26.9553 18 25.6667 18H2.33333C1.04467 18 0 16.9926 0 15.75V2.25Z"