@magento/venia-ui 10.2.0-beta.2 → 10.3.0-alpha.1

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 (36) hide show
  1. package/i18n/en_US.json +4 -0
  2. package/lib/components/AccountChip/__tests__/__snapshots__/accountChip.spec.js.snap +1 -1
  3. package/lib/components/AccountChip/accountChip.js +7 -4
  4. package/lib/components/AccountInformationPage/__tests__/__snapshots__/accountInformationPage.spec.js.snap +2 -2
  5. package/lib/components/AccountInformationPage/accountInformationPage.js +2 -2
  6. package/lib/components/AccountMenu/accountMenu.js +6 -1
  7. package/lib/components/AddressBookPage/__tests__/__snapshots__/addressBookPage.spec.js.snap +18 -6
  8. package/lib/components/AddressBookPage/addressBookPage.js +12 -2
  9. package/lib/components/CartPage/ProductListing/EditModal/productForm.js +1 -0
  10. package/lib/components/CheckoutPage/ShippingInformation/AddressForm/__tests__/__snapshots__/customerForm.spec.js.snap +3 -3
  11. package/lib/components/CheckoutPage/ShippingInformation/AddressForm/__tests__/__snapshots__/guestForm.spec.js.snap +4 -4
  12. package/lib/components/CheckoutPage/ShippingInformation/AddressForm/customerForm.js +27 -1
  13. package/lib/components/CheckoutPage/ShippingInformation/AddressForm/customerForm.module.css +5 -0
  14. package/lib/components/CheckoutPage/ShippingInformation/AddressForm/guestForm.js +20 -1
  15. package/lib/components/CheckoutPage/ShippingInformation/AddressForm/guestForm.module.css +5 -0
  16. package/lib/components/CommunicationsPage/__tests__/__snapshots__/communicationsPage.spec.js.snap +8 -8
  17. package/lib/components/CommunicationsPage/communicationsPage.js +2 -2
  18. package/lib/components/FilterModal/FilterList/__tests__/filterDefault.spec.js +16 -1
  19. package/lib/components/FilterModal/FilterList/filterDefault.js +13 -1
  20. package/lib/components/FilterModal/FilterList/filterItem.js +1 -0
  21. package/lib/components/Header/__tests__/__snapshots__/accountTrigger.spec.js.snap +1 -0
  22. package/lib/components/Header/__tests__/__snapshots__/cartTrigger.spec.js.snap +4 -16
  23. package/lib/components/Header/accountTrigger.js +1 -0
  24. package/lib/components/MegaMenu/submenu.module.css +1 -1
  25. package/lib/components/OrderHistoryPage/__tests__/__snapshots__/orderHistoryPage.spec.js.snap +30 -10
  26. package/lib/components/OrderHistoryPage/orderHistoryPage.js +13 -2
  27. package/lib/components/Region/region.js +8 -1
  28. package/lib/components/SavedPaymentsPage/__tests__/__snapshots__/savedPaymentsPage.spec.js.snap +12 -4
  29. package/lib/components/SavedPaymentsPage/savedPaymentsPage.js +20 -2
  30. package/lib/components/Select/select.js +3 -1
  31. package/lib/components/SignIn/signIn.js +2 -0
  32. package/lib/components/TextInput/textInput.js +3 -1
  33. package/lib/components/WishlistPage/__tests__/__snapshots__/wishlistPage.spec.js.snap +45 -15
  34. package/lib/components/WishlistPage/__tests__/wishlistPage.spec.js +8 -5
  35. package/lib/components/WishlistPage/wishlistPage.js +11 -2
  36. package/package.json +4 -4
package/i18n/en_US.json CHANGED
@@ -27,6 +27,7 @@
27
27
  "addressBookPage.addressBookText": "Address Book",
28
28
  "addressBookPage.editDialogTitle": "Edit Address",
29
29
  "addressBookPage.makeDefaultAddress": "Make this my default address",
30
+ "addressBookPage.addAddressMessage": "You have added {count} address in your address book.",
30
31
  "addressBookPage.telephone": "Phone {telephone}",
31
32
  "addressCard.defaultText": "Default",
32
33
  "addToCartButton.addItemToCart": "ADD TO CART",
@@ -309,6 +310,7 @@
309
310
  "orderHistoryPage.loadMore": "Load More",
310
311
  "orderHistoryPage.pageInfo": "Showing {current} of {total}",
311
312
  "orderHistoryPage.pageTitleText": "Order History",
313
+ "orderHistoryPage.ordersCount": "You have {count} orders in your history",
312
314
  "orderHistoryPage.search": "Search by Order Number",
313
315
  "orderItems.itemsHeading": "Items",
314
316
  "orderProgressBar.deliveredText": "Delivered",
@@ -393,6 +395,7 @@
393
395
  "savedPaymentsPage.addButtonText": "Add a credit card",
394
396
  "savedPaymentsPage.creditCard.errorRemoving": "Something went wrong deleting this payment method. Please refresh and try again.",
395
397
  "savedPaymentsPage.noSavedPayments": "You have no saved payments.",
398
+ "savedPaymentsPage.Message": "You have {count} saved payments.",
396
399
  "savedPaymentsPage.title": "Saved Payments",
397
400
  "searchBar.heading": "Product Suggestions",
398
401
  "searchBar.label": " in {label}",
@@ -480,6 +483,7 @@
480
483
  "wishlistPage.headingText": "{count, plural, one {Favorites List} other {Favorites Lists}}",
481
484
  "wishlistPage.wishlistDisabledMessage": "The wishlist is not currently available.",
482
485
  "wishlist.itemCountOpen": "Showing {currentCount} of {count} items in this list",
486
+ "wishlist.itemsMessage": "You have {count} items in your wishlist",
483
487
  "wishlist.itemCountClosed": "You have {count} {count, plural, one {item} other {items}} in this list",
484
488
  "wishlist.loadMore": "Load More",
485
489
  "LegacyMiniCart.buttonExpanded":"More Options Expanded",
