@magento/venia-ui 9.6.0-beta.1 → 9.7.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 (55) hide show
  1. package/i18n/en_US.json +1 -0
  2. package/lib/components/Accordion/__tests__/__snapshots__/accordion.spec.js.snap +2 -0
  3. package/lib/components/Accordion/section.js +1 -0
  4. package/lib/components/AddToCartDialog/__tests__/__snapshots__/addToCartDialog.spec.js.snap +11 -0
  5. package/lib/components/AddToCartDialog/__tests__/addToCartDialog.spec.js +1 -0
  6. package/lib/components/AddToCartDialog/addToCartDialog.js +4 -1
  7. package/lib/components/CartPage/PriceAdjustments/__tests__/__snapshots__/priceAdjustments.spec.js.snap +2 -0
  8. package/lib/components/CartPage/ProductListing/EditModal/__tests__/__snapshots__/productForm.spec.js.snap +22 -0
  9. package/lib/components/CartPage/ProductListing/EditModal/__tests__/productForm.spec.js +1 -0
  10. package/lib/components/CartPage/ProductListing/EditModal/productForm.js +2 -0
  11. package/lib/components/CartPage/ProductListing/__tests__/__snapshots__/product.spec.js.snap +3 -0
  12. package/lib/components/CategoryTree/categoryBranch.js +3 -3
  13. package/lib/components/CategoryTree/categoryLeaf.js +3 -3
  14. package/lib/components/CategoryTree/categoryTree.js +4 -4
  15. package/lib/components/CheckoutPage/PaymentInformation/paymentMethods.js +2 -0
  16. package/lib/components/CheckoutPage/PaymentInformation/paymentMethods.module.css +1 -3
  17. package/lib/components/FilterSidebar/filterSidebar.js +0 -1
  18. package/lib/components/Gallery/__tests__/__snapshots__/gallery.spec.js.snap +0 -6
  19. package/lib/components/Gallery/__tests__/__snapshots__/item.spec.js.snap +0 -2
  20. package/lib/components/Gallery/gallery.js +1 -6
  21. package/lib/components/Gallery/item.js +3 -9
  22. package/lib/components/Header/__tests__/__snapshots__/accountTrigger.spec.js.snap +1 -0
  23. package/lib/components/Header/accountTrigger.js +1 -0
  24. package/lib/components/LegacyMiniCart/__tests__/__snapshots__/kebab.spec.js.snap +2 -0
  25. package/lib/components/LegacyMiniCart/kebab.js +2 -1
  26. package/lib/components/LegacyMiniCart/kebab.module.css +0 -1
  27. package/lib/components/Logo/logo.js +1 -0
  28. package/lib/components/MegaMenu/__tests__/__snapshots__/MegaMenu.spec.js.snap +3 -0
  29. package/lib/components/MegaMenu/__tests__/__snapshots__/MegaMenuItem.spec.js.snap +2 -0
  30. package/lib/components/MegaMenu/megaMenuItem.js +4 -0
  31. package/lib/components/Navigation/navigation.js +2 -2
  32. package/lib/components/Pagination/navButton.module.css +5 -0
  33. package/lib/components/Pagination/tile.module.css +0 -1
  34. package/lib/components/ProductFullDetail/__tests__/__snapshots__/productFullDetail.spec.js.snap +576 -298
  35. package/lib/components/ProductFullDetail/__tests__/productFullDetail.spec.js +16 -0
  36. package/lib/components/ProductFullDetail/productFullDetail.js +37 -20
  37. package/lib/components/ProductFullDetail/productFullDetail.module.css +3 -0
  38. package/lib/components/ProductOptions/__tests__/__snapshots__/swatch.spec.js.snap +51 -0
  39. package/lib/components/ProductOptions/__tests__/__snapshots__/tile.spec.js.snap +28 -0
  40. package/lib/components/ProductOptions/__tests__/swatch.spec.js +52 -0
  41. package/lib/components/ProductOptions/__tests__/tile.spec.js +48 -0
  42. package/lib/components/ProductOptions/option.js +5 -1
  43. package/lib/components/ProductOptions/options.js +12 -2
  44. package/lib/components/ProductOptions/swatch.js +27 -5
  45. package/lib/components/ProductOptions/swatch.module.css +17 -0
  46. package/lib/components/ProductOptions/swatchList.js +25 -4
  47. package/lib/components/ProductOptions/tile.js +24 -5
  48. package/lib/components/ProductOptions/tile.module.css +20 -0
  49. package/lib/components/ProductOptions/tileList.js +25 -2
  50. package/lib/components/ProductSort/__tests__/__snapshots__/productSort.spec.js.snap +0 -1
  51. package/lib/components/ProductSort/productSort.js +0 -1
  52. package/lib/components/SearchPage/__tests__/__snapshots__/searchPage.spec.js.snap +28 -9
  53. package/lib/components/SearchPage/searchPage.js +6 -6
  54. package/lib/components/SortedByContainer/sortedByContainer.js +1 -1
  55. package/package.json +2 -2
