@foxy.io/elements 1.14.0-beta.7 → 1.14.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 (107) hide show
  1. package/dist/cdn/foxy-access-recovery-form.js +1 -1
  2. package/dist/cdn/foxy-address-card.js +1 -1
  3. package/dist/cdn/foxy-address-form.js +1 -1
  4. package/dist/cdn/foxy-applied-tax-card.js +1 -1
  5. package/dist/cdn/foxy-attribute-card.js +1 -1
  6. package/dist/cdn/foxy-attribute-form.js +1 -1
  7. package/dist/cdn/foxy-cancellation-form.js +1 -1
  8. package/dist/cdn/foxy-collection-page.js +1 -1
  9. package/dist/cdn/foxy-collection-pages.js +1 -1
  10. package/dist/cdn/foxy-custom-field-card.js +1 -1
  11. package/dist/cdn/foxy-custom-field-form.js +1 -1
  12. package/dist/cdn/foxy-customer-card.js +1 -1
  13. package/dist/cdn/foxy-customer-form.js +1 -1
  14. package/dist/cdn/foxy-customer-portal-settings.js +17 -17
  15. package/dist/cdn/foxy-customer-portal.js +18 -15
  16. package/dist/cdn/foxy-customer.js +4 -4
  17. package/dist/cdn/foxy-customers-table.js +1 -1
  18. package/dist/cdn/foxy-discount-card.js +1 -1
  19. package/dist/cdn/foxy-donation.js +1 -1
  20. package/dist/cdn/foxy-email-template-form.js +1 -1
  21. package/dist/cdn/foxy-error-entry-card.js +1 -1
  22. package/dist/cdn/foxy-form-dialog.js +1 -1
  23. package/dist/cdn/foxy-i18n.js +1 -1
  24. package/dist/cdn/foxy-items-form.js +1 -1
  25. package/dist/cdn/foxy-payment-card.js +1 -1
  26. package/dist/cdn/foxy-payment-method-card.js +1 -1
  27. package/dist/cdn/foxy-query-builder.js +2 -2
  28. package/dist/cdn/foxy-sign-in-form.js +1 -1
  29. package/dist/cdn/foxy-spinner.js +1 -1
  30. package/dist/cdn/foxy-subscription-card.js +1 -1
  31. package/dist/cdn/foxy-subscription-form.js +3 -3
  32. package/dist/cdn/foxy-subscriptions-table.js +1 -1
  33. package/dist/cdn/foxy-table.js +1 -1
  34. package/dist/cdn/foxy-tax-card.js +1 -1
  35. package/dist/cdn/foxy-tax-form.js +1 -1
  36. package/dist/cdn/foxy-template-config-form.js +1 -14
  37. package/dist/cdn/foxy-template-form.js +1 -1
  38. package/dist/cdn/foxy-transaction-card.js +1 -1
  39. package/dist/cdn/foxy-transactions-table.js +1 -1
  40. package/dist/cdn/foxy-user-form.js +1 -1
  41. package/dist/cdn/foxy-users-table.js +1 -1
  42. package/dist/cdn/shared-07134f93.js +14 -0
  43. package/dist/cdn/{shared-691da586.js → shared-07abcd7b.js} +1 -1
  44. package/dist/cdn/{shared-6f7f752e.js → shared-322e60b1.js} +1 -1
  45. package/dist/cdn/shared-35dbd2c5.js +1 -0
  46. package/dist/cdn/{shared-1bafffd0.js → shared-5c8b531d.js} +1 -1
  47. package/dist/cdn/{shared-6ecbc785.js → shared-5f54e916.js} +1 -1
  48. package/dist/cdn/{shared-50c7a176.js → shared-7a42073a.js} +1 -1
  49. package/dist/cdn/{shared-c66e9946.js → shared-8a7bee0d.js} +1 -1
  50. package/dist/cdn/{shared-4d3c7828.js → shared-91e768be.js} +1 -1
  51. package/dist/cdn/shared-9a40309d.js +1 -0
  52. package/dist/cdn/{shared-7629a1a5.js → shared-b5147166.js} +1 -1
  53. package/dist/cdn/{shared-16e28f3b.js → shared-bc2bfe52.js} +1 -1
  54. package/dist/cdn/{shared-0ba88744.js → shared-ce1da35d.js} +1 -1
  55. package/dist/cdn/{shared-09feabf8.js → shared-d01d809a.js} +1 -1
  56. package/dist/cdn/{shared-8edee4e1.js → shared-d8ffb279.js} +7 -7
  57. package/dist/cdn/{shared-a6c047b1.js → shared-e5cbf291.js} +1 -1
  58. package/dist/cdn/shared-f1dc1c6c.js +1 -0
  59. package/dist/cdn/translations/shared/de.json +94 -0
  60. package/dist/cdn/translations/shared/en.json +83 -83
  61. package/dist/cdn/translations/shared/es.json +93 -0
  62. package/dist/elements/private/Checkbox/Checkbox.d.ts +3 -1
  63. package/dist/elements/private/Checkbox/Checkbox.js +43 -14
  64. package/dist/elements/private/Checkbox/Checkbox.js.map +1 -1
  65. package/dist/elements/private/Choice/Choice.js +7 -5
  66. package/dist/elements/private/Choice/Choice.js.map +1 -1
  67. package/dist/elements/public/CustomerPortal/InternalCustomerPortalLink.d.ts +1 -0
  68. package/dist/elements/public/CustomerPortal/InternalCustomerPortalLink.js +17 -8
  69. package/dist/elements/public/CustomerPortal/InternalCustomerPortalLink.js.map +1 -1
  70. package/dist/elements/public/CustomerPortal/InternalCustomerPortalLoggedInView.js +19 -6
  71. package/dist/elements/public/CustomerPortal/InternalCustomerPortalLoggedInView.js.map +1 -1
  72. package/dist/elements/public/CustomerPortal/InternalCustomerPortalSubscriptions.js +11 -3
  73. package/dist/elements/public/CustomerPortal/InternalCustomerPortalSubscriptions.js.map +1 -1
  74. package/dist/elements/public/EmailTemplateForm/EmailTemplateForm.d.ts +24 -2
  75. package/dist/elements/public/EmailTemplateForm/EmailTemplateForm.js +89 -50
  76. package/dist/elements/public/EmailTemplateForm/EmailTemplateForm.js.map +1 -1
  77. package/dist/elements/public/EmailTemplateForm/types.d.ts +14 -0
  78. package/dist/elements/public/EmailTemplateForm/types.js.map +1 -1
  79. package/dist/elements/public/ItemsForm/private/Picture.d.ts +1 -0
  80. package/dist/elements/public/ItemsForm/private/Picture.js +2 -0
  81. package/dist/elements/public/ItemsForm/private/Picture.js.map +1 -1
  82. package/dist/elements/public/SubscriptionForm/SubscriptionForm.js +12 -4
  83. package/dist/elements/public/SubscriptionForm/SubscriptionForm.js.map +1 -1
  84. package/dist/elements/public/TemplateConfigForm/CountriesList.d.ts +2 -4
  85. package/dist/elements/public/TemplateConfigForm/CountriesList.js +29 -21
  86. package/dist/elements/public/TemplateConfigForm/CountriesList.js.map +1 -1
  87. package/dist/elements/public/TemplateConfigForm/CountryCard.d.ts +1 -1
  88. package/dist/elements/public/TemplateConfigForm/CountryCard.js +53 -18
  89. package/dist/elements/public/TemplateConfigForm/CountryCard.js.map +1 -1
  90. package/dist/elements/public/TemplateConfigForm/TemplateConfigForm.d.ts +55 -1
  91. package/dist/elements/public/TemplateConfigForm/TemplateConfigForm.js +395 -185
  92. package/dist/elements/public/TemplateConfigForm/TemplateConfigForm.js.map +1 -1
  93. package/dist/elements/public/TemplateConfigForm/types.d.ts +34 -0
  94. package/dist/elements/public/TemplateConfigForm/types.js.map +1 -1
  95. package/dist/elements/public/TemplateForm/TemplateForm.d.ts +23 -1
  96. package/dist/elements/public/TemplateForm/TemplateForm.js +92 -52
  97. package/dist/elements/public/TemplateForm/TemplateForm.js.map +1 -1
  98. package/dist/elements/public/TemplateForm/types.d.ts +14 -0
  99. package/dist/elements/public/TemplateForm/types.js.map +1 -1
  100. package/dist/mixins/themeable.js +30 -14
  101. package/dist/mixins/themeable.js.map +1 -1
  102. package/dist/mixins/translatable.js +1 -1
  103. package/dist/mixins/translatable.js.map +1 -1
  104. package/package.json +1 -1
  105. package/dist/cdn/shared-3f35fa81.js +0 -1
  106. package/dist/cdn/shared-ace85f1b.js +0 -1
  107. package/dist/cdn/shared-d8852c42.js +0 -1