@@ -31,7 +31,7 @@ exports[`it renders a loading indicator when appropriate 1`] = `
31
31
  </span>
32
32
  <span
33
33
  aria-atomic="true"
34
- aria-label="Toggle My Account Menu"
34
+ aria-label="Hiundefined"
35
35
  aria-live="polite"
36
36
  className="text"
37
37
  >
@@ -35,10 +35,13 @@ const AccountChip = props => {
35
35
  const classes = useStyle(defaultClasses, props.classes);
36
36
  const { formatMessage } = useIntl();
37
37
 
38
- const ariaLabelMyMenu = formatMessage({
39
- id: 'accountTrigger.ariaLabelMyMenu',
40
- defaultMessage: 'Toggle My Account Menu'
41
- });
38
+ const ariaLabelMyMenu =
39
+ currentUser != null
40
+ ? formatMessage({
41
+ id: 'Hi' + currentUser.firstname,
42
+ defaultMessage: 'Hi' + currentUser.firstname
43
+ })
44
+ : '';
42
45
 
43
46
  const ariaLabel = isUserSignedIn ? ariaLabelMyMenu : '';
44
47
 
@@ -5,7 +5,7 @@ exports[`renders form error 1`] = `
5
5
  className="root"
6
6
  >
7
7
  Account Information
8
- <h1
8
+ <div
9
9
  aria-live="polite"
10
10
  className="title"
11
11
  >
@@ -13,7 +13,7 @@ exports[`renders form error 1`] = `
13
13
  defaultMessage="Account Information"
14
14
  id="accountInformationPage.accountInformation"
15
15
  />
16
- </h1>
16
+ </div>
17
17
  <p
18
18
  className="root"
19
19
  >
@@ -126,7 +126,7 @@ const AccountInformationPage = props => {
126
126
  defaultMessage: 'Account Information'
127
127
  })}
128
128
  </StoreTitle>
129
- <h1
129
+ <div
130
130
  aria-live="polite"
131
131
  className={classes.title}
132
132
  data-cy="AccountInformationPage-title"
@@ -135,7 +135,7 @@ const AccountInformationPage = props => {
135
135
  id={'accountInformationPage.accountInformation'}
136
136
  defaultMessage={'Account Information'}
137
137
  />
138
- </h1>
138
+ </div>
139
139
  {errorMessage ? errorMessage : pageContent}
140
140
  </div>
141
141
  );
@@ -10,7 +10,11 @@ import ForgotPassword from '../ForgotPassword';
10
10
  import defaultClasses from './accountMenu.module.css';
11
11
 
12
12
  const AccountMenu = React.forwardRef((props, ref) => {
13
- const { accountMenuIsOpen, setAccountMenuIsOpen } = props;
13
+ const {
14
+ handleTriggerClick,
15
+ accountMenuIsOpen,
16
+ setAccountMenuIsOpen
17
+ } = props;
14
18
  const talonProps = useAccountMenu({
15
19
  accountMenuIsOpen,
16
20
  setAccountMenuIsOpen
@@ -67,6 +71,7 @@ const AccountMenu = React.forwardRef((props, ref) => {
67
71
  default: {
68
72
  dropdownContents = (
69
73
  <SignIn
74
+ handleTriggerClick={handleTriggerClick}
70
75
  classes={{
71
76
  modal_active: classes.loading
72
77
  }}
@@ -5,12 +5,16 @@ exports[`renders correctly when there are existing addresses 1`] = `
5
5
  className="root"
6
6
  >
7
7
  Title
8
- <h1
8
+ <div
9
9
  aria-live="polite"
10
10
  className="heading"
11
11
  >
12
12
  Address Book
13
- </h1>
13
+ <div
14
+ aria-label="You have added 3 address in your address book."
15
+ aria-live="polite"
16
+ />
17
+ </div>
14
18
  <div
15
19
  className="content"
16
20
  >
@@ -125,12 +129,16 @@ exports[`renders correctly when there are no existing addresses 1`] = `
125
129
  className="root"
126
130
  >
127
131
  Title
128
- <h1
132
+ <div
129
133
  aria-live="polite"
130
134
  className="heading"
131
135
  >
132
136
  Address Book
133
- </h1>
137
+ <div
138
+ aria-label="You have added 0 address in your address book."
139
+ aria-live="polite"
140
+ />
141
+ </div>
134
142
  <div
135
143
  className="content"
136
144
  >
@@ -200,12 +208,16 @@ exports[`renders delete confirmation on address that is being deleted 1`] = `
200
208
  className="root"
201
209
  >
202
210
  Title
203
- <h1
211
+ <div
204
212
  aria-live="polite"
205
213
  className="heading"
206
214
  >
207
215
  Address Book
208
- </h1>
216
+ <div
217
+ aria-label="You have added 3 address in your address book."
218
+ aria-live="polite"
219
+ />
220
+ </div>
209
221
  <div
210
222
  className="content"
211
223
  >
@@ -90,16 +90,26 @@ const AddressBookPage = props => {
90
90
  return fullPageLoadingIndicator;
91
91
  }
92
92
 
93
+ const addressBookPageMessage = formatMessage(
94
+ {
95
+ id: 'addressBookPage.addAddressMessage',
96
+ defaultMessage:
97
+ 'You have added {count} address in your address book.'
98
+ },
99
+ { count: customerAddresses.length }
100
+ );
101
+
93
102
  return (
94
103
  <div className={classes.root}>
95
104
  <StoreTitle>{PAGE_TITLE}</StoreTitle>
96
- <h1
105
+ <div
97
106
  aria-live="polite"
98
107
  className={classes.heading}
99
108
  data-cy="AddressBookPage-heading"
100
109
  >
101
110
  {PAGE_TITLE}
102
- </h1>
111
+ <div aria-live="polite" aria-label={addressBookPageMessage} />
112
+ </div>
103
113
  <div className={classes.content} data-cy="AddressBookPage-content">
104
114
  {addressBookElements}
105
115
  <LinkButton
@@ -91,6 +91,7 @@ const ProductForm = props => {
91
91
  }}