@@ -175,6 +175,8 @@ const talonProps = {
175
175
  handleAddToCart: mockHandleAddToCart,
176
176
  handleSelectionChange: mockHandleSelectionChange,
177
177
  isOutOfStock: false,
178
+ isEverythingOutOfStock: false,
179
+ outOfStockVariants: [],
178
180
  isAddToCartDisabled: false,
179
181
  isSupportedProductType: true,
180
182
  mediaGalleryEntries: [],
@@ -356,3 +358,17 @@ test('it renders message with unsupported product type', () => {
356
358
 
357
359
  expect(tree.toJSON()).toMatchSnapshot();
358
360
  });
361
+
362
+ test('it renders message with everything out of stock', () => {
363
+ useProductFullDetail.mockReturnValue({
364
+ ...talonProps,
365
+ isEverythingOutOfStock: true,
366
+ isAddToCartDisabled: true
367
+ });
368
+
369
+ const tree = createTestInstance(
370
+ <ProductFullDetail product={mockConfigurableProduct} />
371
+ );
372
+
373
+ expect(tree.toJSON()).toMatchSnapshot();
374
+ });
@@ -47,6 +47,8 @@ const ProductFullDetail = props => {
47
47
  handleAddToCart,
48
48
  handleSelectionChange,
49
49
  isOutOfStock,
50
+ isEverythingOutOfStock,
51
+ outOfStockVariants,
50
52
  isAddToCartDisabled,
51
53
  isSupportedProductType,
52
54
  mediaGalleryEntries,
@@ -64,6 +66,8 @@ const ProductFullDetail = props => {
64
66
  <Options
65
67
  onSelectionChange={handleSelectionChange}
66
68
  options={product.configurable_options}
69
+ isEverythingOutOfStock={isEverythingOutOfStock}
70
+ outOfStockVariants={outOfStockVariants}
67
71
  />
68
72
  </Suspense>
69
73
  ) : null;
@@ -167,27 +171,40 @@ const ProductFullDetail = props => {
167
171
  };
168
172
  }, [customAttributes, productDetails.sku, formatMessage]);
169
173
 
170
- const cartCallToActionText = !isOutOfStock ? (
171
- <FormattedMessage
172
- id="productFullDetail.addItemToCart"
173
- defaultMessage="Add to Cart"
174
- />
175
- ) : (
176
- <FormattedMessage
177
- id="productFullDetail.itemOutOfStock"
178
- defaultMessage="Out of Stock"
179
- />
180
- );
181
-
174
+ const cartCallToActionText =
175
+ !isEverythingOutOfStock || !isOutOfStock ? (
176
+ <FormattedMessage
177
+ id="productFullDetail.addItemToCart"
178
+ defaultMessage="Add to Cart"
179
+ />
180
+ ) : (
181
+ <FormattedMessage
182
+ id="productFullDetail.itemOutOfStock"
183
+ defaultMessage="Out of Stock"
184
+ />
185
+ );
186
+ // Error message for screen reader
182
187
  const cartActionContent = isSupportedProductType ? (
183
- <Button
184
- data-cy="ProductFullDetail-addToCartButton"
185
- disabled={isAddToCartDisabled}
186
- priority="high"
187
- type="submit"
188
- >
189
- {cartCallToActionText}
190
- </Button>
188
+ <section className={classes.actButton}>
189
+ <Button
190
+ data-cy="ProductFullDetail-addToCartButton"
191
+ disabled={isAddToCartDisabled}
192
+ aria-disabled={isAddToCartDisabled}
193
+ aria-label={
194
+ isEverythingOutOfStock
195
+ ? formatMessage({
196
+ id: 'productFullDetail.outOfStockProduct',
197
+ defaultMessage:
198
+ 'This item is currently out of stock'
199
+ })
200
+ : ''
201
+ }
202
+ priority="high"
203
+ type="submit"
204
+ >
205
+ {cartCallToActionText}
206
+ </Button>
207
+ </section>
191
208
  ) : (
192
209
  <div className={classes.unavailableContainer}>
193
210
  <Info />
@@ -197,3 +197,6 @@
197
197
  composes: text-subtle from global;
198
198
  composes: w-full from global;
199
199
  }