@@ -16,10 +16,64 @@ import { getDefaultJSON } from "./defaults.js";
16
16
  import { live } from 'lit-html/directives/live';
17
17
  const NS = 'template-config-form';
18
18
  const Base = ScopedElementsMixin(ResponsiveMixin(ConfigurableMixin(ThemeableMixin(TranslatableMixin(NucleonElement, NS)))));
19
+ /**
20
+ * Form element for creating or editing template configs (`fx:template_config`).
21
+ *
22
+ * @slot cart-type:before
23
+ * @slot cart-type:after
24
+ *
25
+ * @slot foxycomplete:before
26
+ * @slot foxycomplete:after
27
+ *
28
+ * @slot locations:before
29
+ * @slot locations:after
30
+ *
31
+ * @slot hidden-fields:before
32
+ * @slot hidden-fields:after
33
+ *
34
+ * @slot cards:before
35
+ * @slot cards:after
36
+ *
37
+ * @slot checkout-type:before
38
+ * @slot checkout-type:after
39
+ *
40
+ * @slot consent:before
41
+ * @slot consent:after
42
+ *
43
+ * @slot fields:before
44
+ * @slot fields:after
45
+ *
46
+ * @slot google-analytics:before
47
+ * @slot google-analytics:after
48
+ *
49
+ * @slot segment-io:before
50
+ * @slot segment-io:after
51
+ *
52
+ * @slot troubleshooting:before
53
+ * @slot troubleshooting:after
54
+ *
55
+ * @slot custom-config:before
56
+ * @slot custom-config:after
57
+ *
58
+ * @slot header:before
59
+ * @slot header:after
60
+ *
61
+ * @slot custom-fields:before
62
+ * @slot custom-fields:after
63
+ *
64
+ * @slot footer:before
65
+ * @slot footer:after
66
+ *
67
+ * @element foxy-template-config-form
68
+ * @since 1.14.0
69
+ */
19
70
  export class TemplateConfigForm extends Base {
20
71
  constructor() {
21
72
  super(...arguments);
73
+ this.templates = {};
74
+ /** URI of the `fx:countries` hAPI resource. */
22
75
  this.countries = '';
76
+ /** URI of the `fx:regions` hAPI resource. */
23
77
  this.regions = '';
24
78
  this.__addHiddenFieldInputValue = '';
25
79
  }
@@ -47,16 +101,11 @@ export class TemplateConfigForm extends Base {
47
101
  }
48
102
  render() {
49
103
  var _a, _b;
50
- const hidden = this.hiddenControls;
104
+ const hidden = this.hiddenSelector;
51
105
  const json = this.form.json ? JSON.parse(this.form.json) : getDefaultJSON();
52
106
  return html `
53
107
  <div class="relative" aria-busy=${this.in('busy')} aria-live="polite">
54
- <div
55
- class=${classMap({
56
- 'space-y-l transition-opacity': true,
57
- 'opacity-50': !this.in('idle'),
58
- })}
59
- >
108
+ <div class="space-y-l">
60
109
  ${hidden.matches('cart-type', true) ? '' : this.__renderCartType(json)}
61
110
  ${hidden.matches('foxycomplete', true) ? '' : this.__renderFoxycomplete(json)}
62
111
  ${hidden.matches('locations', true) ? '' : this.__renderLocations(json)}
@@ -95,17 +144,26 @@ export class TemplateConfigForm extends Base {
95
144
  __renderCartType(json) {
96
145
  const { lang, ns } = this;
97
146
  const items = ['default', 'fullpage', 'custom'];
147
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('cart-type', true);
98
148
  return html `
99
- <div>
149
+ <div data-testid="cart-type">
100
150
  ${this.renderTemplateOrSlot('cart-type:before')}
101
151
 
102
152
  <x-group frame>
103
- <foxy-i18n slot="header" lang=${lang} key="cart_type" ns=${ns}></foxy-i18n>
153
+ <foxy-i18n
154
+ class=${isDisabled ? 'text-disabled' : ''}
155
+ slot="header"
156
+ lang=${lang}
157
+ key="cart_type"
158
+ ns=${ns}
159
+ >
160
+ </foxy-i18n>
104
161
 
105
162
  <x-choice
163
+ data-testid="cart-type-choice"
106
164
  .value=${json.cart_type}
107
165
  .items=${items}
108
- ?disabled=${this.disabledSelector.matches('cart-type', true)}
166
+ ?disabled=${isDisabled}
109
167
  ?readonly=${this.readonlySelector.matches('cart-type', true)}
110
168
  @change=${(evt) => {
111
169
  this.edit({ json: JSON.stringify({ ...json, cart_type: evt.detail }) });
@@ -116,7 +174,7 @@ export class TemplateConfigForm extends Base {
116
174
  <div slot="${item}-label" class="grid leading-s py-s">
117
175
  <foxy-i18n lang=${lang} key="cart_type_${item}" ns=${ns}></foxy-i18n>
118
176
  <foxy-i18n
119
- class="text-secondary text-xs"
177
+ class="text-xs ${isDisabled ? 'text-disabled' : 'text-secondary'}"
120
178
  lang=${lang}
121
179
  key="cart_type_${item}_explainer"
122
180
  ns=${ns}
@@ -134,39 +192,41 @@ export class TemplateConfigForm extends Base {
134
192
  }
135
193
  __renderFoxycomplete(json) {
136
194
  const { lang, ns } = this;
137
- const isDisabled = this.disabledSelector.matches('foxycomplete', true);
195
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('foxycomplete', true);
138
196
  const isReadonly = this.readonlySelector.matches('foxycomplete', true);
197
+ const config = json.foxycomplete;
139
198
  const items = ['combobox', 'search', 'disabled'];
140
- const value = json.foxycomplete.usage === 'none'
141
- ? 'disabled'
142
- : json.foxycomplete.show_combobox
143
- ? 'combobox'
144
- : 'search';
145
- const renderFlagsCheckbox = () => html `
199
+ const value = config.usage === 'none' ? 'disabled' : config.show_combobox ? 'combobox' : 'search';
200
+ const flagsCheckbox = html `
146
201
  <x-checkbox
202
+ data-testid="foxycomplete-flags-check"
147
203
  ?disabled=${isDisabled}
148
204
  ?readonly=${isReadonly}
149
- ?checked=${json.foxycomplete.show_flags}
205
+ ?checked=${config.show_flags}
150
206
  @change=${(evt) => {
151
- const newConfig = {
152
- ...json.foxycomplete,
153
- show_flags: evt.detail,
154
- };
155
- this.edit({ json: JSON.stringify({ ...json, foxycomplete: newConfig }) });
207
+ config.show_flags = evt.detail;
208
+ this.edit({ json: JSON.stringify(json) });
156
209
  }}
157
210
  >
158
- <foxy-i18n class="leading-s block" lang=${lang} key="show_country_flags" ns=${ns}>
159
- </foxy-i18n>
211
+ <foxy-i18n lang=${lang} key="show_country_flags" ns=${ns}></foxy-i18n>
160
212
  </x-checkbox>
161
213
  `;
162
214
  return html `
163
- <div>
215
+ <div data-testid="foxycomplete">
164
216
  ${this.renderTemplateOrSlot('foxycomplete:before')}
165
217
 
166
218
  <x-group frame>
167
- <foxy-i18n slot="header" lang=${lang} key="foxycomplete" ns=${ns}></foxy-i18n>
219
+ <foxy-i18n
220
+ class=${isDisabled ? 'text-disabled' : ''}
221
+ slot="header"
222
+ lang=${lang}
223
+ key="foxycomplete"
224
+ ns=${ns}
225
+ >
226
+ </foxy-i18n>
168
227
 
169
228
  <x-choice
229
+ data-testid="foxycomplete-choice"
170
230
  .value=${value}
171
231
  .items=${items}
172
232
  ?disabled=${isDisabled}
@@ -174,12 +234,9 @@ export class TemplateConfigForm extends Base {
174
234
  @change=${(evt) => {
175
235
  if (!(evt instanceof ChoiceChangeEvent))
176
236
  return;
177
- const newConfig = {
178
- ...json.foxycomplete,
179
- usage: evt.detail === 'disabled' ? 'none' : 'required',
180
- show_combobox: evt.detail === 'combobox',
181
- };
182
- this.edit({ json: JSON.stringify({ ...json, foxycomplete: newConfig }) });
237
+ config.usage = evt.detail === 'disabled' ? 'none' : 'required';
238
+ config.show_combobox = evt.detail === 'combobox';
239
+ this.edit({ json: JSON.stringify(json) });
183
240
  }}
184
241
  >
185
242
  ${items.map(item => {
@@ -187,7 +244,7 @@ export class TemplateConfigForm extends Base {
187
244
  <div slot="${item}-label" class="grid leading-s py-s">
188
245
  <foxy-i18n lang=${lang} key="foxycomplete_${item}" ns=${ns}></foxy-i18n>
189
246
  <foxy-i18n
190
- class="text-secondary text-xs"
247
+ class="text-xs ${isDisabled ? 'text-disabled' : 'text-secondary'}"
191
248
  lang=${lang}
192
249
  key="foxycomplete_${item}_explainer"
193
250
  ns=${ns}
@@ -203,17 +260,15 @@ export class TemplateConfigForm extends Base {
203
260
  const field = action === 'open' ? 'combobox_open' : 'combobox_close';
204
261
  return html `
205
262
  <vaadin-text-field
263
+ data-testid="foxycomplete-${action}-icon"
206
264
  label=${this.t(`${action}_icon`)}
207
- .value=${json.foxycomplete[field]}
265
+ .value=${config[field]}
208
266
  ?disabled=${isDisabled}
209
267
  ?readonly=${isReadonly}
268
+ @keydown=${(evt) => evt.key === 'Enter' && this.submit()}
210
269
  @input=${(evt) => {
211
- const target = evt.currentTarget;
212
- const newConfig = {
213
- ...json.foxycomplete,
214
- [field]: target.value,
215
- };
216
- this.edit({ json: JSON.stringify({ ...json, foxycomplete: newConfig }) });
270
+ config[field] = evt.currentTarget.value;
271
+ this.edit({ json: JSON.stringify(json) });
217
272
  }}
218
273
  >
219
274
  </vaadin-text-field>
@@ -221,24 +276,21 @@ export class TemplateConfigForm extends Base {
221
276
  })}
222
277
  </div>
223
278
 
224
- ${renderFlagsCheckbox()}
279
+ ${flagsCheckbox}
225
280
  </div>
226
281
 
227
- <div slot="search" class="pb-s" ?hidden=${value !== 'search'}>
228
- ${renderFlagsCheckbox()}
229
- </div>
282
+ <div slot="search" class="pb-s" ?hidden=${value !== 'search'}>${flagsCheckbox}</div>
230
283
  </x-choice>
231
284
 
232
285
  <div class="border-t border-contrast-10 p-m">
233
286
  <x-checkbox
287
+ data-testid="foxycomplete-lookup-check"
234
288
  ?disabled=${isDisabled}
235
289
  ?readonly=${isReadonly}
236
290
  ?checked=${json.postal_code_lookup.usage === 'enabled'}
237
291
  @change=${(evt) => {
238
- const newConfig = {
239
- usage: evt.detail ? 'enabled' : 'none',
240
- };
241
- this.edit({ json: JSON.stringify({ ...json, postal_code_lookup: newConfig }) });
292
+ json.postal_code_lookup.usage = evt.detail ? 'enabled' : 'none';
293
+ this.edit({ json: JSON.stringify(json) });
242
294
  }}
243
295
  >
244
296
  <foxy-i18n lang=${lang} key="enable_postcode_lookup" ns=${ns}></foxy-i18n>
@@ -253,6 +305,8 @@ export class TemplateConfigForm extends Base {
253
305
  __renderLocations(json) {
254
306
  const { lang, ns } = this;
255
307
  const config = json.location_filtering;
308
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('locations', true);
309
+ const isReadonly = this.readonlySelector.matches('locations', true);
256
310
  const shippingChoice = config.shipping_filter_type === 'blacklist' ? 'block' : 'allow';
257
311
  const billingChoice = config.usage === 'both'
258
312
  ? 'copy'
@@ -282,58 +336,85 @@ export class TemplateConfigForm extends Base {
282
336
  }
283
337
  };
284
338
  return html `
285
- ${this.renderTemplateOrSlot('locations:before')}
339
+ <div data-testid="locations">
340
+ ${this.renderTemplateOrSlot('locations:before')}
286
341
 
287
- <x-group frame>
288
- <foxy-i18n slot="header" lang=${lang} key="location_plural" ns=${ns}></foxy-i18n>
342
+ <x-group frame>
343
+ <foxy-i18n
344
+ class=${isDisabled ? 'text-disabled' : ''}
345
+ slot="header"
346
+ lang=${lang}
347
+ key="location_plural"
348
+ ns=${ns}
349
+ >
350
+ </foxy-i18n>
289
351
 
290
- <div class="grid sm-grid-cols-2 bg-contrast-10" style="gap: 1px">
291
- <x-group class="bg-base pt-m">
292
- <foxy-i18n class="text-tertiary" slot="header" lang=${lang} key="shipping" ns=${ns}>
293
- </foxy-i18n>
352
+ <div class="grid sm-grid-cols-2 bg-contrast-10" style="gap: 1px">
353
+ <x-group class="bg-base pt-m">
354
+ <foxy-i18n
355
+ class=${isDisabled ? 'text-disabled' : 'text-tertiary'}
356
+ slot="header"
357
+ lang=${lang}
358
+ key="shipping"
359
+ ns=${ns}
360
+ >
361
+ </foxy-i18n>
294
362
 
295
- <x-choice
296
- .items=${['allow', 'block']}
297
- .value=${shippingChoice}
298
- @change=${(evt) => {
363
+ <x-choice
364
+ data-testid="locations-shipping-choice"
365
+ .items=${['allow', 'block']}
366
+ .value=${shippingChoice}
367
+ ?disabled=${isDisabled}
368
+ ?readonly=${isReadonly}
369
+ @change=${(evt) => {
299
370
  if (config.usage !== 'both')
300
371
  config.usage = 'independent';
301
372
  config.shipping_filter_type = evt.detail === 'block' ? 'blacklist' : 'whitelist';
302
373
  normalize();
303
374
  this.edit({ json: JSON.stringify(json) });
304
375
  }}
305
- >
306
- <foxy-i18n slot="allow-label" lang=${lang} key="allowlist" ns=${ns}></foxy-i18n>
307
- <foxy-i18n slot="block-label" lang=${lang} key="blocklist" ns=${ns}></foxy-i18n>
308
-
309
- <x-countries-list
310
- countries=${JSON.stringify(config.shipping_filter_values)}
311
- regions=${this.regions}
312
- class="mb-m"
313
- href=${this.countries}
314
- slot=${shippingChoice}
315
- lang=${lang}
316
- ns=${ns}
317
- ?disabled=${this.disabledSelector.matches('locations', true)}
318
- ?readonly=${this.readonlySelector.matches('locations', true)}
319
- @update:countries=${(evt) => {
376
+ >
377
+ <foxy-i18n slot="allow-label" lang=${lang} key="allowlist" ns=${ns}></foxy-i18n>
378
+ <foxy-i18n slot="block-label" lang=${lang} key="blocklist" ns=${ns}></foxy-i18n>
379
+
380
+ <x-countries-list
381
+ data-testid="locations-shipping-list"
382
+ countries=${JSON.stringify(config.shipping_filter_values)}
383
+ regions=${this.regions}
384
+ class="mb-m"
385
+ href=${this.countries}
386
+ slot=${shippingChoice}
387
+ lang=${lang}
388
+ ns=${ns}
389
+ ?disabled=${isDisabled}
390
+ ?readonly=${isReadonly}
391
+ @update:countries=${(evt) => {
320
392
  config.shipping_filter_values = evt.currentTarget.countries;
321
393
  normalize();
322
394
  this.edit({ json: JSON.stringify(json) });
323
395
  }}
324
- >
325
- </x-countries-list>
326
- </x-choice>
327
- </x-group>
396
+ >
397
+ </x-countries-list>
398
+ </x-choice>
399
+ </x-group>
328
400
 
329
- <x-group class="bg-base pt-m">
330
- <foxy-i18n class="text-tertiary" slot="header" lang=${lang} key="billing" ns=${ns}>
331
- </foxy-i18n>
401
+ <x-group class="bg-base pt-m">
402
+ <foxy-i18n
403
+ class=${isDisabled ? 'text-disabled' : 'text-tertiary'}
404
+ slot="header"
405
+ lang=${lang}
406
+ key="billing"
407
+ ns=${ns}
408
+ >
409
+ </foxy-i18n>
332
410
 
333
- <x-choice
334
- .items=${['allow', 'block', 'copy']}
335
- .value=${billingChoice}
336
- @change=${(evt) => {
411
+ <x-choice
412
+ data-testid="locations-billing-choice"
413
+ .items=${['allow', 'block', 'copy']}
414
+ .value=${billingChoice}
415
+ ?disabled=${isDisabled}
416
+ ?readonly=${isReadonly}
417
+ @change=${(evt) => {
337
418
  if (evt.detail === 'copy') {
338
419
  config.usage = 'both';
339
420
  }
@@ -344,35 +425,38 @@ export class TemplateConfigForm extends Base {
344
425
  normalize();
345
426
  this.edit({ json: JSON.stringify(json) });
346
427
  }}
347
- >
348
- <foxy-i18n slot="allow-label" lang=${lang} key="allowlist" ns=${ns}></foxy-i18n>
349
- <foxy-i18n slot="block-label" lang=${lang} key="blocklist" ns=${ns}></foxy-i18n>
350
- <foxy-i18n slot="copy-label" lang=${lang} key="same_as_shipping" ns=${ns}></foxy-i18n>
351
-
352
- <x-countries-list
353
- countries=${JSON.stringify(config.billing_filter_values)}
354
- regions=${this.regions}
355
- class="mb-m"
356
- href=${this.countries}
357
- slot=${billingChoice}
358
- lang=${lang}
359
- ns=${ns}
360
- ?disabled=${this.disabledSelector.matches('locations', true)}
361
- ?readonly=${this.readonlySelector.matches('locations', true)}
362
- ?hidden=${billingChoice === 'copy'}
363
- @update:countries=${(evt) => {
428
+ >
429
+ <foxy-i18n slot="allow-label" lang=${lang} key="allowlist" ns=${ns}></foxy-i18n>
430
+ <foxy-i18n slot="block-label" lang=${lang} key="blocklist" ns=${ns}></foxy-i18n>
431
+ <foxy-i18n slot="copy-label" lang=${lang} key="same_as_shipping" ns=${ns}>
432
+ </foxy-i18n>
433
+
434
+ <x-countries-list
435
+ data-testid="locations-billing-list"
436
+ countries=${JSON.stringify(config.billing_filter_values)}
437
+ regions=${this.regions}
438
+ class="mb-m"
439
+ href=${this.countries}
440
+ slot=${billingChoice}
441
+ lang=${lang}
442
+ ns=${ns}
443
+ ?disabled=${isDisabled}
444
+ ?readonly=${isReadonly}
445
+ ?hidden=${billingChoice === 'copy'}
446
+ @update:countries=${(evt) => {
364
447
  config.billing_filter_values = evt.currentTarget.countries;
365
448
  normalize();
366
449
  this.edit({ json: JSON.stringify(json) });
367
450
  }}
368
- >
369
- </x-countries-list>
370
- </x-choice>
371
- </x-group>
372
- </div>
373
- </x-group>
451
+ >
452
+ </x-countries-list>
453
+ </x-choice>
454
+ </x-group>
455
+ </div>
456
+ </x-group>
374
457
 
375
- ${this.renderTemplateOrSlot('locations:after')}
458
+ ${this.renderTemplateOrSlot('locations:after')}
459
+ </div>
376
460
  `;
377
461
  }
378
462
  __renderHiddenFields(json) {
@@ -380,6 +464,8 @@ export class TemplateConfigForm extends Base {
380
464
  const suggestions = [];
381
465
  const fields = [];
382
466
  const config = json.cart_display_config;
467
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('hidden-fields', true);
468
+ const isReadonly = this.readonlySelector.matches('hidden-fields', true);
383
469
  for (const key in config) {
384
470
  if (!key.startsWith('show_'))
385
471
  continue;
@@ -404,43 +490,71 @@ export class TemplateConfigForm extends Base {
404
490
  };
405
491
  const radius = 'calc(var(--lumo-border-radius-l) / 1.2)';
406
492
  const inputRadius = fields.length === 0 ? [radius] : ['0', '0', radius, radius];
493
+ const isAddButtonDisabled = isDisabled || !this.__addHiddenFieldInputValue;
407
494
  return html `
408
- <div>
495
+ <div data-testid="hidden-fields">
409
496
  ${this.renderTemplateOrSlot('hidden-fields:before')}
410
497
 
411
498
  <x-group frame>
412
- <foxy-i18n slot="header" lang=${lang} key="hidden_fields" ns=${ns}></foxy-i18n>
499
+ <foxy-i18n
500
+ class=${isDisabled ? 'text-disabled' : ''}
501
+ slot="header"
502
+ lang=${lang}
503
+ key="hidden_fields"
504
+ ns=${ns}
505
+ >
506
+ </foxy-i18n>
413
507
 
414
- <div class="divide-y divide-contrast-10">
415
- ${fields.map(field => html `
416
- <div class="h-m ml-m pr-xs flex items-center justify-between">
508
+ <div class="divide-y divide-contrast-10" data-testid="hidden-fields-list">
509
+ ${fields.map(field => {
510
+ return html `
511
+ <div
512
+ class=${classMap({
513
+ 'h-m ml-m pr-xs flex items-center justify-between': true,
514
+ 'text-secondary': isReadonly,
515
+ 'text-disabled': isDisabled,
516
+ })}
517
+ >
417
518
  ${suggestions.includes(field)
418
- ? html `<foxy-i18n lang=${lang} key=${field} ns=${ns}></foxy-i18n>`
419
- : html `<span>${field}</span>`}
519
+ ? html `<foxy-i18n lang=${lang} key=${field} ns=${ns}></foxy-i18n>`
520
+ : html `<span>${field}</span>`}
420
521
 
421
522
  <button
422
- class="flex w-xs h-xs items-center justify-center rounded-full transition-colors hover-bg-error-10 hover-text-error focus-outline-none focus-ring-2 focus-ring-inset focus-ring-error-50"
523
+ aria-label=${this.t('delete')}
524
+ class=${classMap({
525
+ 'w-xs h-xs rounded-full transition-colors': true,
526
+ 'hover-bg-error-10 hover-text-error': !isDisabled,
527
+ 'focus-outline-none focus-ring-2 ring-inset ring-error-50': !isDisabled,
528
+ 'cursor-default': isDisabled,
529
+ 'flex': !isReadonly,
530
+ 'hidden': isReadonly,
531
+ })}
532
+ ?disabled=${isDisabled}
423
533
  @click=${() => {
424
- if (typeof config[`show_${field}`] === 'boolean') {
425
- config[`show_${field}`] = true;
426
- }
427
- else {
428
- config.hidden_product_options = config.hidden_product_options.filter(option => option !== field);
429
- }
430
- this.edit({ json: JSON.stringify(json) });
431
- }}
534
+ if (typeof config[`show_${field}`] === 'boolean') {
535
+ config[`show_${field}`] = true;
536
+ }
537
+ else {
538
+ config.hidden_product_options = config.hidden_product_options.filter(option => option !== field);
539
+ }
540
+ this.edit({ json: JSON.stringify(json) });
541
+ }}
432
542
  >
433
- <iron-icon icon="icons:close" class="icon-inline text-m"></iron-icon>
543
+ <iron-icon icon="icons:close" class="icon-inline text-m m-auto"></iron-icon>
434
544
  </button>
435
545
  </div>
436
- `)}
546
+ `;
547
+ })}
437
548
  </div>
438
549
 
439
550
  <div
551
+ data-testid="hidden-fields-new"
440
552
  style="border-radius: ${inputRadius.join(' ')}"
441
553
  class=${classMap({
442
554
  'h-m flex items-center ring-inset ring-primary-50 focus-within-ring-2': true,
443
555
  'border-t border-contrast-10': fields.length > 0,
556
+ 'flex': !isReadonly,
557
+ 'hidden': isReadonly,
444
558
  })}
445
559
  >
446
560
  <input
@@ -448,6 +562,8 @@ export class TemplateConfigForm extends Base {
448
562
  class="w-full bg-transparent appearance-none h-m px-m focus-outline-none"
449
563
  list="hidden-fields-list"
450
564
  .value=${live(this.__addHiddenFieldInputValue)}
565
+ ?disabled=${isDisabled}
566
+ ?readonly=${isReadonly}
451
567
  @keydown=${(evt) => evt.key === 'Enter' && addField()}
452
568
  @input=${(evt) => {
453
569
  this.__addHiddenFieldInputValue = evt.currentTarget.value;
@@ -465,12 +581,12 @@ export class TemplateConfigForm extends Base {
465
581
  class=${classMap({
466
582
  'w-xs h-xs mr-xs flex-shrink-0 ring-inset ring-success-50': true,
467
583
  'flex items-center justify-center rounded-full transition-colors': true,
468
- 'bg-contrast-5 text-disabled cursor-default': !this.__addHiddenFieldInputValue,
469
- 'bg-success-10 text-success cursor-pointer': !!this.__addHiddenFieldInputValue,
470
- 'hover-bg-success hover-text-success-contrast': !!this.__addHiddenFieldInputValue,
471
- 'focus-outline-none focus-ring-2': !!this.__addHiddenFieldInputValue,
584
+ 'bg-contrast-5 text-disabled cursor-default': isAddButtonDisabled,
585
+ 'bg-success-10 text-success cursor-pointer': !isAddButtonDisabled,
586
+ 'hover-bg-success hover-text-success-contrast': !isAddButtonDisabled,
587
+ 'focus-outline-none focus-ring-2': !isAddButtonDisabled,
472
588
  })}
473
- ?disabled=${!this.__addHiddenFieldInputValue}
589
+ ?disabled=${isAddButtonDisabled}
474
590
  @click=${addField}
475
591
  >
476
592
  <iron-icon icon="icons:add" class="icon-inline text-m"></iron-icon>
@@ -484,7 +600,8 @@ export class TemplateConfigForm extends Base {
484
600
  }
485
601
  __renderCards(json) {
486
602
  const { lang, ns } = this;
487
- const isDisabled = this.disabledSelector.matches('cards', true);
603
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('cards', true);
604
+ const isReadonly = this.readonlySelector.matches('cards', true);
488
605
  const config = json.supported_payment_cards;
489
606
  let skipForSaved;
490
607
  let skipForSSO;
@@ -511,12 +628,19 @@ export class TemplateConfigForm extends Base {
511
628
  visa: 'Visa',
512
629
  };
513
630
  return html `
514
- <div>
631
+ <div data-testid="cards">
515
632
  ${this.renderTemplateOrSlot('cards:before')}
516
633
 
517
634
  <div class="space-y-xs">
518
635
  <x-group frame>
519
- <foxy-i18n slot="header" lang=${lang} key="supported_cards" ns=${ns}></foxy-i18n>
636
+ <foxy-i18n
637
+ class=${isDisabled ? 'text-disabled' : ''}
638
+ slot="header"
639
+ lang=${lang}
640
+ key="supported_cards"
641
+ ns=${ns}
642
+ >
643
+ </foxy-i18n>
520
644
 
521
645
  <div class="flex flex-wrap m-xs p-s">
522
646
  ${Object.entries(logos).map(([type, logo]) => {
@@ -534,10 +658,12 @@ export class TemplateConfigForm extends Base {
534
658
  <label
535
659
  class=${classMap({
536
660
  'overflow-hidden transition-colors flex rounded border': true,
537
- 'border-primary bg-primary-10 text-primary': isChecked,
538
- 'hover-text-body': isChecked && !isDisabled,
661
+ 'border-primary bg-primary-10 text-primary': isChecked && !isReadonly,
662
+ 'border-contrast bg-contrast-5 text-secondary': isChecked && isReadonly,
663
+ 'hover-text-body': isChecked && !isDisabled && !isReadonly,
539
664
  'border-contrast-10': !isChecked,
540
- 'hover-border-primary hover-text-primary': !isChecked && !isDisabled,
665
+ 'hover-border-primary': !isChecked && !isDisabled && !isReadonly,
666
+ 'hover-text-primary': !isChecked && !isDisabled && !isReadonly,
541
667
  })}
542
668
  >
543
669
  <div class="h-s">${logo}</div>
@@ -550,14 +676,17 @@ export class TemplateConfigForm extends Base {
550
676
  type="checkbox"
551
677
  class="sr-only"
552
678
  ?disabled=${isDisabled}
679
+ ?readonly=${isReadonly}
553
680
  ?checked=${isChecked}
554
681
  @change=${(evt) => {
682
+ if (isReadonly)
683
+ return evt.preventDefault();
555
684
  evt.stopPropagation();
556
- if (isChecked) {
557
- config.splice(config.indexOf(type), 1);
685
+ if (evt.currentTarget.checked) {
686
+ config.push(type);
558
687
  }
559
688
  else {
560
- config.push(type);
689
+ config.splice(config.indexOf(type), 1);
561
690
  }
562
691
  this.edit({ json: JSON.stringify(json) });
563
692
  }}
@@ -570,8 +699,10 @@ export class TemplateConfigForm extends Base {
570
699
 
571
700
  <div class="flex flex-wrap p-s border-t border-contrast-10">
572
701
  <x-checkbox
702
+ data-testid="cards-saved-check"
573
703
  class="m-s"
574
704
  ?disabled=${isDisabled || json.csc_requirements === 'new_cards_only'}
705
+ ?readonly=${isReadonly}
575
706
  ?checked=${skipForSaved}
576
707
  @change=${(evt) => {
577
708
  json.csc_requirements = evt.detail ? 'sso_only' : 'all_cards';
@@ -583,8 +714,10 @@ export class TemplateConfigForm extends Base {
583
714
  </x-checkbox>
584
715
 
585
716
  <x-checkbox
717
+ data-testid="cards-sso-check"
586
718
  class="m-s"
587
719
  ?disabled=${isDisabled}
720
+ ?readonly=${isReadonly}
588
721
  ?checked=${skipForSSO}
589
722
  @change=${(evt) => {
590
723
  json.csc_requirements = evt.detail
@@ -602,7 +735,7 @@ export class TemplateConfigForm extends Base {
602
735
  </x-group>
603
736
 
604
737
  <foxy-i18n
605
- class="text-xs text-secondary leading-s block"
738
+ class="text-xs leading-s block ${isDisabled ? 'text-disabled' : 'text-secondary'}"
606
739
  lang=${lang}
607
740
  key="supported_cards_disclaimer"
608
741
  ns=${ns}
@@ -616,17 +749,27 @@ export class TemplateConfigForm extends Base {
616
749
  }
617
750
  __renderCheckoutType(json) {
618
751
  const { lang, ns } = this;
752
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('checkout-type', true);
753
+ const isReadonly = this.readonlySelector.matches('checkout-type', true);
619
754
  return html `
620
- <div>
755
+ <div data-testid="checkout-type">
621
756
  ${this.renderTemplateOrSlot('checkout-type:before')}
622
757
 
623
758
  <div class="space-y-xs">
624
759
  <x-group frame>
625
- <foxy-i18n slot="header" lang=${lang} key="checkout_type" ns=${ns}></foxy-i18n>
760
+ <foxy-i18n
761
+ class=${isDisabled ? 'text-disabled' : ''}
762
+ slot="header"
763
+ lang=${lang}
764
+ key="checkout_type"
765
+ ns=${ns}
766
+ >
767
+ </foxy-i18n>
626
768
 
627
769
  <x-choice
628
- ?disabled=${this.disabledSelector.matches('checkout-type', true)}
629
- ?readonly=${this.readonlySelector.matches('checkout-type', true)}
770
+ data-testid="checkout-type-choice"
771
+ ?disabled=${isDisabled}
772
+ ?readonly=${isReadonly}
630
773
  .items=${['default_account', 'default_guest', 'guest_only', 'account_only']}
631
774
  .value=${json.checkout_type}
632
775
  .getText=${(item) => this.t(`checkout_type_${item}`)}
@@ -639,7 +782,7 @@ export class TemplateConfigForm extends Base {
639
782
  </x-group>
640
783
 
641
784
  <foxy-i18n
642
- class="text-secondary text-xs leading-s block"
785
+ class="text-xs leading-s block ${isDisabled ? 'text-disabled' : 'text-secondary'}"
643
786
  lang=${lang}
644
787
  key="checkout_type_helper_text"
645
788
  ns=${ns}
@@ -656,17 +799,25 @@ export class TemplateConfigForm extends Base {
656
799
  const tosConfig = json.tos_checkbox_settings;
657
800
  const mailConfig = json.newsletter_subscribe;
658
801
  const sdtaConfig = json.eu_secure_data_transfer_consent;
659
- const isDisabled = this.disabledSelector.matches('consent', true);
802
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('consent', true);
660
803
  const isReadonly = this.readonlySelector.matches('consent', true);
661
804
  const dividerStyle = 'margin-left: calc(1.125rem + (var(--lumo-space-m) * 2))';
662
805
  return html `
663
- <div>
806
+ <div data-testid="consent">
664
807
  ${this.renderTemplateOrSlot('consent:before')}
665
808
 
666
809
  <x-group frame>
667
- <foxy-i18n slot="header" lang=${lang} key="consent" ns=${ns}></foxy-i18n>
810
+ <foxy-i18n
811
+ class=${isDisabled ? 'text-disabled' : ''}
812
+ slot="header"
813
+ lang=${lang}
814
+ key="consent"
815
+ ns=${ns}
816
+ >
817
+ </foxy-i18n>
668
818
 
669
819
  <x-checkbox
820
+ data-testid="consent-tos-check"
670
821
  ?disabled=${isDisabled}
671
822
  ?readonly=${isReadonly}
672
823
  ?checked=${tosConfig.usage === 'required' || tosConfig.usage === 'optional'}
@@ -682,7 +833,7 @@ export class TemplateConfigForm extends Base {
682
833
  <div class="flex flex-col">
683
834
  <foxy-i18n lang=${lang} key="display_tos_link" ns=${ns}></foxy-i18n>
684
835
  <foxy-i18n
685
- class="text-xs leading-s text-secondary"
836
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
686
837
  lang=${lang}
687
838
  key="display_tos_link_explainer"
688
839
  ns=${ns}
@@ -692,6 +843,7 @@ export class TemplateConfigForm extends Base {
692
843
 
693
844
  <div slot="content" ?hidden=${tosConfig.usage === 'none'}>
694
845
  <vaadin-text-field
846
+ data-testid="consent-tos-field"
695
847
  label=${this.t('location_url')}
696
848
  class="w-full mt-m"
697
849
  placeholder="https://example.com/path/to/tos"
@@ -708,8 +860,10 @@ export class TemplateConfigForm extends Base {
708
860
 
709
861
  <div class="flex flex-wrap -mx-s -mb-s mt-s">
710
862
  <x-checkbox
863
+ data-testid="consent-tos-require-check"
711
864
  class="m-s"
712
865
  ?disabled=${isDisabled}
866
+ ?readonly=${isReadonly}
713
867
  ?checked=${tosConfig.usage === 'required'}
714
868
  @change=${(evt) => {
715
869
  tosConfig.usage = evt.detail ? 'required' : 'optional';
@@ -721,8 +875,10 @@ export class TemplateConfigForm extends Base {
721
875
  </x-checkbox>
722
876
 
723
877
  <x-checkbox
878
+ data-testid="consent-tos-state-check"
724
879
  class="m-s"
725
880
  ?disabled=${isDisabled}
881
+ ?readonly=${isReadonly}
726
882
  ?checked=${tosConfig.initial_state === 'checked'}
727
883
  @change=${(evt) => {
728
884
  tosConfig.initial_state = evt.detail ? 'checked' : 'unchecked';
@@ -739,6 +895,7 @@ export class TemplateConfigForm extends Base {
739
895
  <div style=${dividerStyle} class="border-b border-contrast-10"></div>
740
896
 
741
897
  <x-checkbox
898
+ data-testid="consent-mail-check"
742
899
  ?disabled=${isDisabled}
743
900
  ?readonly=${isReadonly}
744
901
  ?checked=${mailConfig.usage === 'required'}
@@ -751,7 +908,7 @@ export class TemplateConfigForm extends Base {
751
908
  <div class="flex flex-col">
752
909
  <foxy-i18n lang=${lang} key="newsletter_subscribe" ns=${ns}></foxy-i18n>
753
910
  <foxy-i18n
754
- class="text-xs leading-s text-secondary"
911
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
755
912
  lang=${lang}
756
913
  key="newsletter_subscribe_explainer"
757
914
  ns=${ns}
@@ -763,6 +920,7 @@ export class TemplateConfigForm extends Base {
763
920
  <div style=${dividerStyle} class="border-b border-contrast-10"></div>
764
921
 
765
922
  <x-checkbox
923
+ data-testid="consent-sdta-check"
766
924
  ?disabled=${isDisabled}
767
925
  ?readonly=${isReadonly}
768
926
  ?checked=${sdtaConfig.usage === 'required'}
@@ -775,7 +933,7 @@ export class TemplateConfigForm extends Base {
775
933
  <div class="flex flex-col">
776
934
  <foxy-i18n lang=${lang} key="display_sdta" ns=${ns}></foxy-i18n>
777
935
  <foxy-i18n
778
- class="text-xs leading-s text-secondary"
936
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
779
937
  lang=${lang}
780
938
  key="display_sdta_explainer"
781
939
  ns=${ns}
@@ -785,13 +943,14 @@ export class TemplateConfigForm extends Base {
785
943
  </x-checkbox>
786
944
  </x-group>
787
945
 
788
- ${this.renderTemplateOrSlot('consent:before')}
946
+ ${this.renderTemplateOrSlot('consent:after')}
789
947
  </div>
790
948
  `;
791
949
  }
792
950
  __renderFields(json) {
793
951
  const { lang, ns } = this;
794
- const isDisabled = this.disabledSelector.matches('fields', true);
952
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('fields', true);
953
+ const isReadonly = this.readonlySelector.matches('fields', true);
795
954
  const config = json.custom_checkout_field_requirements;
796
955
  const options = {
797
956
  cart_controls: ['enabled', 'disabled'],
@@ -809,16 +968,29 @@ export class TemplateConfigForm extends Base {
809
968
  billing_country: ['default', 'optional', 'required', 'hidden'],
810
969
  };
811
970
  return html `
812
- <div>
971
+ <div data-testid="fields">
813
972
  ${this.renderTemplateOrSlot('fields:before')}
814
973
 
815
974
  <x-group frame>
816
- <foxy-i18n slot="header" lang=${lang} key="field_plural" ns=${ns}></foxy-i18n>
975
+ <foxy-i18n
976
+ class=${isDisabled ? 'text-disabled' : ''}
977
+ slot="header"
978
+ lang=${lang}
979
+ key="field_plural"
980
+ ns=${ns}
981
+ >
982
+ </foxy-i18n>
817
983
 
818
984
  <div class="bg-contrast-10 grid grid-cols-1 md-grid-cols-2" style="gap: 1px">
819
985
  ${Object.entries(options).map(([property, values]) => {
820
986
  return html `
821
- <label class="flex items-center pl-m bg-base">
987
+ <label
988
+ class=${classMap({
989
+ 'flex items-center pl-m bg-base': true,
990
+ 'text-secondary': isReadonly,
991
+ 'text-disabled': isDisabled,
992
+ })}
993
+ >
822
994
  <foxy-i18n
823
995
  class="flex-1"
824
996
  lang=${lang}
@@ -829,14 +1001,33 @@ export class TemplateConfigForm extends Base {
829
1001
 
830
1002
  <div
831
1003
  class=${classMap({
832
- 'px-s m-xs flex items-center cursor-pointer rounded leading-none': true,
1004
+ 'flex items-center text-right font-medium h-s px-s m-xs': isReadonly,
1005
+ 'hidden': !isReadonly,
1006
+ })}
1007
+ >
1008
+ ${this.t(values.find(value => config[property] === value))}
1009
+ </div>
1010
+
1011
+ <div
1012
+ class=${classMap({
1013
+ 'px-s m-xs flex items-center rounded leading-none': true,
833
1014
  'ring-primary-50 ring-inset focus-within-ring-2': !isDisabled,
834
1015
  'hover-text-primary': !isDisabled,
835
- 'opacity-50': isDisabled,
1016
+ 'cursor-pointer': !isDisabled,
1017
+ 'cursor-default': isDisabled,
1018
+ 'flex': !isReadonly,
1019
+ 'hidden': isReadonly,
836
1020
  })}
837
1021
  >
838
1022
  <select
839
- class="h-s mr-xs text-right appearance-none bg-transparent cursor-pointer focus-outline-none font-medium"
1023
+ data-testid="fields-${property}"
1024
+ class=${classMap({
1025
+ 'h-s mr-xs text-right appearance-none bg-transparent font-medium': true,
1026
+ 'focus-outline-none cursor-pointer': !isDisabled,
1027
+ 'cursor-default': isDisabled,
1028
+ })}
1029
+ ?disabled=${isDisabled}
1030
+ ?readonly=${isReadonly}
840
1031
  @change=${(evt) => {
841
1032
  const select = evt.currentTarget;
842
1033
  const value = select.options[select.options.selectedIndex].value;
@@ -879,17 +1070,18 @@ export class TemplateConfigForm extends Base {
879
1070
  const config = json.analytics_config;
880
1071
  const sioConfig = config.segment_io;
881
1072
  const gaConfig = config.google_analytics;
882
- const isDisabled = this.disabledSelector.matches('google-analytics', true);
1073
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('google-analytics', true);
883
1074
  const isReadonly = this.readonlySelector.matches('google-analytics', true);
884
1075
  return html `
885
- <div>
1076
+ <div data-testid="google-analytics">
886
1077
  ${this.renderTemplateOrSlot('google-analytics:before')}
887
1078
 
888
1079
  <x-group frame>
889
- <span slot="header">Google Analytics</span>
1080
+ <span class=${isDisabled ? 'text-disabled' : ''} slot="header">Google Analytics</span>
890
1081
 
891
1082
  <div class="p-m space-y-m">
892
1083
  <vaadin-text-field
1084
+ data-testid="google-analytics-field"
893
1085
  class="w-full"
894
1086
  label=${this.t('ga_account_id')}
895
1087
  placeholder="UA-1234567-1"
@@ -903,11 +1095,13 @@ export class TemplateConfigForm extends Base {
903
1095
  gaConfig.account_id = evt.currentTarget.value;
904
1096
  gaConfig.usage = gaConfig.account_id ? 'required' : 'none';
905
1097
  config.usage = gaConfig.account_id || sioConfig.account_id ? 'required' : 'none';
1098
+ this.edit({ json: JSON.stringify(json) });
906
1099
  }}
907
1100
  >
908
1101
  </vaadin-text-field>
909
1102
 
910
1103
  <x-checkbox
1104
+ data-testid="google-analytics-check"
911
1105
  ?disabled=${isDisabled}
912
1106
  ?readonly=${isReadonly}
913
1107
  ?checked=${gaConfig.include_on_site}
@@ -919,7 +1113,7 @@ export class TemplateConfigForm extends Base {
919
1113
  <div class="flex flex-col">
920
1114
  <foxy-i18n lang=${lang} key="ga_include_on_site" ns=${ns}></foxy-i18n>
921
1115
  <foxy-i18n
922
- class="text-xs leading-s text-secondary"
1116
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
923
1117
  lang=${lang}
924
1118
  key="ga_include_on_site_explainer"
925
1119
  ns=${ns}
@@ -938,17 +1132,18 @@ export class TemplateConfigForm extends Base {
938
1132
  const config = json.analytics_config;
939
1133
  const sioConfig = config.segment_io;
940
1134
  const gaConfig = config.google_analytics;
941
- const isDisabled = this.disabledSelector.matches('segment-io', true);
1135
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('segment-io', true);
942
1136
  const isReadonly = this.readonlySelector.matches('segment-io', true);
943
1137
  return html `
944
- <div>
1138
+ <div data-testid="segment-io">
945
1139
  ${this.renderTemplateOrSlot('segment-io:before')}
946
1140
 
947
1141
  <x-group frame>
948
- <span slot="header">Segment.io</span>
1142
+ <span class=${isDisabled ? 'text-disabled' : ''} slot="header">Segment.io</span>
949
1143
 
950
1144
  <div class="p-m">
951
1145
  <vaadin-text-field
1146
+ data-testid="segment-io-field"
952
1147
  class="w-full"
953
1148
  label=${this.t('sio_account_id')}
954
1149
  placeholder="MY-WRITE-KEY"
@@ -962,6 +1157,7 @@ export class TemplateConfigForm extends Base {
962
1157
  sioConfig.account_id = evt.currentTarget.value;
963
1158
  sioConfig.usage = sioConfig.account_id ? 'required' : 'none';
964
1159
  config.usage = gaConfig.account_id || sioConfig.account_id ? 'required' : 'none';
1160
+ this.edit({ json: JSON.stringify(json) });
965
1161
  }}
966
1162
  >
967
1163
  </vaadin-text-field>
@@ -975,17 +1171,27 @@ export class TemplateConfigForm extends Base {
975
1171
  __renderTroubleshooting(json) {
976
1172
  const { lang, ns } = this;
977
1173
  const config = json.debug;
1174
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('troubleshooting', true);
1175
+ const isReadonly = this.readonlySelector.matches('troubleshooting', true);
978
1176
  return html `
979
- <div>
1177
+ <div data-testid="troubleshooting">
980
1178
  ${this.renderTemplateOrSlot('troubleshooting:before')}
981
1179
 
982
1180
  <x-group frame>
983
- <foxy-i18n slot="header" lang=${lang} key="troubleshooting" ns=${ns}></foxy-i18n>
1181
+ <foxy-i18n
1182
+ class=${isDisabled ? 'text-disabled' : ''}
1183
+ slot="header"
1184
+ lang=${lang}
1185
+ key="troubleshooting"
1186
+ ns=${ns}
1187
+ >
1188
+ </foxy-i18n>
984
1189
 
985
1190
  <div class="p-m space-y-m">
986
1191
  <x-checkbox
987
- ?disabled=${this.disabledSelector.matches('troubleshooting', true)}
988
- ?readonly=${this.readonlySelector.matches('troubleshooting', true)}
1192
+ data-testid="troubleshooting-check"
1193
+ ?disabled=${isDisabled}
1194
+ ?readonly=${isReadonly}
989
1195
  ?checked=${config.usage === 'required'}
990
1196
  @change=${(evt) => {
991
1197
  config.usage = evt.detail ? 'required' : 'none';
@@ -995,7 +1201,7 @@ export class TemplateConfigForm extends Base {
995
1201
  <div class="flex flex-col">
996
1202
  <foxy-i18n lang=${lang} key="troubleshooting_debug" ns=${ns}></foxy-i18n>
997
1203
  <foxy-i18n
998
- class="text-xs leading-s text-secondary"
1204
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
999
1205
  lang=${lang}
1000
1206
  key="troubleshooting_debug_explainer"
1001
1207
  ns=${ns}
@@ -1012,16 +1218,17 @@ export class TemplateConfigForm extends Base {
1012
1218
  }
1013
1219
  __renderCustomConfig(json) {
1014
1220
  return html `
1015
- <div>
1221
+ <div data-testid="custom-config">
1016
1222
  ${this.renderTemplateOrSlot('custom-config:before')}
1017
1223
 
1018
1224
  <vaadin-text-area
1225
+ data-testid="custom-config-field"
1019
1226
  class="w-full"
1020
1227
  label=${this.t('custom_config')}
1021
1228
  placeholder='{ "key": "value" }'
1022
1229
  helper-text=${this.t('custom_config_helper_text')}
1023
1230
  .value=${json.custom_config ? JSON.stringify(json.custom_config, null, 2) : ''}
1024
- ?disabled=${this.disabledSelector.matches('custom-config', true)}
1231
+ ?disabled=${!this.in('idle') || this.disabledSelector.matches('custom-config', true)}
1025
1232
  ?readonly=${this.readonlySelector.matches('custom-config', true)}
1026
1233
  @input=${(evt) => {
1027
1234
  const input = evt.currentTarget;
@@ -1043,15 +1250,16 @@ export class TemplateConfigForm extends Base {
1043
1250
  }
1044
1251
  __renderHeader(json) {
1045
1252
  return html `
1046
- <div>
1253
+ <div data-testid="header">
1047
1254
  ${this.renderTemplateOrSlot('header:before')}
1048
1255
 
1049
1256
  <vaadin-text-area
1257
+ data-testid="header-field"
1050
1258
  class="w-full"
1051
1259
  label=${this.t('custom_header')}
1052
1260
  helper-text=${this.t('custom_header_helper_text')}
1053
1261
  .value=${json.custom_script_values.header}
1054
- ?disabled=${this.disabledSelector.matches('header', true)}
1262
+ ?disabled=${!this.in('idle') || this.disabledSelector.matches('header', true)}
1055
1263
  ?readonly=${this.readonlySelector.matches('header', true)}
1056
1264
  @input=${(evt) => {
1057
1265
  const target = evt.currentTarget;
@@ -1070,16 +1278,17 @@ export class TemplateConfigForm extends Base {
1070
1278
  }
1071
1279
  __renderCustomFields(json) {
1072
1280
  return html `
1073
- <div>
1281
+ <div data-testid="custom-fields">
1074
1282
  ${this.renderTemplateOrSlot('custom-fields:before')}
1075
1283
 
1076
1284
  <vaadin-text-area
1285
+ data-testid="custom-fields-field"
1077
1286
  class="w-full"
1078
1287
  label=${this.t('custom_fields')}
1079
1288
  helper-text=${this.t('custom_fields_helper_text')}
1080
- .value=${json.custom_script_values.header}
1081
- ?disabled=${this.disabledSelector.matches('header', true)}
1082
- ?readonly=${this.readonlySelector.matches('header', true)}
1289
+ .value=${json.custom_script_values.checkout_fields}
1290
+ ?disabled=${!this.in('idle') || this.disabledSelector.matches('custom-fields', true)}
1291
+ ?readonly=${this.readonlySelector.matches('custom-fields', true)}
1083
1292
  @input=${(evt) => {
1084
1293
  const newValue = evt.currentTarget.value;
1085
1294
  json.custom_script_values.checkout_fields = newValue;
@@ -1094,15 +1303,16 @@ export class TemplateConfigForm extends Base {
1094
1303
  }
1095
1304
  __renderFooter(json) {
1096
1305
  return html `
1097
- <div>
1306
+ <div data-testid="footer">
1098
1307
  ${this.renderTemplateOrSlot('footer:before')}
1099
1308
 
1100
1309
  <vaadin-text-area
1310
+ data-testid="footer-field"
1101
1311
  class="w-full"
1102
1312
  label=${this.t('custom_footer')}
1103
1313
  helper-text=${this.t('custom_footer_helper_text')}
1104
1314
  .value=${json.custom_script_values.footer}
1105
- ?disabled=${this.disabledSelector.matches('footer', true)}
1315
+ ?disabled=${!this.in('idle') || this.disabledSelector.matches('footer', true)}
1106
1316
  ?readonly=${this.readonlySelector.matches('footer', true)}
1107
1317
  @input=${(evt) => {
1108
1318
  const target = evt.currentTarget;