@gem-sdk/components 2.1.35 → 2.1.36

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.
@@ -9,6 +9,7 @@ var helpers = require('../../helpers.js');
9
9
  const PRODUCT_ID_LATEST = 'latest';
10
10
  const PREFIX_PRODUCT_ID = 'gid://shopify/Product/';
11
11
  const PREFIX_PRODUCT_VARIANT_ID = 'gid://shopify/ProductVariant/';
12
+ const PREFIX_PRODUCT_OPTION_VALUE_ID = 'gid://shopify/ProductOptionValue/';
12
13
  const STATIC_PRODUCT_STATUS = 'static';
13
14
  const DYNAMIC_PRODUCT_STATUS = 'dynamic';
14
15
  const Product = ({ children, setting, styles, style, builderProps, rawChildren, advanced })=>{
@@ -24,8 +25,8 @@ const Product = ({ children, setting, styles, style, builderProps, rawChildren,
24
25
  const formatProductId = productSetting?.productId?.replace(PREFIX_PRODUCT_ID, '').toLowerCase() || PRODUCT_ID_LATEST;
25
26
  const formatVariantId = initVariantId?.replace(PREFIX_PRODUCT_VARIANT_ID, '') || '';
26
27
  const productStatus = productSetting?.productStatus ?? STATIC_PRODUCT_STATUS;
28
+ const preSelectedOptionIds = productSetting?.selectedOptions?.map((option)=>option?.valueBaseID?.replace(PREFIX_PRODUCT_OPTION_VALUE_ID, ''));
27
29
  return core.template /* liquid */ `
28
-
29
30
  {%- assign gpBkProduct = product -%}
30
31
  ${productStatus !== DYNAMIC_PRODUCT_STATUS ? `
31
32
  {%- liquid
@@ -100,7 +101,7 @@ const Product = ({ children, setting, styles, style, builderProps, rawChildren,
100
101
  {%- endif -%}
101
102
  <gp-product data-uid="${builderProps?.uid}" data-id="${builderProps?.uid}" style="${{
102
103
  ...advancedStyle
103
- }}" class="${advanced?.cssClass}" gp-context='{"productId": {{ product.id }}, "isSyncProduct": "${isSyncProduct}", "variantSelected": {{ variant | json | escape }}, "inventoryQuantity": {{ variant.inventory_quantity }}, "quantity": 1, "formId": "{{ product_form_id }}" }'
104
+ }}" class="${advanced?.cssClass}" gp-context='{"productId": {{ product.id }}, "preSelectedOptionIds": [${preSelectedOptionIds}], "isSyncProduct": "${isSyncProduct}", "variantSelected": {{ variant | json | escape }}, "inventoryQuantity": {{ variant.inventory_quantity }}, "quantity": 1, "formId": "{{ product_form_id }}" }'
104
105
  gp-data='{"variantSelected": {{ variant | json | escape }}, "quantity": 1, "productUrl":{{ product.url | json | escape }}, "productHandle":{{ product.handle | json | escape }}, "collectionUrl": {{ collection.url | json | escape }}, "collectionHandle": {{ collection.handle | json | escape }}}'>
105
106
  <product-form class="product-form">
106
107
  {%- form 'product', product, id: product_form_id, class: 'form contents', data-type: 'add-to-cart-form', autocomplete: 'off' -%}
@@ -97,15 +97,9 @@ const ProductVariants = ({ builderProps, style, styles, setting, advanced })=>{
97
97
  <div
98
98
  option-name="{{option.name | escape}}"
99
99
  class="${core.cls('gp-flex variant-inside', {
100
- 'gp-flex-col': layout?.desktop === 'vertical',
101
- 'gp-flex-row': layout?.desktop === 'horizontal',
102
- 'tablet:gp-flex-row': layout?.tablet === 'horizontal',
103
- 'tablet:gp-flex-col': layout?.tablet === 'vertical',
104
- 'mobile:gp-flex-row': layout?.mobile === 'horizontal',
105
- 'mobile:gp-flex-col': layout?.mobile === 'vertical'
106
- }, {
100
+ ...core.getLayoutClasses(layout),
107
101
  ..._function.getAlignClasses(layout, align)
108
- })} {% if hiddenPresetOptions contains option.name %} gp-hidden {% endif %}"
102
+ })}"
109
103
 
110
104
  >
111
105
  {% assign showVariantClass = 'variant-display' %}
