@thecb/components 9.0.0-beta.1 → 9.0.0-beta.11

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 (27) hide show
  1. package/dist/index.cjs.js +132 -97
  2. package/dist/index.cjs.js.map +1 -1
  3. package/dist/index.d.ts +4 -4
  4. package/dist/index.esm.js +132 -97
  5. package/dist/index.esm.js.map +1 -1
  6. package/package.json +1 -1
  7. package/src/components/atoms/checkbox/Checkbox.js +3 -1
  8. package/src/components/atoms/country-dropdown/CountryDropdown.js +3 -3
  9. package/src/components/atoms/country-dropdown/CountryDropdown.stories.js +0 -1
  10. package/src/components/atoms/display-box/DisplayBox.js +1 -6
  11. package/src/components/atoms/dropdown/Dropdown.js +14 -15
  12. package/src/components/atoms/form-layouts/FormInput.js +2 -3
  13. package/src/components/atoms/form-layouts/index.d.ts +2 -2
  14. package/src/components/atoms/form-select/FormSelect.js +10 -5
  15. package/src/components/atoms/form-select/index.d.ts +2 -2
  16. package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.js +1 -4
  17. package/src/components/molecules/account-and-routing-modal/AccountAndRoutingModal.js +1 -2
  18. package/src/components/molecules/address-form/AddressForm.js +10 -3
  19. package/src/components/molecules/modal/Modal.js +1 -1
  20. package/src/components/molecules/payment-details/PaymentDetails.js +36 -16
  21. package/src/components/molecules/payment-form-card/PaymentFormCard.js +1 -1
  22. package/src/components/molecules/phone-form/PhoneForm.js +2 -0
  23. package/src/components/molecules/registration-form/RegistrationForm.js +5 -0
  24. package/src/components/molecules/terms-and-conditions/TermsAndConditionsControlV1.js +2 -4
  25. package/src/components/molecules/terms-and-conditions/TermsAndConditionsControlV2.js +1 -3
  26. package/src/components/atoms/dropdown/index.d.ts +0 -32
  27. package/src/components/atoms/state-province-dropdown/index.d.ts +0 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thecb/components",