200
+ .actButton {
201
+ composes: mt-sm from global;
202
+ }
@@ -35,6 +35,57 @@ exports[`appends "_focused" to className if hasFocus is true 1`] = `
35
35
  </button>
36
36
  `;
37
37
 
38
+ exports[`appends "_outOfStock" to className if isEverythingOutOfStock is true 1`] = `
39
+ <button
40
+ className="root_outOfStock"
41
+ disabled={true}
42
+ onClick={[Function]}
43
+ style={
44
+ Object {
45
+ "--venia-swatch-bg": "#123123",
46
+ }
47
+ }
48
+ title="red"
49
+ type="button"
50
+ >
51
+ <span
52
+ className="root"
53
+ >
54
+ <svg
55
+ className="icon"
56
+ fill="none"
57
+ height={24}
58
+ stroke="currentColor"
59
+ strokeLinecap="round"
60
+ strokeLinejoin="round"
61
+ strokeWidth="2"
62
+ viewBox="0 0 24 24"
63
+ width={24}
64
+ xmlns="http://www.w3.org/2000/svg"
65
+ >
66
+ <polyline
67
+ points="20 6 9 17 4 12"
68
+ />
69
+ </svg>
70
+ </span>
71
+ </button>
72
+ `;
73
+
74
+ exports[`appends "_outOfStock" to className if isOptionOutOfStock is true 1`] = `
75
+ <button
76
+ className="root_outOfStock"
77
+ disabled={true}
78
+ onClick={[Function]}
79
+ style={
80
+ Object {
81
+ "--venia-swatch-bg": "#123123",
82
+ }
83
+ }
84
+ title="red"
85
+ type="button"
86
+ />
87
+ `;
88
+
38
89
  exports[`appends "_selected" to className if isSelected is true 1`] = `
39
90
  <button
40
91
  className="root_selected"
@@ -13,6 +13,34 @@ exports[`appends "_focused" to className if hasFocus is true 1`] = `
13
13
  </button>
14
14
  `;
15
15
 
16
+ exports[`appends "_outOfStock" to className if isEverythingOutOfStock is true 1`] = `
17
+ <button
18
+ className="root_outOfStock"
19
+ disabled={true}
20
+ onClick={[Function]}
21
+ title="red"
22
+ type="button"
23
+ >
24
+ <span>
25
+ red
26
+ </span>
27
+ </button>
28
+ `;
29
+
30
+ exports[`appends "_outOfStock" to className if isOptionOutOfStock is true 1`] = `
31
+ <button
32
+ className="root_outOfStock"
33
+ disabled={true}
34
+ onClick={[Function]}
35
+ title="red"
36
+ type="button"
37
+ >
38
+ <span>
39
+ red
40
+ </span>
41
+ </button>
42
+ `;
43
+
16
44
  exports[`appends "_selected" to className if isSelected is true 1`] = `
17
45
  <button
18
46
  className="root_selected"
@@ -27,6 +27,10 @@ test('renders a Swatch correctly', () => {
27
27
  expect(component.root.findByType('button').props.className).not.toContain(
28
28
  '_focused'
29
29
  );
30
+
31
+ expect(component.root.findByType('button').props.className).not.toContain(
32
+ '_outOfStock'
33
+ );
30
34
  expect(component).toMatchSnapshot();
31
35
  });
32
36
 