@@ -137,15 +131,7 @@ const ProductVariants = ({ builderProps, style, styles, setting, advanced })=>{
137
131
  <div
138
132
  variant-option-name="{{option.name | escape}}"
139
133
  class="${core.cls({
140
- 'gp-justify-start': align?.desktop === 'left',
141
- 'gp-justify-center': align?.desktop === 'center',
142
- 'gp-justify-end': align?.desktop === 'right',
143
- 'tablet:gp-justify-start': align?.tablet === 'left',
144
- 'tablet:gp-justify-center': align?.tablet === 'center',
145
- 'tablet:gp-justify-end': align?.tablet === 'right',
146
- 'mobile:gp-justify-start': align?.mobile === 'left',
147
- 'mobile:gp-justify-center': align?.mobile === 'center',
148
- 'mobile:gp-justify-end': align?.mobile === 'right'
134
+ ...core.getAlignmentClasses(align)
149
135
  }, 'gp-flex gp-w-full gp-flex-wrap gp-items-center variant-option-group')}"
150
136
  style="${{
151
137
  ...core.makeStyle({
@@ -328,6 +314,10 @@ const ProductVariants = ({ builderProps, style, styles, setting, advanced })=>{
328
314
  `;
329
315
  };
330
316
  return core.template`
317
+ {%- assign total_combinations = 1 -%}
318
+ {%- for option in product.options_with_values -%}
319
+ {%- assign total_combinations = total_combinations | times: option.values.size -%}
320
+ {%- endfor -%}
331
321
  <gp-product-variants
332
322
  data-id="${uid}"
333
323
  class="${advanced?.cssClass}"
@@ -343,7 +333,10 @@ const ProductVariants = ({ builderProps, style, styles, setting, advanced })=>{
343
333
  "moneyFormat": {{shop.money_format | json | escape}},
344
334
  "productId": {{product.id | json | escape}},
345
335
  "productUrl": {{product.url | json | escape}},
346
- "displayState":${JSON.stringify(advancedDisplay)}
336
+ "productHandle": {{product.handle | json | escape}},
337
+ "displayState": ${JSON.stringify(advancedDisplay)},
338
+ "totalVariantCombinations": {{total_combinations}},
339
+ "firstAvailableVariant": {{product.selected_or_first_available_variant | json | escape}}
347
340
  }
348
341
  '>
349
342
  {%- assign options = product.options_with_values -%}
@@ -156,6 +156,7 @@ const BaseVariant = ({ optionTransform, optionTypography, optionBgColor, optionT
156
156
  option-data="{{option.name | escape}}"
157
157
  option-value="{{value | escape}}"
158
158
  option-position="{{option.position}}"
159
+ data-gp-option-available="{{value.available}}"
159
160
  option-type="${type || 'rectangle_list'}"
160
161
  data-disabled="{%- if option_disabled == true -%} disabled {%- endif -%}"
161
162
  data-hidden='true'
@@ -18,6 +18,15 @@ const DropdownVariant = ({ variantGroup, blankText, swatchAutoWidth, swatchHeigh
18
18
  };
19
19
  const appendTypoClass = core.composeTypographyClassName(optionTypo, optionTypography);
20
20
  const appendTypoStyle = core.composeTypographyStyle(optionTypo, optionTypography);
21
+ const composeSelectOptionAttrs = `
22
+ option-data="{{option.name | escape}}"
23
+ option-value="{{value | escape}}"
24
+ data-gp-option-value-id="{{value.id}}"
25
+ data-gp-option-available="{{value.available}}"
26
+ value="{{value | escape}}"
27
+ class="option-value-wrapper"
28
+ key="{{value | escape}}"
29
+ `;
21
30
  return core.template /* liquid */ `
22
31
  <select
23
32
  aria-label={{option.name | escape}}
@@ -73,37 +82,42 @@ const DropdownVariant = ({ variantGroup, blankText, swatchAutoWidth, swatchHeigh
73
82
  -%}
74
83
  ${isSoldOutMark ? `{%- if option_disabled == true -%}
75
84
  {%- if value == selectedValue -%}
76
- <option disabled ${!hasPreSelected ? '' : 'selected'} option-data="{{option.name | escape}}"
85
+ <option disabled ${!hasPreSelected ? '' : 'selected'}
77
86
  option-position="{{option.position}}"
78
- option-value="{{value | escape}}" value="{{value | escape}}" class="option-value-wrapper" key="{{value | escape}}">
87
+ ${composeSelectOptionAttrs}>
79
88
  {{value}}
80
89
  </option>
81
90
  {% else %}
82
- <option disabled option-data="{{option.name | escape}}"
83
- option-value="{{value | escape}}" value="{{value | escape}}" class="option-value-wrapper" key="{{value | escape}}">
91
+ <option
92
+ disabled
93
+ ${composeSelectOptionAttrs}>
84
94
  {{value}}
85
95
  </option>
86
96
  {%- endif -%}
87
97
  {%- else -%}
88
98
  {%- if value == selectedValue -%}
89
- <option ${!hasPreSelected ? '' : 'selected'} option-data="{{option.name | escape}}"
90
- option-value="{{value | escape}}" option-position="{{option.position}}" class="option-value-wrapper" value="{{value | escape}}" key="{{value | escape}}">
99
+ <option ${!hasPreSelected ? '' : 'selected'}
100
+ option-position="{{option.position}}"
101
+ ${composeSelectOptionAttrs}>
91
102
  {{value}}
92
103
  </option>
93
104
  {% else %}
94
- <option option-data="{{option.name | escape}}"
95
- option-value="{{value | escape}}" option-position="{{option.position}}" class="option-value-wrapper" value="{{value | escape}}" key="{{value | escape}}">
105
+ <option
106
+ ${composeSelectOptionAttrs}
107
+ option-position="{{option.position}}">
96
108
  {{value}}
97
109
  </option>
98
110
  {%- endif -%}
99
111
  {%- endif -%}` : `{%- if value == selectedValue -%}
100
- <option ${!hasPreSelected ? '' : 'selected'} option-data="{{option.name | escape}}"
101
- option-value="{{value | escape}}" option-position="{{option.position}}" class="option-value-wrapper" value="{{value | escape}}" key="{{value | escape}}">
112
+ <option ${!hasPreSelected ? '' : 'selected'}
113
+ ${composeSelectOptionAttrs}
114
+ option-position="{{option.position}}">
102
115
  {{value}}
103
116
  </option>
104
117
  {% else %}
105
- <option option-data="{{option.name | escape}}"
106
- option-value="{{value | escape}}" option-position="{{option.position}}" class="option-value-wrapper" value="{{value | escape}}" key="{{value | escape}}">
118
+ <option
119
+ ${composeSelectOptionAttrs}
120
+ option-position="{{option.position}}">
107
121
  {{value}}
108
122
  </option>
109
123
  {%- endif -%}`}
@@ -3,9 +3,9 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var core = require('@gem-sdk/core');
6
- var helpers = require('../../../../helpers.js');
6
+ var index = require('./combine/index.js');
7
7
 
8
- const DropdownVariant = ({ price, blankText, optionTypography, optionBgColor, optionTextColor, optionRounded, optionShadow, optionHasShadow, optionBorder, optionTransform, hasPreSelected, optionTypo, combineWidth, combineHeight, soldOutStyle })=>{
8
+ const DropdownVariant = ({ price: hasPrice, blankText, optionTypography, optionBgColor, optionTextColor, optionRounded, optionShadow, optionHasShadow, optionBorder, optionTransform, hasPreSelected, optionTypo, combineWidth, combineHeight, soldOutStyle })=>{
9
9
  const swatchWidthResponsive = core.makeStyleResponsive('w', core.makeWidth(combineWidth));
10
10
  const getCustomCSSActiveState = ()=>{
11
11
  return core.makeStyle({
@@ -27,7 +27,6 @@ const DropdownVariant = ({ price, blankText, optionTypography, optionBgColor, op
27
27
  option-data="{{option.name}}"
28
28
  option-type="{{optionType}}"
29
29
  class="${core.cls('gp-truncate gp-bg-auto gp-pl-4 gp-pr-6 gp-outline-none dropdown-option-item', core.handleConvertClassColor(optionBorder), appendTypoClass, core.getGlobalColorStateClass('text', optionTextColor), core.getGlobalColorStateClass('bg', optionBgColor), 'gp-outline-none', 'gp-shadow-none')}"
30
-
31
30
  style="${{
32
31
  ...core.getStyleShadowState(optionShadow, 'box-shadow', optionHasShadow),
33
32
  ...getCustomCSSActiveState(),
@@ -49,40 +48,8 @@ const DropdownVariant = ({ price, blankText, optionTypography, optionBgColor, op
49
48
  'background-position': 'right 16px center'
50
49
  }}"
51
50
  >
52
- ${!hasPreSelected ? `<option value="blank" selected>${blankText || helpers.getStaticLocale('ProductVariants', 'please_select')}</option>` : ''}
53
- ${`{%- for variantItem in variants -%}
54
- ${isSoldOutMark ? `{%- if variantItem.available == false -%}
55
- {%- if variantItem.id == variant.id -%}
56
- <option origin-price="{{variantItem.price}}" disabled ${!hasPreSelected ? '' : 'selected'} value="{{variantItem.id}}" key="{{variantItem.id}}">
57
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
58
- </option>
59
- {% else %}
60
- <option origin-price="{{variantItem.price}}" disabled value="{{variantItem.id}}" key="{{variantItem.id}}">
61
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
62
- </option>
63
- {%- endif -%}
64
- {%- else -%}
65
- {%- if variantItem.id == variant.id -%}
66
- <option origin-price="{{variantItem.price}}" ${!hasPreSelected ? '' : 'selected'} value="{{variantItem.id}}" key="{{variantItem.id}}">
67
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
68
- </option>
69
- {% else %}
70
- <option origin-price="{{variantItem.price}}" value="{{variantItem.id}}" key="{{variantItem.id}}">
71
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
72
- </option>
73
- {%- endif -%}
74
- {%- endif -%}` : `{%- if variantItem.id == variant.id -%}
75
- <option origin-price="{{variantItem.price}}" ${!hasPreSelected ? '' : 'selected'} value="{{variantItem.id}}" key="{{variantItem.id}}">
76
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
77
- </option>
78
- {% else %}
79
- <option origin-price="{{variantItem.price}}" value="{{variantItem.id}}" key="{{variantItem.id}}">
80
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
81
- </option>
82
- {%- endif -%}`}
83
-
84
- {%- endfor -%}
85
- `}
51
+ ${index.renderBlankOption(hasPreSelected, blankText)}
52
+ ${index.renderCombineVariants(isSoldOutMark, hasPreSelected, hasPrice)}
86
53
  </select>
87
54
  `;
88
55
  };
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ var helpers = require('../../../../../helpers.js');
4
+
5
+ const renderCombineVariants = (isSoldOutMark, hasPreSelected, enablePrice)=>{
6
+ const hasPrice = enablePrice ? '- {{variantItem.price | money}}' : '';
7
+ const optionAttrs = 'origin-price="{{variantItem.price}}" value="{{variantItem.id}}" key="{{variantItem.id}}"';
8
+ return `${`{%- for variantItem in variants -%}
9
+ ${isSoldOutMark ? `{%- if variantItem.available == false -%}
10
+ {%- if variantItem.id == variant.id -%}
11
+ <option origin-price="{{variantItem.price}}" disabled ${hasPreSelected ? 'selected' : ''} value="{{variantItem.id}}" key="{{variantItem.id}}">
12
+ {{variantItem.title}} ${hasPrice} : ''}
13
+ </option>
14
+ {% else %}
15
+ <option ${optionAttrs} disabled>
16
+ {{variantItem.title}} ${hasPrice}
17
+ </option>
18
+ {%- endif -%}
19
+ {%- else -%}
20
+ {%- if variantItem.id == variant.id -%}
21
+ <option origin-price="{{variantItem.price}}" ${hasPreSelected ? 'selected' : ''} value="{{variantItem.id}}" key="{{variantItem.id}}">
22
+ {{variantItem.title}} ${hasPrice}
23
+ </option>
24
+ {% else %}
25
+ <option ${optionAttrs}>
26
+ {{variantItem.title}} ${hasPrice}
27
+ </option>
28
+ {%- endif -%}
29
+ {%- endif -%}` : `{%- if variantItem.id == variant.id -%}
30
+ <option origin-price="{{variantItem.price}}" ${hasPreSelected ? 'selected' : ''} value="{{variantItem.id}}" key="{{variantItem.id}}">
31
+ {{variantItem.title}} ${hasPrice}
32
+ </option>
33
+ {% else %}
34
+ <option ${optionAttrs}>
35
+ {{variantItem.title}} ${hasPrice}
36
+ </option>
37
+ {%- endif -%}`}
38
+
39
+ {%- endfor -%}
40
+ `}`;
41
+ };
42
+ const renderBlankOption = (hasPreSelected, blankText)=>{
43
+ return !hasPreSelected ? `<option value="blank" selected>${blankText ?? helpers.getStaticLocale('ProductVariants', 'please_select')}</option>` : '';
44
+ };
45
+
46
+ exports.renderBlankOption = renderBlankOption;
47
+ exports.renderCombineVariants = renderCombineVariants;
@@ -5,6 +5,7 @@ import { getStaticLocale, getSettingPreloadData } from '../../helpers.js';
5
5
  const PRODUCT_ID_LATEST = 'latest';
6
6
  const PREFIX_PRODUCT_ID = 'gid://shopify/Product/';
7
7
  const PREFIX_PRODUCT_VARIANT_ID = 'gid://shopify/ProductVariant/';
8
+ const PREFIX_PRODUCT_OPTION_VALUE_ID = 'gid://shopify/ProductOptionValue/';
8
9
  const STATIC_PRODUCT_STATUS = 'static';
9
10
  const DYNAMIC_PRODUCT_STATUS = 'dynamic';
10
11
  const Product = ({ children, setting, styles, style, builderProps, rawChildren, advanced })=>{
@@ -20,8 +21,8 @@ const Product = ({ children, setting, styles, style, builderProps, rawChildren,
20
21
  const formatProductId = productSetting?.productId?.replace(PREFIX_PRODUCT_ID, '').toLowerCase() || PRODUCT_ID_LATEST;
21
22
  const formatVariantId = initVariantId?.replace(PREFIX_PRODUCT_VARIANT_ID, '') || '';
22
23
  const productStatus = productSetting?.productStatus ?? STATIC_PRODUCT_STATUS;
24
+ const preSelectedOptionIds = productSetting?.selectedOptions?.map((option)=>option?.valueBaseID?.replace(PREFIX_PRODUCT_OPTION_VALUE_ID, ''));
23
25
  return template /* liquid */ `
24
-
25
26
  {%- assign gpBkProduct = product -%}
26
27
  ${productStatus !== DYNAMIC_PRODUCT_STATUS ? `
27
28
  {%- liquid
@@ -96,7 +97,7 @@ const Product = ({ children, setting, styles, style, builderProps, rawChildren,
96
97
  {%- endif -%}
97
98
  <gp-product data-uid="${builderProps?.uid}" data-id="${builderProps?.uid}" style="${{
98
99
  ...advancedStyle
99
- }}" class="${advanced?.cssClass}" gp-context='{"productId": {{ product.id }}, "isSyncProduct": "${isSyncProduct}", "variantSelected": {{ variant | json | escape }}, "inventoryQuantity": {{ variant.inventory_quantity }}, "quantity": 1, "formId": "{{ product_form_id }}" }'
100
+ }}" class="${advanced?.cssClass}" gp-context='{"productId": {{ product.id }}, "preSelectedOptionIds": [${preSelectedOptionIds}], "isSyncProduct": "${isSyncProduct}", "variantSelected": {{ variant | json | escape }}, "inventoryQuantity": {{ variant.inventory_quantity }}, "quantity": 1, "formId": "{{ product_form_id }}" }'
100
101
  gp-data='{"variantSelected": {{ variant | json | escape }}, "quantity": 1, "productUrl":{{ product.url | json | escape }}, "productHandle":{{ product.handle | json | escape }}, "collectionUrl": {{ collection.url | json | escape }}, "collectionHandle": {{ collection.handle | json | escape }}}'>
101
102
  <product-form class="product-form">
102
103
  {%- form 'product', product, id: product_form_id, class: 'form contents', data-type: 'add-to-cart-form', autocomplete: 'off' -%}
@@ -1,4 +1,4 @@
1
- import { makeStyleResponsive, makeWidth, composeMemo, composeTypographyClassName, template, optionLayoutStyle, RenderIf, isLocalEnv, baseAssetURL, cls, makeStyle, getResponsiveValueByScreen } from '@gem-sdk/core';
1
+ import { makeStyleResponsive, makeWidth, composeMemo, composeTypographyClassName, template, optionLayoutStyle, RenderIf, isLocalEnv, baseAssetURL, cls, getLayoutClasses, getAlignmentClasses, makeStyle, getResponsiveValueByScreen } from '@gem-sdk/core';
2
2
  import Text from '../../../text/components/Text.liquid.js';
3
3
  import VariantItem from './variants/index.liquid.js';
4
4
  import DropdownVariant from './variants/Dropdown.liquid.js';
@@ -93,15 +93,9 @@ const ProductVariants = ({ builderProps, style, styles, setting, advanced })=>{
93
93
  <div
94
94
  option-name="{{option.name | escape}}"
95
95
  class="${cls('gp-flex variant-inside', {
96
- 'gp-flex-col': layout?.desktop === 'vertical',
97
- 'gp-flex-row': layout?.desktop === 'horizontal',
98
- 'tablet:gp-flex-row': layout?.tablet === 'horizontal',
99
- 'tablet:gp-flex-col': layout?.tablet === 'vertical',
100
- 'mobile:gp-flex-row': layout?.mobile === 'horizontal',
101
- 'mobile:gp-flex-col': layout?.mobile === 'vertical'
102
- }, {
96
+ ...getLayoutClasses(layout),
103
97
  ...getAlignClasses(layout, align)
104
- })} {% if hiddenPresetOptions contains option.name %} gp-hidden {% endif %}"
98
+ })}"
105
99
 
106
100
  >
107
101
  {% assign showVariantClass = 'variant-display' %}
@@ -133,15 +127,7 @@ const ProductVariants = ({ builderProps, style, styles, setting, advanced })=>{
133
127
  <div
134
128
  variant-option-name="{{option.name | escape}}"
135
129
  class="${cls({
136
- 'gp-justify-start': align?.desktop === 'left',
137
- 'gp-justify-center': align?.desktop === 'center',
138
- 'gp-justify-end': align?.desktop === 'right',
139
- 'tablet:gp-justify-start': align?.tablet === 'left',
140
- 'tablet:gp-justify-center': align?.tablet === 'center',
141
- 'tablet:gp-justify-end': align?.tablet === 'right',
142
- 'mobile:gp-justify-start': align?.mobile === 'left',
143
- 'mobile:gp-justify-center': align?.mobile === 'center',
144
- 'mobile:gp-justify-end': align?.mobile === 'right'
130
+ ...getAlignmentClasses(align)
145
131
  }, 'gp-flex gp-w-full gp-flex-wrap gp-items-center variant-option-group')}"