3
- "version": "9.0.0-beta.1",
3
+ "version": "9.0.0-beta.11",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
@@ -95,7 +95,7 @@ const Checkbox = ({
95
95
  checkboxMargin = "0 16px 0 0",
96
96
  extraStyles,
97
97
  textExtraStyles,
98
- dataQa = "Checkbox Label"
98
+ dataQa = null
99
99
  }) => {
100
100
  const [focused, setFocused] = useState(false);
101
101
 
@@ -130,9 +130,11 @@ const Checkbox = ({
130
130
  aria-describedby={error ? `${name}-error-message` : ""}
131
131
  />
132
132
  <StyledCheckbox
133
+ role="checkbox"
133
134
  error={error}
134
135
  disabled={disabled}
135
136
  checked={checked}
137
+ aria-checked={checked}
136
138
  focused={focused}
137
139
  defaultStyles={themeValues.defaultStyles}
138
140
  checkedStyles={themeValues.checkedStyles}
@@ -4,20 +4,20 @@ import FormSelect from "../form-select";
4
4
  import { options } from "./options";
5
5
 
6
6
  const CountryDropdown = ({
7
- labelTextWhenNoError,
7
+ labelTextWhenNoError = "Country",
8
8
  errorMessages,
9
9
  field,
10
10
  fieldActions,
11
11
  showErrors,
12
12
  onChange,
13
- dataQa = "Country Dropdown"
13
+ dataQa = null
14
14
  }) => (
15
15
  <FormSelect
16
16
  options={options}
17
17
  field={field}
18
18
  fieldActions={fieldActions}
19
19
  labelTextWhenNoError={labelTextWhenNoError}
20
- dataQa={dataQa}
20
+ dataQa={dataQa || "CountryDropdown"}
21
21
  errorMessages={errorMessages}
22
22
  showErrors={showErrors}
23
23
  onChange={onChange}
@@ -26,7 +26,6 @@ const story = page({
26
26
  const CountryFormWrapper = ({ fields, actions }) => (
27
27
  <Box minHeight="300px">
28
28
  <CountryDropdown
29
- labelTextWhenNoError="Country"
30
29
  errorMessages={errorMessages}
31
30
  options={options}
32
31
  field={fields.country}
@@ -4,12 +4,7 @@ import { fallbackValues } from "./DisplayBox.theme";
4
4
  import { themeComponent } from "../../../util/themeUtils";
5
5
  import { RED } from "../../../constants/colors";
6
6
 
7
- const DisplayBox = ({
8
- children,
9
- themeValues,
10
- showError,
11
- dataQa = "DisplayBox"
12
- }) => (
7
+ const DisplayBox = ({ children, themeValues, showError, dataQa = null }) => (
13
8
  <Box padding="0.5rem 0 1.5rem 0">
14
9
  <Box
15
10
  padding="1.5rem"
@@ -3,7 +3,6 @@ import { Box, Stack } from "../layouts";
3
3
  import Text from "../text";
4
4
  import {
5
5
  noop,
6
- createIdFromString,
7
6
  inputDisabledStyle,
8
7
  inputPlaceholderTextStyle
9
8
  } from "../../../util/general";
@@ -290,13 +289,15 @@ const Dropdown = ({
290
289
  as="input"
291
290
  aria-multiline="false"
292
291
  autoComplete={autocompleteValue}
293
- aria-controls={`${createIdFromString(ariaLabelledby)}_listbox`}
292
+ aria-controls={`${ariaLabelledby}_listbox`}
294
293
  aria-activedescendant="focused_option"
295
294
  aria-owns={`${ariaLabelledby}_listbox`}
296
295
  aria-haspopup="listbox"
297
296
  aria-labelledby={ariaLabelledby}
298
297
  aria-describedby={ariaDescribedby}
299
298
  aria-expanded={isOpen}
299
+ aria-required={options.required}
300
+ aria-invalid={ariaInvalid}
300
301
  background={isOpen ? themeValues.hoverColor : WHITE}
301
302
  borderRadius="2px"
302
303
  borderSize="1px"
@@ -307,6 +308,7 @@ const Dropdown = ({
307
308
  ? themeValues.selectedColor
308
309
  : GREY_CHATEAU
309
310
  }
311
+ dataQa={placeholder}
310
312
  extraStyles={
311
313
  disabled
312
314
  ? `${inputPlaceholderTextStyle}${inputDisabledStyle}`
@@ -326,6 +328,7 @@ const Dropdown = ({
326
328
  }}
327
329
  padding="12px"
328
330
  placeholder={getSelection()}
331
+ required={options.required}
329
332
  role="combobox"
330
333
  themeValues={themeValues}
331
334
  title={hasTitles ? getSelection() : null}
@@ -333,10 +336,6 @@ const Dropdown = ({
333
336
  tabIndex={0}
334
337
  value={inputValue}
335
338
  width="100%"
336
- dataQa={placeholder}
337
- required={options.required}
338
- aria-required={options.required}
339
- aria-invalid={ariaInvalid}
340
339
  />
341
340
  <IconWrapper open={isOpen} onClick={onClick}>
342
341
  <DropdownIcon />
@@ -383,8 +382,8 @@ const Dropdown = ({
383
382
  data-qa={choice.text}
384
383
  themeValues={themeValues}
385
384
  title={hasTitles ? choice.text : null}
386
- onFocus={() => setFocusedRef(optionRefs.current[i])}
387
385
  role="option"
386
+ onFocus={() => setFocusedRef(optionRefs.current[i])}
388
387
  >
389
388
  <Text
390
389
  variant="p"
@@ -396,14 +395,14 @@ const Dropdown = ({
396
395
  : MINESHAFT_GREY
397
396
  }
398
397
  extraStyles={`padding-left: 16px;
399
- cursor: ${
400
- disabledValues.includes(choice.value)
401
- ? "default"
402
- : "pointer"
403
- };
404
- white-space: nowrap;
405
- overflow: hidden;
406
- text-overflow: ellipsis;`}
398
+ cursor: ${
399
+ disabledValues.includes(choice.value)
400
+ ? "default"
401
+ : "pointer"
402
+ };
403
+ white-space: nowrap;
404
+ overflow: hidden;
405
+ text-overflow: ellipsis;`}
407
406
  >
408
407
  {choice.text}
409
408
  </Text>
@@ -112,10 +112,10 @@ const FormInput = ({
112
112
  themeValues,
113
113
  background,
114
114
  customHeight,
115
- autocompleteValue = "",
115
+ autocompleteValue = null,
116
116
  extraStyles,
117
117
  removeFromValue, // regex of characters to remove before setting value
118
- dataQa,
118
+ dataQa = null,
119
119
  ...props
120
120
  }) => {
121
121
  const [showPassword, setShowPassword] = useState(false);
@@ -256,7 +256,6 @@ const FormInput = ({
256
256
  justify="space-between"
257
257
  aria-live="polite"
258
258
  aria-atomic={true}
259
- data-qa={`${labelTextWhenNoError} error message`}
260
259
  >
261
260
  {(field.hasErrors && field.dirty) || (field.hasErrors && showErrors) ? (
262
261
  <Text
@@ -23,9 +23,9 @@ export interface FormInputProps {
23
23
  themeValues?: object;
24
24
  background?: string;
25
25
  customHeight?: string;
26
- autocompleteValue?: string;
26
+ autocompleteValue?: string | null;
27
27
  removeFromValue?: RegExp;
28
- dataQa?: string;
28
+ dataQa?: string | null;
29
29
  }
30
30
 
31
31
  export const FormInput: React.FC<Expand<FormInputProps> &
@@ -21,9 +21,9 @@ const FormSelect = ({
21
21
  disabled,
22
22
  themeValues,
23
23
  hasTitles = false,
24
- autocompleteValue = "", // browser autofill value, like country-name or address-level1 for state
24
+ autocompleteValue = null, // browser autofill value, like country-name
25
25
  smoothScroll = true, // whether the browser should animate scroll to selected item on first open
26
- dataQa = "FormSelect"
26
+ dataQa = null
27
27
  }) => {
28
28
  const [open, setOpen] = useState(false);
29
29
  const dropdownRef = useRef(null);
@@ -42,7 +42,12 @@ const FormSelect = ({
42
42
  });
43
43
 
44
44
  return (
45
- <SelectContainer ref={dropdownRef} disabled={disabled} data-qa={dataQa}>
45
+ <SelectContainer
46
+ ref={dropdownRef}
47
+ disabled={disabled}
48
+ aria-disabled={disabled}
49
+ data-qa={dataQa}
50
+ >
46
51
  <Box padding="0" minWidth="100%">
47
52
  <Cluster justify="space-between" align="center">
48
53
  <Text
@@ -62,8 +67,8 @@ const FormSelect = ({
62
67
  </Cluster>
63
68
  </Box>
64
69
  <Dropdown
65
- ariaLabelledby={labelTextWhenNoError}
66
- ariaDescribedBy={createIdFromString(
70
+ ariaLabelledby={createIdFromString(labelTextWhenNoError)}
71
+ ariaDescribedby={createIdFromString(
67
72
  labelTextWhenNoError,
68
73
  "error message"
69
74
  )}
@@ -20,9 +20,9 @@ export interface FormSelectProps {
20
20
  disabledValues?: string[];
21
21
  themeValues?: object;
22
22
  hasTitles?: boolean;
23
- autocompleteValue?: string;
23
+ autocompleteValue?: string | null;
24
24
  smoothScroll?: boolean;
25
- dataQa?: string;
25
+ dataQa?: string | null;
26
26
  }
27
27
 
28
28
  export const FormSelect: React.FC<Expand<FormSelectProps> &
@@ -10,8 +10,7 @@ const FormStateDropdown = ({
10
10
  fieldActions,
11
11
  showErrors,
12
12
  countryCode,
13
- autocompleteValue = "administrative-area",
14
- dataQa = "StateProvinceDropdown"
13
+ autocompleteValue = null
15
14
  }) => {
16
15
  const placeholder =
17
16
  countryCode === "US" ? placeHolderOptionUS : placeHolderOption;
@@ -24,9 +23,7 @@ const FormStateDropdown = ({
24
23
  labelTextWhenNoError={labelTextWhenNoError}
25
24
  errorMessages={errorMessages}
26
25
  showErrors={showErrors}
27
- aria-invalid={!!errorMessages?.length}
28
26
  autocompleteValue={autocompleteValue}
29
- dataQa={dataQa}
30
27
  />
31
28
  );
32
29
  };
@@ -17,7 +17,7 @@ const AccountAndRoutingModal = ({
17
17
  content,
18
18
  imageType,
19
19
  themeValues,
20
- dataQa = "AccountAndRoutingModal"
20
+ dataQa = null
21
21
  }) => (
22
22
  <Modal
23
23
  modalOpen={isOpen}
@@ -52,7 +52,6 @@ const AccountAndRoutingModal = ({
52
52
  }}
53
53
  >
54
54
  <Text
55
- role="button"
56
55
  variant="pS"
57
56
  onClick={() => toggleOpen(true)}
58
57
  onKeyPress={e => e.key === "Enter" && toggleOpen(true)}
@@ -3,6 +3,7 @@ import { required, hasLength } from "redux-freeform";
3
3
  import StateProvinceDropdown from "../../atoms/state-province-dropdown";
4
4
  import Checkbox from "../../atoms/checkbox";
5
5
  import CountryDropdown from "../../atoms/country-dropdown";
6
+ import { noop } from "../../../util/general";
6
7
  import { zipFormat } from "../../../util/formats";
7
8
  import {
8
9
  FormInput,
@@ -19,7 +20,8 @@ const AddressForm = ({
19
20
  handleSubmit = noop,
20
21
  showWalletCheckbox,
21
22
  saveToWallet,
22
- walletCheckboxMarked
23
+ walletCheckboxMarked,
24
+ dataQa = null
23
25
  }) => {
24
26
  if (clearOnDismount) {
25
27
  useEffect(() => () => actions.form.clear(), []);
@@ -45,7 +47,12 @@ const AddressForm = ({
45
47
  const isUS = fields.country.rawValue === "US";
46
48
 
47
49
  return (
48
- <FormContainer variant={variant} role="form" aria-label="Address">
50
+ <FormContainer
51
+ variant={variant}
52
+ role="form"
53
+ aria-label="Address"
54
+ dataQa={dataQa}
55
+ >
49
56
  <FormInputColumn>
50
57
  <CountryDropdown
51
58
  labelTextWhenNoError="Country"
@@ -73,7 +80,7 @@ const AddressForm = ({
73
80
  showErrors={showErrors}
74
81
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
75
82
  autocompleteValue="address-line1"
76
- dataQa="Address Line 1"
83
+ dataQa="Address"
77
84
  />
78
85
  <FormInput
79
86
  labelTextWhenNoError="Apt, Suite, Unit, Floor, etc. (Optional)"
@@ -45,7 +45,7 @@ const Modal = ({
45
45
  isLoading,
46
46
  buttonExtraStyles,
47
47
  children,
48
- dataQa = ""
48
+ dataQa = null
49
49
  }) => {
50
50
  const { isMobile } = useContext(ThemeContext);
51
51
  const modalContainerRef = useRef(null);
@@ -13,6 +13,7 @@ import { displayCurrency } from "../../../util/general";
13
13
  import { themeComponent } from "../../../util/themeUtils";
14
14
  import CollapsibleSection from "../collapsible-section";
15
15
 
16
+ import LoadingLine from "../../atoms/loading-line";
16
17
  import LabeledAmount from "../../atoms/labeled-amount";
17
18
  import LineItem from "../../atoms/line-item";
18
19
  import Title from "../../atoms/title";
@@ -120,22 +121,41 @@ const PaymentDetailsContent = ({
120
121
  );
121
122
 
122
123
  const LoadingDetails = () => (
123
- <Box
124
- padding="0"
125
- background={GRECIAN_GREY}
126
- borderRadius="4px"
127
- minHeight="196px"
128
- >
129
- <Cover minHeight="196px" singleChild fillCenter>
130
- <Center intrinsic>
131
- <Box
132
- padding="0"
133
- extraStyles={`flex-grow: 1; display: flex; justify-content: center; align-items: center;`}
134
- >
135
- <Spinner size="100" centerSpinner />
136
- </Box>
137
- </Center>
138
- </Cover>
124
+ <Box padding="0" minHeight="196px">
125
+ <Box
126
+ padding="0"
127
+ extraStyles={`position: absolute;
128
+ height: 200px;
129
+ width: 100%;
130
+ display: flex;
131
+ justify-content: center;
132
+ align-items: center;`}
133
+ >
134
+ <Spinner size="100" centerSpinner />
135
+ </Box>
136
+ <Stack childGap="16px">
137
+ <Cluster nowrap justify="space-between" align="start">
138
+ <LoadingLine exactWidth="110" height="27px" />
139
+ <LoadingLine exactWidth="60" height="27px" />
140
+ </Cluster>
141
+ <SolidDivider />
142
+ <Box padding="0.5rem 0">
143
+ <Cluster justify="space-between" align="start">
144
+ <LoadingLine exactWidth="80" height="27px" />
145
+ <LoadingLine exactWidth="60" height="27px" />
146
+ </Cluster>
147
+ <Box padding="4px 0" />
148
+ <Cluster justify="space-between" align="start">
149
+ <LoadingLine exactWidth="100" height="27px" />
150
+ <LoadingLine exactWidth="50" height="27px" />
151
+ </Cluster>
152
+ </Box>
153
+ <SolidDivider />
154
+ <Stack justify="space-between" direction="row">
155
+ <LoadingLine exactWidth="55" height="30px" />
156
+ <LoadingLine exactWidth="70" height="30px" />
157
+ </Stack>
158
+ </Stack>
139
159
  </Box>
140
160
  );
141
161
 
@@ -140,7 +140,7 @@ const PaymentFormCard = ({
140
140
  >
141
141
  <FormInput
142
142
  labelTextWhenNoError="Expiration date (MM/YY)"
143
- dataQa="Expiration date"
143
+ dataQa="Expiration date (MM/YY)"
144
144
  errorMessages={expirationDateErrors}
145
145
  field={fields.expirationDate}
146
146
  fieldActions={actions.fields.expirationDate}
@@ -6,6 +6,7 @@ import {
6
6
  FormContainer,
7
7
  FormInputColumn
8
8
  } from "../../atoms/form-layouts";
9
+ import { noop } from "../../../util/general";
9
10
  import Checkbox from "../../atoms/checkbox";
10
11
  import { phoneFormats, formatDelimiter } from "../../../util/formats";
11
12
 
@@ -41,6 +42,7 @@ const PhoneForm = ({
41
42
  onKeyUp={e => e.key === "Enter" && handleSubmit(e)}
42
43
  autocompleteValue="tel"
43
44
  dataQa="Phone number"
45
+ isNum={true}
44
46
  />
45
47
  {showWalletCheckbox && (
46
48
  <Checkbox
@@ -60,6 +60,7 @@ const RegistrationForm = ({
60
60
  showErrors={showErrors}
61
61
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
62
62
  autocompleteValue="given-name"
63
+ dataQa="First name"
63
64
  />
64
65
  <FormInput
65
66
  labelTextWhenNoError="Last name"
@@ -69,6 +70,7 @@ const RegistrationForm = ({
69
70
  showErrors={showErrors}
70
71
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
71
72
  autocompleteValue="family-name"
73
+ dataQa="Last name"
72
74
  />
73
75
  <FormInput
74
76
  labelTextWhenNoError="Email address"
@@ -80,6 +82,7 @@ const RegistrationForm = ({
80
82
  type="email"
81
83
  isEmail
82
84
  autocompleteValue="email"
85
+ dataQa="Email address"
83
86
  />
84
87
  <FormInput
85
88
  labelTextWhenNoError="Password"
@@ -90,6 +93,7 @@ const RegistrationForm = ({
90
93
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
91
94
  type="password"
92
95
  autocompleteValue="new-password"
96
+ dataQa="Password"
93
97
  />
94
98
  <FormInput
95
99
  labelTextWhenNoError="Confirm password"
@@ -100,6 +104,7 @@ const RegistrationForm = ({
100
104
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
101
105
  type="password"
102
106
  autocompleteValue="new-password"
107
+ dataQa="Confirm password"
103
108
  />
104
109
  <Box padding={isMobile ? "0" : "0.5rem 0 0"}>
105
110
  <PasswordRequirements password={fields.password} isMobile={isMobile} />
@@ -10,17 +10,15 @@ const TermsAndConditionsControlV1 = ({
10
10
  html,
11
11
  terms,
12
12
  error = false,
13
- linkVariant,
14
- dataQa = "TermsAndConditionsControlV1"
13
+ linkVariant
15
14
  }) => {
16
15
  const [showTerms, toggleShowTerms] = useState(false);
17
16
  return (
18
- <DisplayBox dataQ={dataQa}>
17
+ <DisplayBox>
19
18
  <Stack>
20
19
  <Checkbox
21
20
  name="terms"
22
21
  title="Terms and Conditions"
23
- dataQa="Terms and Conditions"
24
22
  error={error}
25
23
  checked={isChecked}
26
24
  onChange={onCheck}
@@ -26,8 +26,7 @@ const TermsAndConditionsControlV2 = ({
26
26
  modalVariant = "default",
27
27
  containerBackground = ATHENS_GREY,
28
28
  checkboxMargin = "4px 8px 4px 4px",
29
- modalTitle = "Terms and Conditions",
30
- dataQa = "TermsAndConditionsControlV2"
29
+ modalTitle = "Terms and Conditions"
31
30
  }) => {
32
31
  const [showTerms, toggleShowTerms] = useState(false);
33
32
  const standardBoxShadow = generateShadows().standard.base;
@@ -46,7 +45,6 @@ const TermsAndConditionsControlV2 = ({
46
45
  background={displayInline ? "transparent" : containerBackground}
47
46
  boxShadow={displayInline ? "none" : standardBoxShadow}
48
47
  borderRadius={displayInline ? "0" : "4px"}
49
- dataQa={dataQa}
50
48
  >
51
49
  <Stack childGap="0">
52
50
  {html && <Box padding="0">{html}</Box>}
@@ -1,32 +0,0 @@
1
- import React from "react";
2
- import Expand from "../../../util/expand";
3
-
4
- export interface DropdownOption {
5
- text: string;
6
- value: string;
7
- }
8
-
9
- export interface DropdownProps {
10
- placeholder?: string;
11
- options?: DropdownOption[];
12
- value?: string;
13
- isOpen?: boolean;
14
- isError?: boolean;
15
- onSelect?: (event: React.SyntheticEvent<HTMLElement>) => void;
16
- disabledValues?: string[];
17
- onClick?: (event: React.MouseEvent<HTMLElement>) => void;
18
- themeValues?: object;
19
- maxHeight?: string;
20
- widthFitOptions?: boolean;
21
- disabled?: boolean;
22
- hasTitles?: boolean;
23
- autoEraseTypeAhead?: true;
24
- ariaLabelledby?: string;
25
- ariaDescribedby?: string;
26
- autocompleteValue?: string;
27
- smoothScroll?: boolean;
28
- ariaInvalid?: boolean;
29
- }
30
-
31
- export const Dropdown: React.FC<Expand<DropdownProps> &
32
- React.HTMLAttributes<HTMLElement>>;
@@ -1,26 +0,0 @@
1
- import React from "react";
2
-
3
- import {
4
- ErrorMessageDictionary,
5
- Field,
6
- FieldActions,
7
- FormSelectOption
8
- } from "../../../types/common";
9
- import Expand from "../../../util/expand";
10
-
11
- export interface StateProvinceDropdownProps {
12
- labelTextWhenNoError?: string;
13
- errorMessages?: ErrorMessageDictionary;
14
- field?: Field;
15
- fieldActions?: FieldActions;
16
- options?: FormSelectOption[];
17
- showErrors?: boolean;
18
- countryCode?: string;
19
- autocompleteValue?: string;
20
- dataQa?: string;
21
- }
22
-
23
- export const StateProvinceDropdown: React.FC<Expand<
24
- StateProvinceDropdownProps
25
- > &
26
- React.HTMLAttributes<HTMLElement>>;