@@ -59,6 +63,34 @@ test('appends "_focused" to className if hasFocus is true', () => {
59
63
  expect(component).toMatchSnapshot();
60
64
  });
61
65
 
66
+ test('appends "_outOfStock" to className if isEverythingOutOfStock is true', () => {
67
+ const props = {
68
+ ...defaultProps,
69
+ isEverythingOutOfStock: true
70
+ };
71
+ const component = testRenderer.create(<Swatch {...props} />);
72
+
73
+ expect(component.root.findByType('button').props.className).toContain(
74
+ '_outOfStock'
75
+ );
76
+
77
+ expect(component).toMatchSnapshot();
78
+ });
79
+
80
+ test('appends "_outOfStock" to className if isOptionOutOfStock is true', () => {
81
+ const props = {
82
+ ...defaultProps,
83
+ isOptionOutOfStock: true
84
+ };
85
+ const component = testRenderer.create(<Swatch {...props} />);
86
+
87
+ expect(component.root.findByType('button').props.className).toContain(
88
+ '_outOfStock'
89
+ );
90
+
91
+ expect(component).toMatchSnapshot();
92
+ });
93
+
62
94
  test('renders an icon if isSelected is true', () => {
63
95
  const props = {
64
96
  ...defaultProps,
@@ -70,3 +102,23 @@ test('renders an icon if isSelected is true', () => {
70
102
  expect(() => component.root.findByType(Icon)).not.toThrow();
71
103
  expect(component).toMatchSnapshot();
72
104
  });
105
+
106
+ test('button is disabled if isEverythingOutOfStock is true', () => {
107
+ const props = {
108
+ ...defaultProps,
109
+ isEverythingOutOfStock: true
110
+ };
111
+ const component = testRenderer.create(<Swatch {...props} />);
112
+
113
+ expect(component.root.findByType('button').props.disabled).toBeTruthy;
114
+ });
115
+
116
+ test('button is disabled if isOptionOutOfStock is true', () => {
117
+ const props = {
118
+ ...defaultProps,
119
+ isOptionOutOfStock: true
120
+ };
121
+ const component = testRenderer.create(<Swatch {...props} />);
122
+
123
+ expect(component.root.findByType('button').props.disabled).toBeTruthy;
124
+ });
@@ -54,3 +54,51 @@ test('appends "_focused" to className if hasFocus is true', () => {
54
54
 
55
55
  expect(component).toMatchSnapshot();
56
56
  });
57
+
58
+ test('appends "_outOfStock" to className if isEverythingOutOfStock is true', () => {
59
+ const props = {
60
+ ...defaultProps,
61
+ isEverythingOutOfStock: true
62
+ };
63
+ const component = testRenderer.create(<Tile {...props} />);
64
+
65
+ expect(component.root.findByType('button').props.className).toContain(
66
+ '_outOfStock'
67
+ );
68
+
69
+ expect(component).toMatchSnapshot();
70
+ });
71
+
72
+ test('appends "_outOfStock" to className if isOptionOutOfStock is true', () => {
73
+ const props = {
74
+ ...defaultProps,
75
+ isOptionOutOfStock: true
76
+ };
77
+ const component = testRenderer.create(<Tile {...props} />);
78
+
79
+ expect(component.root.findByType('button').props.className).toContain(
80
+ '_outOfStock'
81
+ );
82
+
83
+ expect(component).toMatchSnapshot();
84
+ });
85
+
86
+ test('button is disabled if isEverythingOutOfStock is true', () => {
87
+ const props = {
88
+ ...defaultProps,
89
+ isEverythingOutOfStock: true
90
+ };
91
+ const component = testRenderer.create(<Tile {...props} />);
92
+
93
+ expect(component.root.findByType('button').props.disabled).toBeTruthy;
94
+ });
95
+
96
+ test('button is disabled if isOptionOutOfStock is true', () => {
97
+ const props = {
98
+ ...defaultProps,
99
+ isOptionOutOfStock: true
100
+ };
101
+ const component = testRenderer.create(<Tile {...props} />);
102
+
103
+ expect(component.root.findByType('button').props.disabled).toBeTruthy;
104
+ });
@@ -34,7 +34,9 @@ const Option = props => {
34
34
  label,
35
35
  onSelectionChange,
36
36
  selectedValue,
37
- values
37
+ values,
38
+ isEverythingOutOfStock,
39
+ outOfStockVariants
38
40
  } = props;
39
41
 
40
42
  const talonProps = useOption({
@@ -66,6 +68,8 @@ const Option = props => {
66
68
  selectedValue={initialSelection}
67
69
  items={values}
68
70
  onSelectionChange={handleSelectionChange}
71
+ isEverythingOutOfStock={isEverythingOutOfStock}
72
+ outOfStockVariants={outOfStockVariants}
69
73
  />
70
74
  <dl className={classes.selection}>
71
75
  <dt
@@ -5,11 +5,19 @@ import Option from './option';
5
5
  import { useOptions } from '@magento/peregrine/lib/talons/ProductOptions/useOptions';
6
6
 
7
7
  const Options = props => {
8
- const { classes, onSelectionChange, options, selectedValues = [] } = props;
8
+ const {
9
+ classes,
10
+ onSelectionChange,
11
+ options,
12
+ selectedValues = [],
13
+ isEverythingOutOfStock,
14
+ outOfStockVariants
15
+ } = props;
9
16
 
10
17
  const talonProps = useOptions({
11
18
  onSelectionChange,
12
- selectedValues
19
+ selectedValues,
20
+ options
13
21
  });
14
22
 
15
23
  const { handleSelectionChange, selectedValueMap } = talonProps;
@@ -22,6 +30,8 @@ const Options = props => {
22
30
  key={option.attribute_id}
23
31
  onSelectionChange={handleSelectionChange}
24
32
  selectedValue={selectedValueMap.get(option.label)}
33
+ isEverythingOutOfStock={isEverythingOutOfStock}
34
+ outOfStockVariants={outOfStockVariants}
25
35
  />
26
36
  ));
27
37
  };
@@ -18,8 +18,16 @@ import defaultClasses from './swatch.module.css';
18
18
 
19
19
  import { useSwatch } from '@magento/peregrine/lib/talons/ProductOptions/useSwatch';
20
20
 
21
- const getClassName = (name, isSelected, hasFocus) =>
22
- `${name}${isSelected ? '_selected' : ''}${hasFocus ? '_focused' : ''}`;
21
+ const getClassName = (
22
+ name,
23
+ isSelected,
24
+ hasFocus,
25
+ isOptionOutOfStock,
26
+ isEverythingOutOfStock
27
+ ) =>
28
+ `${name}${isSelected ? '_selected' : ''}${hasFocus ? '_focused' : ''}${
29
+ isEverythingOutOfStock || isOptionOutOfStock ? '_outOfStock' : ''
30
+ }`;
23
31
 
24
32
  // Swatches _must_ have a 1x1 aspect ratio to match the UI.
25
33
  const SWATCH_WIDTH = 48;
@@ -30,7 +38,9 @@ const Swatch = props => {
30
38
  isSelected,
31
39
  item: { label, value_index, swatch_data },
32
40
  onClick,
33
- style
41
+ style,
42
+ isEverythingOutOfStock,
43
+ isOptionOutOfStock
34
44
  } = props;
35
45
 
36
46
  const talonProps = useSwatch({
@@ -74,7 +84,16 @@ const Swatch = props => {
74
84
  });
75
85
  }
76
86
 
77
- const className = classes[getClassName('root', isSelected, hasFocus)];
87
+ const className =
88
+ classes[
89
+ getClassName(
90
+ 'root',
91
+ isSelected,
92
+ hasFocus,
93
+ isOptionOutOfStock,
94
+ isEverythingOutOfStock
95
+ )
96
+ ];
78
97
 
79
98
  return (
80
99
  <button
@@ -84,8 +103,11 @@ const Swatch = props => {
84
103
  title={label}
85
104
  type="button"
86
105
  data-cy="Swatch-root"
106
+ disabled={isEverythingOutOfStock || isOptionOutOfStock}
87
107
  >
88
- <Icon classes={{ root: checkStyle }} src={CheckIcon} />
108
+ {!isOptionOutOfStock && (
109
+ <Icon classes={{ root: checkStyle }} src={CheckIcon} />
110
+ )}
89
111
  </button>
90
112
  );
91
113
  };
@@ -36,3 +36,20 @@
36
36
  composes: checked;
37
37
  opacity: 0;
38
38
  }
39
+
40
+ .root_outOfStock,
41
+ .root_selected_outOfStock {
42
+ composes: root;
43
+ composes: opacity-40 from global;
44
+ composes: border-2 from global;
45
+ composes: border-solid from global;
46
+ composes: border-gray-400 from global;
47
+ }
48
+ .root_outOfStock:after,
49
+ .root_selected_outOfStock:after {
50
+ content: '';
51
+ position: absolute;
52
+ border-top: 2px solid rgb(var(--venia-global-color-gray-400));
53
+ width: 62px;
54
+ transform: rotate(-45deg);
55
+ }
@@ -6,25 +6,46 @@ import { useStyle } from '../../classify';
6
6
  import defaultClasses from './swatchList.module.css';
7
7
 
8
8
  const SwatchList = props => {
9
- const { getItemKey, selectedValue = {}, items, onSelectionChange } = props;
9
+ const {
10
+ getItemKey,
11
+ selectedValue = {},
12
+ items,
13
+ onSelectionChange,
14
+ isEverythingOutOfStock,
15
+ outOfStockVariants
16
+ } = props;
10
17
 
11
18
  const classes = useStyle(defaultClasses, props.classes);
12
-
13
19
  const swatches = useMemo(
14
20
  () =>
15
21
  items.map(item => {
16
22
  const isSelected = item.label === selectedValue.label;
17
-
23
+ let isOptionOutOfStock;
24
+ if (outOfStockVariants && outOfStockVariants.length > 0) {
25
+ const flatOutOfStockArray = outOfStockVariants.flat();
26
+ isOptionOutOfStock = flatOutOfStockArray.includes(
27
+ item.value_index
28
+ );
29
+ }
18
30
  return (
19
31
  <Swatch
20
32
  key={getItemKey(item)}
21
33
  isSelected={isSelected}
22
34
  item={item}
23
35
  onClick={onSelectionChange}
36
+ isEverythingOutOfStock={isEverythingOutOfStock}
37
+ isOptionOutOfStock={isOptionOutOfStock}
24
38
  />
25
39
  );
26
40
  }),
27
- [getItemKey, selectedValue.label, items, onSelectionChange]
41
+ [
42
+ getItemKey,
43
+ selectedValue.label,
44
+ items,
45
+ onSelectionChange,
46
+ isEverythingOutOfStock,
47
+ outOfStockVariants
48
+ ]
28
49
  );
29
50
 
30
51
  return <div className={classes.root}>{swatches}</div>;
@@ -5,15 +5,25 @@ import { useStyle } from '../../classify';
5
5
  import defaultClasses from './tile.module.css';
6
6
  import { useTile } from '@magento/peregrine/lib/talons/ProductOptions/useTile';
7
7
 
8
- const getClassName = (name, isSelected, hasFocus) =>
9
- `${name}${isSelected ? '_selected' : ''}${hasFocus ? '_focused' : ''}`;
8
+ const getClassName = (
9
+ name,
10
+ isSelected,
11
+ hasFocus,
12
+ isOptionOutOfStock,
13
+ isEverythingOutOfStock
14
+ ) =>
15
+ `${name}${isSelected ? '_selected' : ''}${hasFocus ? '_focused' : ''}${
16
+ isEverythingOutOfStock || isOptionOutOfStock ? '_outOfStock' : ''
17
+ }`;
10
18
 
11
19
  const Tile = props => {
12
20
  const {
13
21
  hasFocus,
14
22
  isSelected,
15
23
  item: { label, value_index },
16
- onClick
24
+ onClick,
25
+ isEverythingOutOfStock,
26
+ isOptionOutOfStock
17
27
  } = props;
18
28
 
19
29
  const talonProps = useTile({
@@ -22,9 +32,17 @@ const Tile = props => {
22
32
  });
23
33
 
24
34
  const { handleClick } = talonProps;
25
-
26
35
  const classes = useStyle(defaultClasses, props.classes);
27
- const className = classes[getClassName('root', isSelected, hasFocus)];
36
+ const className =
37
+ classes[
38
+ getClassName(
39
+ 'root',
40
+ isSelected,
41
+ hasFocus,
42
+ isOptionOutOfStock,
43
+ isEverythingOutOfStock
44
+ )
45
+ ];
28
46
 
29
47
  return (
30
48
  <button
@@ -33,6 +51,7 @@ const Tile = props => {
33
51
  title={label}
34
52
  type="button"
35
53
  data-cy="Tile-button"
54
+ disabled={isEverythingOutOfStock || isOptionOutOfStock}
36
55
  >
37
56
  <span>{label}</span>
38
57
  </button>
@@ -9,6 +9,7 @@
9
9
  composes: px-2xs from global;
10
10
  composes: py-0 from global;
11
11
  composes: rounded-sm from global;
12
+ position: relative;
12
13
  }
13
14
 
14
15
  .root_selected {
@@ -25,3 +26,22 @@
25
26
  .root_selected_focused {
26
27
  composes: root_selected;
27
28
  }
29
+
30
+ .root_outOfStock,
31
+ .root_selected_outOfStock {
32
+ composes: root;
33
+ composes: bg-disabledTile from global;
34
+ composes: opacity-50 from global;
35
+ composes: border-2 from global;
36
+ composes: border-solid from global;
37
+ composes: border-gray-400 from global;
38
+ composes: text-gray-600 from global;
39
+ }
40
+ .root_outOfStock:after,
41
+ .root_selected_outOfStock:after {
42
+ content: '';
43
+ position: absolute;
44
+ border-top: 2px solid rgb(var(--venia-global-color-gray-400));
45
+ width: 62px;
46
+ transform: rotate(-45deg);
47
+ }
@@ -6,7 +6,14 @@ import { useStyle } from '../../classify';
6
6
  import defaultClasses from './tileList.module.css';
7
7
 
8
8
  const TileList = props => {
9
- const { getItemKey, selectedValue = {}, items, onSelectionChange } = props;
9
+ const {
10
+ getItemKey,
11
+ selectedValue = {},
12
+ items,
13
+ onSelectionChange,
14
+ isEverythingOutOfStock,
15
+ outOfStockVariants
16
+ } = props;
10
17
 
11
18
  const classes = useStyle(defaultClasses, props.classes);
12
19
 
@@ -14,6 +21,13 @@ const TileList = props => {
14
21
  () =>
15
22
  items.map(item => {
16
23
  const isSelected = item.label === selectedValue.label;
24
+ let isOptionOutOfStock;
25
+ if (outOfStockVariants && outOfStockVariants.length > 0) {
26
+ const flatOutOfStockArray = outOfStockVariants.flat();
27
+ isOptionOutOfStock = flatOutOfStockArray.includes(
28
+ item.value_index
29
+ );
30
+ }
17
31
 
18
32
  return (
19
33
  <Tile
@@ -21,10 +35,19 @@ const TileList = props => {
21
35
  isSelected={isSelected}
22
36
  item={item}
23
37
  onClick={onSelectionChange}
38
+ isEverythingOutOfStock={isEverythingOutOfStock}
39
+ isOptionOutOfStock={isOptionOutOfStock}
24
40
  />
25
41
  );
26
42
  }),
27
- [getItemKey, selectedValue.label, items, onSelectionChange]
43
+ [
44
+ getItemKey,
45
+ selectedValue.label,
46
+ items,
47
+ onSelectionChange,
48
+ isEverythingOutOfStock,
49
+ outOfStockVariants
50
+ ]
28
51
  );
29
52
 
30
53
  return <div className={classes.root}>{tiles}</div>;
@@ -3,7 +3,6 @@
3
3
  exports[`renders correctly 1`] = `
4
4
  <div
5
5
  aria-busy="false"
6
- aria-live="polite"
7
6
  >
8
7
  <button
9
8
  disabled={false}
@@ -162,7 +162,6 @@ const ProductSort = props => {
162
162
  ref={elementRef}
163
163
  className={classes.root}
164
164
  data-cy="ProductSort-root"
165
- aria-live="polite"
166
165
  aria-busy="false"
167
166
  >
168
167
  <Button