146
132
  style="${{
147
133
  ...makeStyle({
@@ -324,6 +310,10 @@ const ProductVariants = ({ builderProps, style, styles, setting, advanced })=>{
324
310
  `;
325
311
  };
326
312
  return template`
313
+ {%- assign total_combinations = 1 -%}
314
+ {%- for option in product.options_with_values -%}
315
+ {%- assign total_combinations = total_combinations | times: option.values.size -%}
316
+ {%- endfor -%}
327
317
  <gp-product-variants
328
318
  data-id="${uid}"
329
319
  class="${advanced?.cssClass}"
@@ -339,7 +329,10 @@ const ProductVariants = ({ builderProps, style, styles, setting, advanced })=>{
339
329
  "moneyFormat": {{shop.money_format | json | escape}},
340
330
  "productId": {{product.id | json | escape}},
341
331
  "productUrl": {{product.url | json | escape}},
342
- "displayState":${JSON.stringify(advancedDisplay)}
332
+ "productHandle": {{product.handle | json | escape}},
333
+ "displayState": ${JSON.stringify(advancedDisplay)},
334
+ "totalVariantCombinations": {{total_combinations}},
335
+ "firstAvailableVariant": {{product.selected_or_first_available_variant | json | escape}}
343
336
  }
344
337
  '>
345
338
  {%- assign options = product.options_with_values -%}
@@ -152,6 +152,7 @@ const BaseVariant = ({ optionTransform, optionTypography, optionBgColor, optionT
152
152
  option-data="{{option.name | escape}}"
153
153
  option-value="{{value | escape}}"
154
154
  option-position="{{option.position}}"
155
+ data-gp-option-available="{{value.available}}"
155
156
  option-type="${type || 'rectangle_list'}"
156
157
  data-disabled="{%- if option_disabled == true -%} disabled {%- endif -%}"
157
158
  data-hidden='true'
@@ -14,6 +14,15 @@ const DropdownVariant = ({ variantGroup, blankText, swatchAutoWidth, swatchHeigh
14
14
  };
15
15
  const appendTypoClass = composeTypographyClassName(optionTypo, optionTypography);
16
16
  const appendTypoStyle = composeTypographyStyle(optionTypo, optionTypography);
17
+ const composeSelectOptionAttrs = `
18
+ option-data="{{option.name | escape}}"
19
+ option-value="{{value | escape}}"
20
+ data-gp-option-value-id="{{value.id}}"
21
+ data-gp-option-available="{{value.available}}"
22
+ value="{{value | escape}}"
23
+ class="option-value-wrapper"
24
+ key="{{value | escape}}"
25
+ `;
17
26
  return template /* liquid */ `
18
27
  <select
19
28
  aria-label={{option.name | escape}}
@@ -69,37 +78,42 @@ const DropdownVariant = ({ variantGroup, blankText, swatchAutoWidth, swatchHeigh
69
78
  -%}
70
79
  ${isSoldOutMark ? `{%- if option_disabled == true -%}
71
80
  {%- if value == selectedValue -%}
72
- <option disabled ${!hasPreSelected ? '' : 'selected'} option-data="{{option.name | escape}}"
81
+ <option disabled ${!hasPreSelected ? '' : 'selected'}
73
82
  option-position="{{option.position}}"
74
- option-value="{{value | escape}}" value="{{value | escape}}" class="option-value-wrapper" key="{{value | escape}}">
83
+ ${composeSelectOptionAttrs}>
75
84
  {{value}}
76
85
  </option>
77
86
  {% else %}
78
- <option disabled option-data="{{option.name | escape}}"
79
- option-value="{{value | escape}}" value="{{value | escape}}" class="option-value-wrapper" key="{{value | escape}}">
87
+ <option
88
+ disabled
89
+ ${composeSelectOptionAttrs}>
80
90
  {{value}}
81
91
  </option>
82
92
  {%- endif -%}
83
93
  {%- else -%}
84
94
  {%- if value == selectedValue -%}
85
- <option ${!hasPreSelected ? '' : 'selected'} option-data="{{option.name | escape}}"
86
- option-value="{{value | escape}}" option-position="{{option.position}}" class="option-value-wrapper" value="{{value | escape}}" key="{{value | escape}}">
95
+ <option ${!hasPreSelected ? '' : 'selected'}
96
+ option-position="{{option.position}}"
97
+ ${composeSelectOptionAttrs}>
87
98
  {{value}}
88
99
  </option>
89
100
  {% else %}
90
- <option option-data="{{option.name | escape}}"
91
- option-value="{{value | escape}}" option-position="{{option.position}}" class="option-value-wrapper" value="{{value | escape}}" key="{{value | escape}}">
101
+ <option
102
+ ${composeSelectOptionAttrs}
103
+ option-position="{{option.position}}">
92
104
  {{value}}
93
105
  </option>
94
106
  {%- endif -%}
95
107
  {%- endif -%}` : `{%- if value == selectedValue -%}
96
- <option ${!hasPreSelected ? '' : 'selected'} option-data="{{option.name | escape}}"
97
- option-value="{{value | escape}}" option-position="{{option.position}}" class="option-value-wrapper" value="{{value | escape}}" key="{{value | escape}}">
108
+ <option ${!hasPreSelected ? '' : 'selected'}
109
+ ${composeSelectOptionAttrs}
110
+ option-position="{{option.position}}">
98
111
  {{value}}
99
112
  </option>
100
113
  {% else %}
101
- <option option-data="{{option.name | escape}}"
102
- option-value="{{value | escape}}" option-position="{{option.position}}" class="option-value-wrapper" value="{{value | escape}}" key="{{value | escape}}">
114
+ <option
115
+ ${composeSelectOptionAttrs}
116
+ option-position="{{option.position}}">
103
117
  {{value}}
104
118
  </option>
105
119
  {%- endif -%}`}
@@ -1,7 +1,7 @@
1
1
  import { makeStyleResponsive, makeWidth, composeTypographyClassName, composeTypographyStyle, template, cls, handleConvertClassColor, getGlobalColorStateClass, getStyleShadowState, makeStyle, getGlobalColorStateStyle, handleConvertBorderStyle, handleConvertBorderWidth, handleConvertBorderColor, composeRadius, getSingleColorVariable } from '@gem-sdk/core';
2
- import { getStaticLocale } from '../../../../helpers.js';
2
+ import { renderBlankOption, renderCombineVariants } from './combine/index.js';
3
3
 
4
- const DropdownVariant = ({ price, blankText, optionTypography, optionBgColor, optionTextColor, optionRounded, optionShadow, optionHasShadow, optionBorder, optionTransform, hasPreSelected, optionTypo, combineWidth, combineHeight, soldOutStyle })=>{
4
+ const DropdownVariant = ({ price: hasPrice, blankText, optionTypography, optionBgColor, optionTextColor, optionRounded, optionShadow, optionHasShadow, optionBorder, optionTransform, hasPreSelected, optionTypo, combineWidth, combineHeight, soldOutStyle })=>{
5
5
  const swatchWidthResponsive = makeStyleResponsive('w', makeWidth(combineWidth));
6
6
  const getCustomCSSActiveState = ()=>{
7
7
  return makeStyle({
@@ -23,7 +23,6 @@ const DropdownVariant = ({ price, blankText, optionTypography, optionBgColor, op
23
23
  option-data="{{option.name}}"
24
24
  option-type="{{optionType}}"
25
25
  class="${cls('gp-truncate gp-bg-auto gp-pl-4 gp-pr-6 gp-outline-none dropdown-option-item', handleConvertClassColor(optionBorder), appendTypoClass, getGlobalColorStateClass('text', optionTextColor), getGlobalColorStateClass('bg', optionBgColor), 'gp-outline-none', 'gp-shadow-none')}"
26
-
27
26
  style="${{
28
27
  ...getStyleShadowState(optionShadow, 'box-shadow', optionHasShadow),
29
28
  ...getCustomCSSActiveState(),
@@ -45,40 +44,8 @@ const DropdownVariant = ({ price, blankText, optionTypography, optionBgColor, op
45
44
  'background-position': 'right 16px center'
46
45
  }}"
47
46
  >
48
- ${!hasPreSelected ? `<option value="blank" selected>${blankText || getStaticLocale('ProductVariants', 'please_select')}</option>` : ''}
49
- ${`{%- for variantItem in variants -%}
50
- ${isSoldOutMark ? `{%- if variantItem.available == false -%}
51
- {%- if variantItem.id == variant.id -%}
52
- <option origin-price="{{variantItem.price}}" disabled ${!hasPreSelected ? '' : 'selected'} value="{{variantItem.id}}" key="{{variantItem.id}}">
53
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
54
- </option>
55
- {% else %}
56
- <option origin-price="{{variantItem.price}}" disabled value="{{variantItem.id}}" key="{{variantItem.id}}">
57
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
58
- </option>
59
- {%- endif -%}
60
- {%- else -%}
61
- {%- if variantItem.id == variant.id -%}
62
- <option origin-price="{{variantItem.price}}" ${!hasPreSelected ? '' : 'selected'} value="{{variantItem.id}}" key="{{variantItem.id}}">
63
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
64
- </option>
65
- {% else %}
66
- <option origin-price="{{variantItem.price}}" value="{{variantItem.id}}" key="{{variantItem.id}}">
67
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
68
- </option>
69
- {%- endif -%}
70
- {%- endif -%}` : `{%- if variantItem.id == variant.id -%}
71
- <option origin-price="{{variantItem.price}}" ${!hasPreSelected ? '' : 'selected'} value="{{variantItem.id}}" key="{{variantItem.id}}">
72
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
73
- </option>
74
- {% else %}
75
- <option origin-price="{{variantItem.price}}" value="{{variantItem.id}}" key="{{variantItem.id}}">
76
- {{variantItem.title}} ${price ? '- {{variantItem.price | money}}' : ''}
77
- </option>
78
- {%- endif -%}`}
79
-
80
- {%- endfor -%}
81
- `}
47
+ ${renderBlankOption(hasPreSelected, blankText)}
48
+ ${renderCombineVariants(isSoldOutMark, hasPreSelected, hasPrice)}
82
49
  </select>
83
50
  `;
84
51
  };
@@ -0,0 +1,44 @@
1
+ import { getStaticLocale } from '../../../../../helpers.js';
2
+
3
+ const renderCombineVariants = (isSoldOutMark, hasPreSelected, enablePrice)=>{
4
+ const hasPrice = enablePrice ? '- {{variantItem.price | money}}' : '';
5
+ const optionAttrs = 'origin-price="{{variantItem.price}}" value="{{variantItem.id}}" key="{{variantItem.id}}"';
6
+ return `${`{%- for variantItem in variants -%}
7
+ ${isSoldOutMark ? `{%- if variantItem.available == false -%}
8
+ {%- if variantItem.id == variant.id -%}
9
+ <option origin-price="{{variantItem.price}}" disabled ${hasPreSelected ? 'selected' : ''} value="{{variantItem.id}}" key="{{variantItem.id}}">
10
+ {{variantItem.title}} ${hasPrice} : ''}
11
+ </option>
12
+ {% else %}
13
+ <option ${optionAttrs} disabled>
14
+ {{variantItem.title}} ${hasPrice}
15
+ </option>
16
+ {%- endif -%}
17
+ {%- else -%}
18
+ {%- if variantItem.id == variant.id -%}
19
+ <option origin-price="{{variantItem.price}}" ${hasPreSelected ? 'selected' : ''} value="{{variantItem.id}}" key="{{variantItem.id}}">
20
+ {{variantItem.title}} ${hasPrice}
21
+ </option>
22
+ {% else %}
23
+ <option ${optionAttrs}>
24
+ {{variantItem.title}} ${hasPrice}
25
+ </option>
26
+ {%- endif -%}
27
+ {%- endif -%}` : `{%- if variantItem.id == variant.id -%}
28
+ <option origin-price="{{variantItem.price}}" ${hasPreSelected ? 'selected' : ''} value="{{variantItem.id}}" key="{{variantItem.id}}">
29
+ {{variantItem.title}} ${hasPrice}
30
+ </option>
31
+ {% else %}
32
+ <option ${optionAttrs}>
33
+ {{variantItem.title}} ${hasPrice}
34
+ </option>
35
+ {%- endif -%}`}
36
+
37
+ {%- endfor -%}
38
+ `}`;
39
+ };
40
+ const renderBlankOption = (hasPreSelected, blankText)=>{
41
+ return !hasPreSelected ? `<option value="blank" selected>${blankText ?? getStaticLocale('ProductVariants', 'please_select')}</option>` : '';
42
+ };
43
+
44
+ export { renderBlankOption, renderCombineVariants };
@@ -1361,6 +1361,12 @@ type ProductSetting = {
1361
1361
  initialVariantId?: string;
1362
1362
  initialVariantBaseId?: string;
1363
1363
  productHandle?: string;
1364
+ selectedOptions?: {
1365
+ name: string;
1366
+ value: string;
1367
+ optionType: string;
1368
+ valueBaseID: string;
1369
+ }[];
1364
1370
  };
1365
1371
  discountType?: 'PERCENTAGE' | 'FIXED_AMOUNT';
1366
1372
  discountValue?: number;
@@ -5592,6 +5598,12 @@ declare const Product: ({ children, setting, styles, style, builderProps, rawChi
5592
5598
  initialVariantId?: string | undefined;
5593
5599
  initialVariantBaseId?: string | undefined;
5594
5600
  productHandle?: string | undefined;
5601
+ selectedOptions?: {
5602
+ name: string;
5603
+ value: string;
5604
+ optionType: string;
5605
+ valueBaseID: string;
5606
+ }[] | undefined;
5595
5607
  } | undefined;
5596
5608
  discountType?: "FIXED_AMOUNT" | "PERCENTAGE" | undefined;
5597
5609
  discountValue?: number | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gem-sdk/components",
3
- "version": "2.1.35",
3
+ "version": "2.1.36",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "main": "dist/cjs/index.js",
@@ -21,7 +21,7 @@
21
21
  "format": "prettier --write \"./src/**/*.{ts,tsx}\""
22
22
  },
23
23
  "devDependencies": {
24
- "@gem-sdk/core": "2.1.33",
24
+ "@gem-sdk/core": "2.1.36",
25
25
  "@gem-sdk/styles": "2.1.31",
26
26
  "@types/react-transition-group": "^4.4.5"
27
27
  },