92
92
  errors={Array.from(errors.values())}
93
93
  scrollOnError={false}
94
+ allowErrorMessages={true}
94
95
  />
95
96
  <ProductDetail
96
97
  item={cartItem}
@@ -351,8 +351,8 @@ Array [
351
351
  fieldInput="region[region]"
352
352
  fieldSelect="region[region_id]"
353
353
  optionValueKey="id"
354
- validate={[Function]}
355
354
  />
355
+
356
356
  </div>
357
357
  <div
358
358
  className="postcode"
@@ -827,8 +827,8 @@ Array [
827
827
  fieldInput="region[region]"
828
828
  fieldSelect="region[region_id]"
829
829
  optionValueKey="id"
830
- validate={[Function]}
831
830
  />
831
+
832
832
  </div>
833
833
  <div
834
834
  className="postcode"
@@ -1364,8 +1364,8 @@ Array [
1364
1364
  fieldInput="region[region]"
1365
1365
  fieldSelect="region[region_id]"
1366
1366
  optionValueKey="id"
1367
- validate={[Function]}
1368
1367
  />
1368
+
1369
1369
  </div>
1370
1370
  <div
1371
1371
  className="postcode"
@@ -333,8 +333,8 @@ Array [
333
333
  fieldInput="region[region]"
334
334
  fieldSelect="region[region_id]"
335
335
  optionValueKey="id"
336
- validate={[Function]}
337
336
  />
337
+
338
338
  </div>
339
339
  <div
340
340
  className="postcode"
@@ -800,8 +800,8 @@ Array [
800
800
  fieldInput="region[region]"
801
801
  fieldSelect="region[region_id]"
802
802
  optionValueKey="id"
803
- validate={[Function]}
804
803
  />
804
+
805
805
  </div>
806
806
  <div
807
807
  className="postcode"
@@ -1255,8 +1255,8 @@ Array [
1255
1255
  fieldInput="region[region]"
1256
1256
  fieldSelect="region[region_id]"
1257
1257
  optionValueKey="id"
1258
- validate={[Function]}
1259
1258
  />
1259
+
1260
1260
  </div>
1261
1261
  <div
1262
1262
  className="postcode"
@@ -1736,8 +1736,8 @@ Array [
1736
1736
  fieldInput="region[region]"
1737
1737
  fieldSelect="region[region_id]"
1738
1738
  optionValueKey="id"
1739
- validate={[Function]}
1740
1739
  />
1740
+
1741
1741
  </div>
1742
1742
  <div
1743
1743
  className="postcode"
@@ -134,6 +134,18 @@ const CustomerForm = props => {
134
134
  <Text type="hidden" field="default_shipping" initialValue={true} />
135
135
  );
136
136
 
137
+ const createErrorMessage = JSON.stringify(
138
+ errors.get('createCustomerAddressMutation')
139
+ );
140
+ const updateErrorMessage = JSON.stringify(
141
+ errors.get('updateCustomerAddressMutation')
142
+ );
143
+ const errorMessage = 'region_id is required for the specified country code';
144
+ const regionError =
145
+ createErrorMessage?.includes(errorMessage) ||
146
+ updateErrorMessage?.includes(errorMessage);
147
+
148
+ // errors
137
149
  return (
138
150
  <Fragment>
139
151
  <FormError errors={Array.from(errors.values())} />
@@ -257,9 +269,10 @@ const CustomerForm = props => {
257
269
  />
258
270
  </Field>
259
271
  </div>
272
+
260
273
  <div className={classes.region}>
261
274
  <Region
262
- validate={isRequired}
275
+ regionError={regionError}
263
276
  data-cy="CustomerForm-region"
264
277
  fieldInput={'region[region]'}
265
278
  fieldSelect={'region[region_id]'}
@@ -269,7 +282,20 @@ const CustomerForm = props => {
269
282
  defaultMessage: 'State Required'
270
283
  })}
271
284
  />
285
+ {regionError ? (
286
+ <Message>
287
+ <div className={classes.regionError}>
288
+ <FormattedMessage
289
+ id={'validation.isRequired'}
290
+ defaultMessage={'isRequired'}
291
+ />
292
+ </div>
293
+ </Message>
294
+ ) : (
295
+ ''
296
+ )}
272
297
  </div>
298
+
273
299
  <div className={classes.postcode}>
274
300
  <Postcode
275
301
  validate={isRequired}
@@ -42,6 +42,11 @@
42
42
  composes: p-xs from global;
43
43
  }
44
44
 
45
+ .regionError {
46
+ color: brown;
47
+ font-weight: 600;
48
+ }
49
+
45
50
  @media (max-width: 959px) {
46
51
  .firstname {
47
52
  grid-column: 1 / span 2;
@@ -126,6 +126,13 @@ const GuestForm = props => {
126
126
  }
127
127
  }, [addToast, formatMessage, showSignInToast, handleToastAction]);
128
128
 
129
+ const shippingAddressError = JSON.stringify(
130
+ errors.get('setGuestShippingMutation')
131
+ );
132
+
133
+ const errorMessage = 'Region is required';
134
+ const regionError = shippingAddressError?.includes(errorMessage);
135
+
129
136
  return (
130
137
  <Fragment>
131
138
  <FormError errors={Array.from(errors.values())} />
@@ -304,11 +311,11 @@ const GuestForm = props => {
304
311
  </div>
305
312
  <div className={classes.region}>
306
313
  <Region
314
+ regionError={regionError}
307
315
  autoComplete={formatMessage({
308
316
  id: 'region.label',
309
317
  defaultMessage: 'State'
310
318
  })}
311
- validate={isRequired}
312
319
  fieldInput={'region[region]'}
313
320
  fieldSelect={'region[region_id]'}
314
321
  optionValueKey={'id'}
@@ -318,6 +325,18 @@ const GuestForm = props => {
318
325
  defaultMessage: 'State Required'
319
326
  })}
320
327
  />
328
+ {regionError ? (
329
+ <Message>
330
+ <div className={classes.regionError}>
331
+ <FormattedMessage
332
+ id={'validation.isRequired'}
333
+ defaultMessage={'isRequired'}
334
+ />
335
+ </div>
336
+ </Message>
337
+ ) : (
338
+ ''
339
+ )}
321
340
  </div>
322
341
  <div className={classes.postcode}>
323
342
  <Postcode
@@ -36,6 +36,11 @@
36
36
  composes: p-xs from global;
37
37
  }
38
38
 
39
+ .regionError {
40
+ color: brown;
41
+ font-weight: 600;
42
+ }
43
+
39
44
  @media (max-width: 959px) {
40
45
  .firstname {
41
46
  grid-column: 1 / span 2;
@@ -5,14 +5,14 @@ exports[`renders empty form without data 1`] = `
5
5
  className="root"
6
6
  >
7
7
  Communications
8
- <h1
8
+ <div
9
9
  className="title"
10
10
  >
11
11
  <mock-FormattedMessage
12
12
  defaultMessage="Communications"
13
13
  id="communicationsPage.communicationsText"
14
14
  />
15
- </h1>
15
+ </div>
16
16
  <p>
17
17
  <mock-FormattedMessage
18
18
  defaultMessage="We'd like to stay in touch. Please check the boxes next to the communications you'd like to receive."
@@ -114,14 +114,14 @@ exports[`renders form error 1`] = `
114
114
  className="root"
115
115
  >
116
116
  Communications
117
- <h1
117
+ <div
118
118
  className="title"
119
119
  >
120
120
  <mock-FormattedMessage
121
121
  defaultMessage="Communications"
122
122
  id="communicationsPage.communicationsText"
123
123
  />
124
- </h1>
124
+ </div>
125
125
  <p>
126
126
  <mock-FormattedMessage
127
127
  defaultMessage="We'd like to stay in touch. Please check the boxes next to the communications you'd like to receive."
@@ -223,14 +223,14 @@ exports[`renders prefilled form with data with disabled buttons 1`] = `
223
223
  className="root"
224
224
  >
225
225
  Communications
226
- <h1
226
+ <div
227
227
  className="title"
228
228
  >
229
229
  <mock-FormattedMessage
230
230
  defaultMessage="Communications"
231
231
  id="communicationsPage.communicationsText"
232
232
  />
233
- </h1>
233
+ </div>
234
234
  <p>
235
235
  <mock-FormattedMessage
236
236
  defaultMessage="We'd like to stay in touch. Please check the boxes next to the communications you'd like to receive."
@@ -334,14 +334,14 @@ exports[`renders prefilled form with data with enabled buttons 1`] = `
334
334
  className="root"
335
335
  >
336
336
  Communications
337
- <h1
337
+ <div
338
338
  className="title"
339
339
  >
340
340
  <mock-FormattedMessage
341
341
  defaultMessage="Communications"
342
342
  id="communicationsPage.communicationsText"
343
343
  />
344
- </h1>
344
+ </div>
345
345
  <p>
346
346
  <mock-FormattedMessage
347
347
  defaultMessage="We'd like to stay in touch. Please check the boxes next to the communications you'd like to receive."
@@ -45,12 +45,12 @@ const CommunicationsPage = props => {
45
45
  return (
46
46
  <div className={classes.root}>
47
47
  <StoreTitle>{title}</StoreTitle>
48
- <h1 className={classes.title}>
48
+ <div className={classes.title}>
49
49
  <FormattedMessage
50
50
  id={'communicationsPage.communicationsText'}
51
51
  defaultMessage={'Communications'}
52
52
  />
53
- </h1>
53
+ </div>
54
54
  <p>
55
55
  <FormattedMessage
56
56
  id={'communicationsPage.optInText'}
@@ -1,12 +1,16 @@
1
1
  import React from 'react';
2
2
 
3
3
  import { createTestInstance } from '@magento/peregrine';
4
-
4
+ import { useCurrencySwitcher } from '@magento/peregrine/lib/talons/Header/useCurrencySwitcher';
5
5
  import Checkbox from '../../../Checkbox';
6
6
  import FilterDefault from '../filterDefault';
7
7
 
8
8
  jest.mock('../../../Checkbox', () => props => <mock-Checkbox {...props} />);
9
9
 
10
+ jest.mock('@magento/peregrine/lib/talons/Header/useCurrencySwitcher', () => ({
11
+ useCurrencySwitcher: jest.fn()
12
+ }));
13
+
10
14
  const mockLabel = 'Item Label';
11
15
 
12
16
  let inputProps = {};
@@ -22,6 +26,16 @@ const givenDefaultValues = () => {
22
26
  };
23
27
  };
24
28
 
29
+ const talonProps = {
30
+ handleSwitchCurrency: jest.fn(),
31
+ availableCurrencies: ['USD', 'EUR'],
32
+ currentCurrencyCode: 'EUR',
33
+ currencyMenuRef: {},
34
+ currencyMenuTriggerRef: {},
35
+ currencyMenuIsOpen: false,
36
+ handleTriggerClick: jest.fn()
37
+ };
38
+
25
39
  const givenWithItem = () => {
26
40
  inputProps = {
27
41
  ...inputProps,
@@ -42,6 +56,7 @@ const givenWithSelectedItem = () => {
42
56
  describe('#FilterDefault', () => {
43
57
  beforeEach(() => {
44
58
  givenDefaultValues();
59
+ useCurrencySwitcher.mockReturnValueOnce(talonProps);
45
60
  });
46
61
 
47
62
  it('renders without item', () => {
@@ -5,6 +5,7 @@ import { bool, shape, string } from 'prop-types';
5
5
  import Checkbox from '../../Checkbox';
6
6
  import { useStyle } from '../../../classify';
7
7
  import defaultClasses from './filterDefault.module.css';
8
+ import { useCurrencySwitcher } from '@magento/peregrine/lib/talons/Header/useCurrencySwitcher';
8
9
 
9
10
  const FilterDefault = props => {
10
11
  const {
@@ -12,11 +13,22 @@ const FilterDefault = props => {
12
13
  isSelected,
13
14
  item,
14
15
  onMouseDown,
16
+ group,
15
17
  ...restProps
16
18
  } = props;
17
19
 
18
20
  const { label, value_index } = item || {};
19
21
  const classes = useStyle(defaultClasses, propsClasses);
22
+ const { currentCurrencyCode } = useCurrencySwitcher();
23
+ const currencySymbolMap = {
24
+ USD: '$',
25
+ EUR: '€'
26
+ };
27
+ const title =
28
+ group === 'price'
29
+ ? currencySymbolMap[currentCurrencyCode] +
30
+ label.replace('-', ' - ' + currencySymbolMap[currentCurrencyCode])
31
+ : label;
20
32
  const { formatMessage } = useIntl();
21
33
 
22
34
  const ariaLabel = !isSelected
@@ -44,7 +56,7 @@ const FilterDefault = props => {
44
56
  classes={classes}
45
57
  field={`${label}-${value_index}`}
46
58
  fieldValue={!!isSelected}
47
- label={label}
59
+ label={title}
48
60
  ariaLabel={ariaLabel}
49
61
  data-cy="FilterDefault-checkbox"
50
62
  onClick={onMouseDown}
@@ -52,6 +52,7 @@ const FilterItem = props => {
52
52
  item={tileItem}
53
53
  onMouseDown={handleClick}
54
54
  onKeyDown={handleKeyDown}
55
+ group={group}
55
56
  title={title}
56
57
  value={value}
57
58
  />
@@ -19,6 +19,7 @@ Array [
19
19
  </div>,
20
20
  <require('../AccountMenu')
21
21
  accountMenuIsOpen={false}
22
+ handleTriggerClick={[MockFunction handleTriggerClick]}
22
23
  />,
23
24
  ]
24
25
  `;
@@ -5,7 +5,7 @@ Array [
5
5
  <div>
6
6
  <button
7
7
  aria-expanded={false}
8
- aria-label="Toggle mini cart. You have 100 items in your cart."
8
+ aria-label="Toggle mini cart. You have 0 items in your cart."
9
9
  onClick={[Function]}
10
10
  >
11
11
  <span>
@@ -34,14 +34,11 @@ Array [
34
34
  />
35
35
  </svg>
36
36
  </span>
37
- <span>
38
- 99+
39
- </span>
40
37
  </button>
41
38
  </div>,
42
39
  <button
43
40
  aria-expanded={false}
44
- aria-label="Toggle mini cart. You have 100 items in your cart."
41
+ aria-label="Toggle mini cart. You have 0 items in your cart."
45
42
  onClick={[Function]}
46
43
  >
47
44
  <span>
@@ -70,9 +67,6 @@ Array [
70
67
  />
71
68
  </svg>
72
69
  </span>
73
- <span>
74
- 99+
75
- </span>
76
70
  </button>,
77
71
  <require('../MiniCart')
78
72
  isOpen={false}
@@ -86,7 +80,7 @@ Array [
86
80
  <div>
87
81
  <button
88
82
  aria-expanded={false}
89
- aria-label="Toggle mini cart. You have 10 items in your cart."
83
+ aria-label="Toggle mini cart. You have 0 items in your cart."
90
84
  onClick={[Function]}
91
85
  >
92
86
  <span>
@@ -115,14 +109,11 @@ Array [
115
109
  />
116
110
  </svg>
117
111
  </span>
118
- <span>
119
- 10
120
- </span>
121
112
  </button>
122
113
  </div>,
123
114
  <button
124
115
  aria-expanded={false}
125
- aria-label="Toggle mini cart. You have 10 items in your cart."
116
+ aria-label="Toggle mini cart. You have 0 items in your cart."
126
117
  onClick={[Function]}
127
118
  >
128
119
  <span>
@@ -151,9 +142,6 @@ Array [
151
142
  />
152
143
  </svg>
153
144
  </span>
154
- <span>
155
- 10
156
- </span>
157
145
  </button>,
158
146
  <require('../MiniCart')
159
147
  isOpen={false}
@@ -63,6 +63,7 @@ const AccountTrigger = props => {
63
63
  </div>
64
64
  <Suspense fallback={null}>
65
65
  <AccountMenu
66
+ handleTriggerClick={handleTriggerClick}
66
67
  ref={accountMenuRef}
67
68
  accountMenuIsOpen={accountMenuIsOpen}
68
69
  setAccountMenuIsOpen={setAccountMenuIsOpen}
@@ -7,7 +7,7 @@
7
7
  composes: px-3 from global;
8
8
  composes: py-5 from global;
9
9
  composes: right-0 from global;
10
- composes: top-full from global;
10
+ top: 80px;
11
11
  box-shadow: 0 3px rgb(var(--venia-global-color-gray-100));
12
12
  }
13
13
 
@@ -6,12 +6,16 @@ exports[`renders correctly with data 1`] = `
6
6
  className="root"
7
7
  >
8
8
  Title
9
- <h1
9
+ <div
10
10
  aria-live="polite"
11
11
  className="heading"
12
12
  >
13
13
  Order History
14
- </h1>
14
+ <div
15
+ aria-label="You have 3 orders in your history"
16
+ aria-live="polite"
17
+ />
18
+ </div>
15
19
  <div
16
20
  className="filterRow"
17
21
  >
@@ -209,12 +213,16 @@ exports[`renders correctly without data 1`] = `
209
213
  className="root"
210
214
  >
211
215
  Title
212
- <h1
216
+ <div
213
217
  aria-live="polite"
214
218
  className="heading"
215
219
  >
216
220
  Order History
217
- </h1>
221
+ <div
222
+ aria-label="You have 0 orders in your history"
223
+ aria-live="polite"
224
+ />
225
+ </div>
218
226
  <div
219
227
  className="filterRow"
220
228
  >
@@ -388,12 +396,16 @@ exports[`renders invalid order id message if order id is wrong 1`] = `
388
396
  className="root"
389
397
  >
390
398
  Title
391
- <h1
399
+ <div
392
400
  aria-live="polite"
393
401
  className="heading"
394
402
  >
395
403
  Order History
396
- </h1>
404
+ <div
405
+ aria-label="You have 0 orders in your history"
406
+ aria-live="polite"
407
+ />
408
+ </div>
397
409
  <div
398
410
  className="filterRow"
399
411
  >
@@ -581,12 +593,16 @@ exports[`renders loading indicator 1`] = `
581
593
  className="root"
582
594
  >
583
595
  Title
584
- <h1
596
+ <div
585
597
  aria-live="polite"
586
598
  className="heading"
587
599
  >
588
600
  Order History
589
- </h1>
601
+ <div
602
+ aria-label="You have 0 orders in your history"
603
+ aria-live="polite"
604
+ />
605
+ </div>
590
606
  <div
591
607
  className="filterRow"
592
608
  >
@@ -794,12 +810,16 @@ exports[`renders no orders message is orders is empty 1`] = `
794
810
  className="root"
795
811
  >
796
812
  Title
797
- <h1
813
+ <div
798
814
  aria-live="polite"
799
815
  className="heading"
800
816
  >
801
817
  Order History
802
- </h1>
818
+ <div
819
+ aria-label="You have 0 orders in your history"
820
+ aria-live="polite"
821
+ />
822
+ </div>
803
823
  <div
804
824
  className="filterRow"
805
825
  >
@@ -56,6 +56,15 @@ const OrderHistoryPage = props => {
56
56
  id: 'orderHistoryPage.search',
57
57
  defaultMessage: 'Search by Order Number'
58
58
  });
59
+
60
+ const ordersCountMessage = formatMessage(
61
+ {
62
+ id: 'orderHistoryPage.ordersCount',
63
+ defaultMessage: 'You have {count} orders in your history.'
64
+ },
65
+ { count: orders.length }
66
+ );
67
+
59
68
  const classes = useStyle(defaultClasses, props.classes);
60
69
 
61
70
  const orderRows = useMemo(() => {
@@ -160,9 +169,11 @@ const OrderHistoryPage = props => {
160
169
  <OrderHistoryContextProvider>
161
170
  <div className={classes.root}>
162
171
  <StoreTitle>{PAGE_TITLE}</StoreTitle>
163
- <h1 aria-live="polite" className={classes.heading}>
172
+ <div aria-live="polite" className={classes.heading}>
164
173
  {PAGE_TITLE}
165
- </h1>
174
+ <div aria-live="polite" aria-label={ordersCountMessage} />
175
+ </div>
176
+
166
177
  <div className={classes.filterRow}>
167
178
  <span className={classes.pageInfo}>{pageInfoLabel}</span>
168
179
  <Form className={classes.search} onSubmit={handleSubmit}>
@@ -18,6 +18,7 @@ import { GET_REGIONS_QUERY } from './region.gql';
18
18
  const Region = props => {
19
19
  const {
20
20
  classes: propClasses,
21
+ regionError,
21
22
  countryCodeField,
22
23
  fieldInput,
23
24
  fieldSelect,
@@ -47,13 +48,19 @@ const Region = props => {
47
48
  const regionField =
48
49
  regions.length || loading ? (
49
50
  <Select
51
+ regionError={regionError}
50
52
  {...regionProps}
51
53
  field={fieldSelect}
52
54
  id={classes.root}
53
55
  items={regions}
54
56
  />
55
57
  ) : (
56
- <TextInput {...regionProps} field={fieldInput} id={classes.root} />
58
+ <TextInput
59
+ {...regionProps}
60
+ field={fieldInput}
61
+ id={classes.root}
62
+ regionError={regionError}
63
+ />
57
64
  );
58
65
 
59
66
  return (
@@ -5,12 +5,16 @@ exports[`renders correctly when there are existing saved payments 1`] = `
5
5
  className="root"
6
6
  >
7
7
  Title
8
- <h1
8
+ <div
9
9
  aria-live="polite"
10
10
  className="heading"
11
11
  >
12
12
  Saved Payments
13
- </h1>
13
+ <div
14
+ aria-label="You have 1 saved payments."
15
+ aria-live="polite"
16
+ />
17
+ </div>
14
18
  <div
15
19
  className="content"
16
20
  >
@@ -37,12 +41,16 @@ exports[`renders correctly when there are no existing saved payments 1`] = `
37
41
  className="root"
38
42
  >
39
43
  Title
40
- <h1
44
+ <div
41
45
  aria-live="polite"
42
46
  className="heading"
43
47
  >
44
48
  Saved Payments
45
- </h1>
49
+ <div
50
+ aria-label="You have no saved payments."
51
+ aria-live="polite"
52
+ />
53
+ </div>
46
54
  <div
47
55
  className="content"
48
56
  />
@@ -48,6 +48,23 @@ const SavedPaymentsPage = props => {
48
48
  defaultMessage: 'Saved Payments'
49
49
  });
50
50
 
51
+ const savedPaymentsMessage = useMemo(() => {
52
+ if (!savedPayments.length) {
53
+ return formatMessage({
54
+ id: 'savedPaymentsPage.noSavedPayments',
55
+ defaultMessage: 'You have no saved payments.'
56
+ });
57
+ } else {
58
+ return formatMessage(
59
+ {
60
+ id: 'savedPaymentsPage.Message',
61
+ defaultMessage: 'You have {count} saved payments.'
62
+ },
63
+ { count: savedPayments.length }
64
+ );
65
+ }
66
+ }, [savedPayments, formatMessage]);
67
+
51
68
  if (isLoading) {
52
69
  return fullPageLoadingIndicator;
53
70
  }
@@ -55,9 +72,10 @@ const SavedPaymentsPage = props => {
55
72
  return (
56
73
  <div className={classes.root}>
57
74
  <StoreTitle>{title}</StoreTitle>
58
- <h1 aria-live="polite" className={classes.heading}>
75
+ <div aria-live="polite" className={classes.heading}>
59
76
  {title}
60
- </h1>
77
+ <div aria-live="polite" aria-label={savedPaymentsMessage} />
78
+ </div>
61
79
  <div className={classes.content}>{savedPaymentElements}</div>
62
80
  <div className={classes.noPayments}>{noSavedPayments}</div>
63
81
  </div>
@@ -18,6 +18,7 @@ const Select = props => {
18
18
  const {
19
19
  before,
20
20
  classes: propClasses,
21
+ regionError,
21
22
  field,
22
23
  items,
23
24
  message,
@@ -25,7 +26,8 @@ const Select = props => {
25
26
  } = props;
26
27
  const fieldState = useFieldState(field);
27
28
  const classes = useStyle(defaultClasses, propClasses);
28
- const inputClass = fieldState.error ? classes.input_error : classes.input;
29
+ const inputClass =
30
+ fieldState.error || regionError ? classes.input_error : classes.input;
29
31
 
30
32
  const options = items.map(
31
33
  ({ disabled = null, hidden = null, label, value, key = value }) => (
@@ -19,6 +19,7 @@ import GoogleRecaptcha from '../GoogleReCaptcha';
19
19
  const SignIn = props => {
20
20
  const classes = useStyle(defaultClasses, props.classes);
21
21
  const {
22
+ handleTriggerClick,
22
23
  setDefaultUsername,
23
24
  showCreateAccount,
24
25
  showForgotPassword,
@@ -27,6 +28,7 @@ const SignIn = props => {
27
28
 
28
29
  const { formatMessage } = useIntl();
29
30
  const talonProps = useSignIn({
31
+ handleTriggerClick,
30
32
  getCartDetailsQuery: GET_CART_DETAILS_QUERY,
31
33
  setDefaultUsername,
32
34
  showCreateAccount,
@@ -12,13 +12,15 @@ const TextInput = props => {
12
12
  after,
13
13
  before,
14
14
  classes: propClasses,
15
+ regionError,
15
16
  field,
16
17
  message,
17
18
  ...rest
18
19
  } = props;
19
20
  const fieldState = useFieldState(field);
20
21
  const classes = useStyle(defaultClasses, propClasses);
21
- const inputClass = fieldState.error ? classes.input_error : classes.input;
22
+ var inputClass =
23
+ fieldState.error || regionError ? classes.input_error : classes.input;
22
24
 
23
25
  return (
24
26
  <Fragment>
@@ -4,23 +4,34 @@ exports[`empty single wishlist 1`] = `
4
4
  <div
5
5
  className="root"
6
6
  >
7
- <h1
7
+ <div
8
8
  aria-live="polite"
9
9
  className="heading"
10
10
  >
11
+ <div
12
+ aria-label="You have 5 items in your wishlist"
13
+ aria-live="polite"
14
+ />
11
15
  <mock-FormattedMessage
12
16
  defaultMessage="{count, plural, one {Favorites List} other {Favorites Lists}}"
13
17
  id="wishlistPage.headingText"
14
18
  values={
15
19
  Object {
16
- "count": 0,
20
+ "count": 1,
17
21
  }
18
22
  }
19
23
  />
20
- </h1>
21
- <Wishlist />
24
+ </div>
25
+ <Wishlist
26
+ data={
27
+ Object {
28
+ "items_count": 5,
29
+ }
30
+ }
31
+ isCollapsed={false}
32
+ />
22
33
  <CreateWishlist
23
- numberOfWishlists={0}
34
+ numberOfWishlists={1}
24
35
  />
25
36
  </div>
26
37
  `;
@@ -29,10 +40,14 @@ exports[`renders a single wishlist without visibility toggle 1`] = `
29
40
  <div
30
41
  className="root"
31
42
  >
32
- <h1
43
+ <div
33
44
  aria-live="polite"
34
45
  className="heading"
35
46
  >
47
+ <div
48
+ aria-label="You have 1 items in your wishlist"
49
+ aria-live="polite"
50
+ />
36
51
  <mock-FormattedMessage
37
52
  defaultMessage="{count, plural, one {Favorites List} other {Favorites Lists}}"
38
53
  id="wishlistPage.headingText"
@@ -42,11 +57,12 @@ exports[`renders a single wishlist without visibility toggle 1`] = `
42
57
  }
43
58
  }
44
59
  />
45
- </h1>
60
+ </div>
46
61
  <Wishlist
47
62
  data={
48
63
  Object {
49
64
  "id": 1,
65
+ "items_count": 1,
50
66
  "name": "Favorites",
51
67
  }
52
68
  }
@@ -62,20 +78,24 @@ exports[`renders disabled feature error 1`] = `
62
78
  <div
63
79
  className="root"
64
80
  >
65
- <h1
81
+ <div
66
82
  aria-live="polite"
67
83
  className="heading"
68
84
  >
85
+ <div
86
+ aria-label="You have 1 items in your wishlist"
87
+ aria-live="polite"
88
+ />
69
89
  <mock-FormattedMessage
70
90
  defaultMessage="{count, plural, one {Favorites List} other {Favorites Lists}}"
71
91
  id="wishlistPage.headingText"
72
92
  values={
73
93
  Object {
74
- "count": 0,
94
+ "count": 1,
75
95
  }
76
96
  }
77
97
  />
78
- </h1>
98
+ </div>
79
99
  <div
80
100
  className="errorContainer"
81
101
  >
@@ -93,20 +113,24 @@ exports[`renders general fetch error 1`] = `
93
113
  <div
94
114
  className="root"
95
115
  >
96
- <h1
116
+ <div
97
117
  aria-live="polite"
98
118
  className="heading"
99
119
  >
120
+ <div
121
+ aria-label="You have 1 items in your wishlist"
122
+ aria-live="polite"
123
+ />
100
124
  <mock-FormattedMessage
101
125
  defaultMessage="{count, plural, one {Favorites List} other {Favorites Lists}}"
102
126
  id="wishlistPage.headingText"
103
127
  values={
104
128
  Object {
105
- "count": 0,
129
+ "count": 1,
106
130
  }
107
131
  }
108
132
  />
109
- </h1>
133
+ </div>
110
134
  <div
111
135
  className="errorContainer"
112
136
  >
@@ -206,10 +230,14 @@ exports[`renders wishlist data 1`] = `
206
230
  <div
207
231
  className="root"
208
232
  >
209
- <h1
233
+ <div
210
234
  aria-live="polite"
211
235
  className="heading"
212
236
  >
237
+ <div
238
+ aria-label="You have 1 items in your wishlist"
239
+ aria-live="polite"
240
+ />
213
241
  <mock-FormattedMessage
214
242
  defaultMessage="{count, plural, one {Favorites List} other {Favorites Lists}}"
215
243
  id="wishlistPage.headingText"
@@ -219,11 +247,12 @@ exports[`renders wishlist data 1`] = `
219
247
  }
220
248
  }
221
249
  />
222
- </h1>
250
+ </div>
223
251
  <Wishlist
224
252
  data={
225
253
  Object {
226
254
  "id": 1,
255
+ "items_count": 1,
227
256
  "name": "Favorites",
228
257
  }
229
258
  }
@@ -233,6 +262,7 @@ exports[`renders wishlist data 1`] = `
233
262
  data={
234
263
  Object {
235
264
  "id": 2,
265
+ "items_count": 2,
236
266
  "name": "Registry",
237
267
  }
238
268
  }
@@ -29,7 +29,7 @@ test('renders general fetch error', () => {
29
29
  { graphQLErrors: [{ message: 'Ruh roh!' }] }
30
30
  ]
31
31
  ]),
32
- wishlists: []
32
+ wishlists: [{ id: 1, name: 'Favorites', items_count: 1 }]
33
33
  });
34
34
 
35
35
  const tree = createTestInstance(<WishlistPage />);
@@ -49,7 +49,7 @@ test('renders disabled feature error', () => {
49
49
  }
50
50
  ]
51
51
  ]),
52
- wishlists: []
52
+ wishlists: [{ id: 1, name: 'Favorites', items_count: 1 }]
53
53
  });
54
54
 
55
55
  const tree = createTestInstance(<WishlistPage />);
@@ -60,7 +60,10 @@ test('renders disabled feature error', () => {
60
60
  test('renders wishlist data', () => {
61
61
  useWishlistPage.mockReturnValue({
62
62
  errors: new Map(),
63
- wishlists: [{ id: 1, name: 'Favorites' }, { id: 2, name: 'Registry' }]
63
+ wishlists: [
64
+ { id: 1, name: 'Favorites', items_count: 1 },
65
+ { id: 2, name: 'Registry', items_count: 2 }
66
+ ]
64
67
  });
65
68
 
66
69
  const tree = createTestInstance(<WishlistPage />);
@@ -71,7 +74,7 @@ test('renders wishlist data', () => {
71
74
  test('renders a single wishlist without visibility toggle', () => {
72
75
  useWishlistPage.mockReturnValue({
73
76
  errors: new Map(),
74
- wishlists: [{ id: 1, name: 'Favorites' }]
77
+ wishlists: [{ id: 1, name: 'Favorites', items_count: 1 }]
75
78
  });
76
79
 
77
80
  const tree = createTestInstance(<WishlistPage />);
@@ -82,7 +85,7 @@ test('renders a single wishlist without visibility toggle', () => {
82
85
  test('empty single wishlist', () => {
83
86
  useWishlistPage.mockReturnValue({
84
87
  errors: new Map(),
85
- wishlists: []
88
+ wishlists: [{ items_count: 5 }]
86
89
  });
87
90
 
88
91
  const tree = createTestInstance(<WishlistPage />);
@@ -79,13 +79,22 @@ const WishlistPage = props => {
79
79
  );
80
80
  }
81
81
 
82
+ const wishlistMessage = formatMessage(
83
+ {
84
+ id: 'wishlist.itemsMessage',
85
+ defaultMessage: 'You have {count} items in your wishlist.'
86
+ },
87
+ { count: wishlists[0].items_count }
88
+ );
89
+
82
90
  return (
83
91
  <div className={classes.root} data-cy="Wishlist-root">
84
- <h1
92
+ <div
85
93
  aria-live="polite"
86
94
  className={classes.heading}
87
95
  data-cy="WishlistPage-heading"
88
96
  >
97
+ <div aria-live="polite" aria-label={wishlistMessage} />
89
98
  <FormattedMessage
90
99
  values={{ count: wishlists.length }}
91
100
  id={'wishlistPage.headingText'}
@@ -93,7 +102,7 @@ const WishlistPage = props => {
93
102
  '{count, plural, one {Favorites List} other {Favorites Lists}}'
94
103
  }
95
104
  />
96
- </h1>
105
+ </div>
97
106
  {content}
98
107
  </div>
99
108
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magento/venia-ui",
3
- "version": "10.2.0-beta.2",
3
+ "version": "10.3.0-alpha.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -79,9 +79,9 @@
79
79
  },
80
80
  "peerDependencies": {
81
81
  "@apollo/client": "~3.5.0",
82
- "@magento/babel-preset-peregrine": "~1.2.2",
83
- "@magento/peregrine": "13.1.1-beta.2",
84
- "@magento/pwa-buildpack": "11.4.2-beta.2",
82
+ "@magento/babel-preset-peregrine": "1.2.3-alpha.1",
83
+ "@magento/peregrine": "13.2.1-alpha.1",
84
+ "@magento/pwa-buildpack": "11.4.3-alpha.1",
85
85
  "apollo-cache-persist": "~0.1.1",
86
86
  "braintree-web-drop-in": "~1.33.3",
87
87
  "graphql": "~15.5.0",