@useinsider/guido 3.20.0-beta.5c9442d → 3.20.0-beta.6e5144c

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.
@@ -1,68 +1,77 @@
1
- var C = Object.defineProperty;
2
- var p = (g, u, t) => u in g ? C(g, u, { enumerable: !0, configurable: !0, writable: !0, value: t }) : g[u] = t;
3
- var i = (g, u, t) => p(g, typeof u != "symbol" ? u + "" : u, t);
4
- import { useConfig as h } from "../../../../../composables/useConfig.js";
5
- import { ModificationDescription as y } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
6
- import { CommonControl as N } from "../../../common-control.js";
7
- import { RRS_CONFIG_VERSION as _, DEFAULT_NODE_CONFIG as a } from "../../constants/defaultConfig.js";
8
- import { RECOMMENDATION_ID_ATTR as I } from "../../constants/selectors.js";
9
- import { RecommendationConfigService as c } from "../../services/configService.js";
1
+ var m = Object.defineProperty;
2
+ var C = (h, u, e) => u in h ? m(h, u, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[u] = e;
3
+ var s = (h, u, e) => C(h, typeof u != "symbol" ? u + "" : u, e);
4
+ import { useConfig as f } from "../../../../../composables/useConfig.js";
5
+ import { ModificationDescription as p } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
6
+ import { CommonControl as y } from "../../../common-control.js";
7
+ import { RRS_CONFIG_VERSION as _, DEFAULT_NODE_CONFIG as d } from "../../constants/defaultConfig.js";
8
+ import { RECOMMENDATION_ID_ATTR as N } from "../../constants/selectors.js";
9
+ import { RecommendationConfigService as l } from "../../services/configService.js";
10
10
  import { useRecommendationExtensionStore as R } from "../../store/recommendation.js";
11
- import { registerNodeConfigWriter as b } from "../../utils/nodeConfigWriter.js";
12
- import { AlgorithmControl as T } from "./algorithm.js";
13
- import { ALGORITHM_CONTROL_ID as ut } from "./algorithm.js";
14
- import { CurrencyControl as P } from "./currency.js";
15
- import { CURRENCY_CONTROL_ID as gt } from "./currency.js";
16
- import { FiltersControl as S } from "./filters.js";
17
- import { FILTERS_CONTROL_ID as ft } from "./filters.js";
18
- import { LayoutOrientationControl as O } from "./layoutOrientation.js";
19
- import { LAYOUT_ORIENTATION_CONTROL_ID as Ct } from "./layoutOrientation.js";
20
- import { LocaleControl as L } from "./locale.js";
21
- import { LOCALE_CONTROL_ID as yt } from "./locale.js";
22
- import { PricePlacementControl as k } from "./pricePlacement.js";
23
- import { PRICE_PLACEMENT_CONTROL_ID as _t } from "./pricePlacement.js";
24
- import { ProductCountControl as E } from "./productCount.js";
25
- import { PRODUCT_COUNT_CONTROL_ID as Rt } from "./productCount.js";
26
- import { ProductLayoutControl as F } from "./productLayout.js";
27
- import { PRODUCT_LAYOUT_CONTROL_ID as Tt } from "./productLayout.js";
11
+ import { registerNodeConfigWriter as I, commitBlockChangeOutsidePanel as P } from "../../utils/nodeConfigWriter.js";
12
+ import { AlgorithmControl as S } from "./algorithm.js";
13
+ import { ALGORITHM_CONTROL_ID as le } from "./algorithm.js";
14
+ import { CurrencyControl as b } from "./currency.js";
15
+ import { CURRENCY_CONTROL_ID as he } from "./currency.js";
16
+ import { FiltersControl as k } from "./filters.js";
17
+ import { FILTERS_CONTROL_ID as ge } from "./filters.js";
18
+ import { LayoutOrientationControl as T } from "./layoutOrientation.js";
19
+ import { LAYOUT_ORIENTATION_CONTROL_ID as Ce } from "./layoutOrientation.js";
20
+ import { LocaleControl as O } from "./locale.js";
21
+ import { LOCALE_CONTROL_ID as ye } from "./locale.js";
22
+ import { PricePlacementControl as B } from "./pricePlacement.js";
23
+ import { PRICE_PLACEMENT_CONTROL_ID as Ne } from "./pricePlacement.js";
24
+ import { ProductCountControl as F } from "./productCount.js";
25
+ import { PRODUCT_COUNT_CONTROL_ID as Ie } from "./productCount.js";
26
+ import { ProductLayoutControl as L } from "./productLayout.js";
27
+ import { PRODUCT_LAYOUT_CONTROL_ID as Se } from "./productLayout.js";
28
28
  import { ShuffleControl as D } from "./shuffle.js";
29
- import { SHUFFLE_CONTROL_ID as St } from "./shuffle.js";
30
- import { StrategyControl as w } from "./strategy.js";
31
- import { STRATEGY_CONTROL_ID as Lt } from "./strategy.js";
32
- import { setCurrencyAttributes as v, getBlockElement as A, isPartnerManagedBlock as B, updateProductContentInPlace as x, regenerateProductRowsWithStyles as U } from "./utils.js";
33
- import { adjustProductsToSize as Et, formatProductPrice as Ft, getCardComposition as Dt, getCurrentLayout as wt, getMainContainerTbody as vt, regenerateMobileProductRows as At, updatePricesInPlace as Bt, updateSingleProductContent as xt } from "./utils.js";
34
- import { useDebounceFn as f } from "../../../../../node_modules/@vueuse/shared/index.js";
29
+ import { SHUFFLE_CONTROL_ID as ke } from "./shuffle.js";
30
+ import { StrategyControl as E } from "./strategy.js";
31
+ import { STRATEGY_CONTROL_ID as Oe } from "./strategy.js";
32
+ import { setCurrencyAttributes as w, getBlockElement as V, isPartnerManagedBlock as U, updateProductContentInPlace as v, regenerateProductRowsWithStyles as A } from "./utils.js";
33
+ import { adjustProductsToSize as Fe, formatProductPrice as Le, getCardComposition as De, getCurrentLayout as Ee, getMainContainerTbody as we, regenerateMobileProductRows as Ve, updatePricesInPlace as Ue, updateSingleProductContent as ve } from "./utils.js";
34
+ import { useDebounceFn as g } from "../../../../../node_modules/@vueuse/shared/index.js";
35
35
  const W = "ui-elements-recommendation-block";
36
- class at extends N {
36
+ class ae extends y {
37
37
  constructor() {
38
38
  super(...arguments);
39
- i(this, "store", R());
40
- i(this, "storeUnsubscription", () => {
39
+ s(this, "store", R());
40
+ s(this, "storeUnsubscription", () => {
41
41
  });
42
42
  // A config change waiting to reach the node config. Deferred so it can ride the
43
43
  // re-render's single apply() — one user action must cost one undo press.
44
- i(this, "pendingNodeConfigWrite", null);
45
- i(this, "pendingConfigFlushTimer", null);
44
+ s(this, "pendingNodeConfigWrite", null);
45
+ s(this, "pendingConfigFlushTimer", null);
46
+ // The block the subscription watches, and its own configVersion whose products were
47
+ // fetched / reached the canvas — read on teardown and block switch to finish its refresh.
48
+ s(this, "trackedBlockId", null);
49
+ s(this, "fetchedConfigVersion", 0);
50
+ s(this, "renderedConfigVersion", 0);
51
+ s(this, "isDestroyed", !1);
46
52
  // Sub-control instances for lifecycle management
47
- i(this, "algorithmControl", null);
48
- i(this, "localeControl", null);
49
- i(this, "currencyControl", null);
50
- i(this, "productCountControl", null);
51
- i(this, "productLayoutControl", null);
52
- i(this, "filtersControl", null);
53
- i(this, "shuffleControl", null);
54
- i(this, "pricePlacementControl", null);
55
- i(this, "layoutOrientationControl", null);
56
- i(this, "strategyControl", null);
57
- i(this, "rrsEnabled", !1);
53
+ s(this, "algorithmControl", null);
54
+ s(this, "localeControl", null);
55
+ s(this, "currencyControl", null);
56
+ s(this, "productCountControl", null);
57
+ s(this, "productLayoutControl", null);
58
+ s(this, "filtersControl", null);
59
+ s(this, "shuffleControl", null);
60
+ s(this, "pricePlacementControl", null);
61
+ s(this, "layoutOrientationControl", null);
62
+ s(this, "strategyControl", null);
63
+ s(this, "rrsEnabled", !1);
58
64
  /**
59
65
  * Debounced product fetch to prevent rapid API calls during config changes
60
66
  */
61
- i(this, "_debouncedFetchProducts", f(async () => {
67
+ s(this, "_debouncedFetchProducts", g(async (e) => {
68
+ if (this.isDestroyed || e !== this.store.currentRecommendationId)
69
+ return;
70
+ const t = this._getBlockConfigVersion(e);
62
71
  try {
63
- await this.store.fetchRecommendationProducts();
72
+ await this.store.fetchRecommendationProducts(), e === this.store.currentRecommendationId && (this.fetchedConfigVersion = Math.max(this.fetchedConfigVersion, t));
64
73
  } finally {
65
- this._scheduleConfigFlush();
74
+ !this.isDestroyed && e === this.store.currentRecommendationId && this._scheduleConfigFlush();
66
75
  }
67
76
  }, 500));
68
77
  /**
@@ -76,23 +85,24 @@ class at extends N {
76
85
  * count. The store pads products to the configured size, so in-place only
77
86
  * fails when the size actually changed.
78
87
  */
79
- i(this, "_debouncedRegenerateWithProducts", f(() => {
80
- const t = this.store.recommendationProducts;
81
- if (!this.currentNode || !this.api)
88
+ s(this, "_debouncedRegenerateWithProducts", g(() => {
89
+ const e = this.store.recommendationProducts;
90
+ if (this.isDestroyed || !this.currentNode || !this.api)
82
91
  return;
83
- const e = this.api.getDocumentModifier(), o = this._stagePendingNodeConfig(e);
84
- if (B(this.currentNode)) {
85
- o && (e.apply(new y("Update recommendation configuration")), this.pendingNodeConfigWrite = null, this._clearConfigFlush());
92
+ this.renderedConfigVersion = this.fetchedConfigVersion;
93
+ const t = this.api.getDocumentModifier(), o = this._stagePendingNodeConfig(t);
94
+ if (U(this.currentNode)) {
95
+ o && (t.apply(new p("Update recommendation configuration")), this.pendingNodeConfigWrite = null, this._clearConfigFlush());
86
96
  return;
87
97
  }
88
- x({
98
+ v({
89
99
  currentNode: this.currentNode,
90
- documentModifier: e,
91
- products: t
92
- }) || U({
100
+ documentModifier: t,
101
+ products: e
102
+ }) || A({
93
103
  currentNode: this.currentNode,
94
- documentModifier: e,
95
- products: t
104
+ documentModifier: t,
105
+ products: e
96
106
  });
97
107
  }, 100));
98
108
  }
@@ -114,15 +124,15 @@ class at extends N {
114
124
  ];
115
125
  }
116
126
  getTemplate() {
117
- var t;
118
- return this.rrsEnabled = h().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((e) => {
127
+ var e;
128
+ return this.rrsEnabled = f().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((t) => {
119
129
  var o;
120
- return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
121
- }), this.algorithmControl = new T(), this.localeControl = new L(), this.currencyControl = new P(), this.productCountControl = new E(), this.productLayoutControl = new F(), this.filtersControl = new S(), this.shuffleControl = new D(), this.pricePlacementControl = new k(), this.layoutOrientationControl = new O(), this.strategyControl = this.rrsEnabled ? new w() : null, this._subControls.forEach((e) => {
122
- e && (e.api = this.api);
130
+ return (o = t == null ? void 0 : t.onDestroy) == null ? void 0 : o.call(t);
131
+ }), this.algorithmControl = new S(), this.localeControl = new O(), this.currencyControl = new b(), this.productCountControl = new F(), this.productLayoutControl = new L(), this.filtersControl = new k(), this.shuffleControl = new D(), this.pricePlacementControl = new B(), this.layoutOrientationControl = new T(), this.strategyControl = this.rrsEnabled ? new E() : null, this._subControls.forEach((t) => {
132
+ t && (t.api = this.api);
123
133
  }), `
124
134
  <div class="recommendation-controls-container">
125
- ${((t = this.strategyControl) == null ? void 0 : t.getTemplate()) ?? ""}
135
+ ${((e = this.strategyControl) == null ? void 0 : e.getTemplate()) ?? ""}
126
136
  ${this.layoutOrientationControl.getTemplate()}
127
137
  ${this.productCountControl.getTemplate()}
128
138
  ${this.productLayoutControl.getTemplate()}
@@ -135,39 +145,39 @@ class at extends N {
135
145
  </div>
136
146
  `;
137
147
  }
138
- _showControlsForBlock(t) {
148
+ _showControlsForBlock(e) {
139
149
  var r;
140
- const e = (r = this.getContainer()) == null ? void 0 : r.querySelector(".recommendation-controls-container");
141
- if (!e)
150
+ const t = (r = this.getContainer()) == null ? void 0 : r.querySelector(".recommendation-controls-container");
151
+ if (!t)
142
152
  return;
143
- const o = this._getRecommendationIdFromNode(t) === null ? null : c.getConfig(t), n = this.rrsEnabled && !!o && (!!(o != null && o.strategyId) || ((o == null ? void 0 : o.configVersion) ?? 0) >= _), s = this.rrsEnabled && !!o && !n;
144
- e.classList.toggle("strategy-block", n), e.classList.toggle("legacy-strategy-block", s);
153
+ const o = this._getRecommendationIdFromNode(e) === null ? null : l.getConfig(e), n = this.rrsEnabled && !!o && (!!(o != null && o.strategyId) || ((o == null ? void 0 : o.configVersion) ?? 0) >= _), i = this.rrsEnabled && !!o && !n;
154
+ t.classList.toggle("strategy-block", n), t.classList.toggle("legacy-strategy-block", i);
145
155
  }
146
156
  async onRender() {
147
157
  var o;
148
- b(this.api);
149
- const t = this._getRecommendationIdFromNode(this.currentNode), e = t ?? this.store.currentRecommendationId;
150
- if (e !== null && this.store.setCurrentBlock(e), t !== null && this._syncNodeConfigIfChanged(t), this._listenStateUpdates(), this._showControlsForBlock(this.currentNode), t !== null && this.strategyControl && (this.strategyControl.api = this.api, this.strategyControl.currentNode = this.currentNode, this.strategyControl.onRender()), e !== null && ((o = this.store.blockStates[e]) != null && o.isInitialized)) {
158
+ I(this.api);
159
+ const e = this._getRecommendationIdFromNode(this.currentNode), t = e ?? this.store.currentRecommendationId;
160
+ if (t !== null && this.store.setCurrentBlock(t), e !== null && this._syncNodeConfigIfChanged(e), this._listenStateUpdates(), this._showControlsForBlock(this.currentNode), e !== null && this.strategyControl && (this.strategyControl.api = this.api, this.strategyControl.currentNode = this.currentNode, this.strategyControl.onRender()), t !== null && ((o = this.store.blockStates[t]) != null && o.isInitialized)) {
151
161
  this._initializeSubControls();
152
162
  return;
153
163
  }
154
- await this._fetchBlockData(e), this._initializeSubControls();
164
+ await this._fetchBlockData(t), this._initializeSubControls();
155
165
  }
156
- onTemplateNodeUpdated(t) {
166
+ onTemplateNodeUpdated(e) {
157
167
  var o;
158
- super.onTemplateNodeUpdated(t);
159
- const e = this._getRecommendationIdFromNode(t);
160
- e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null && this._syncNodeConfigIfChanged(e), this._showControlsForBlock(t), e !== null && !((o = this.store.blockStates[e]) != null && o.isInitialized) && this._fetchBlockData(e).then(() => {
168
+ super.onTemplateNodeUpdated(e);
169
+ const t = this._getRecommendationIdFromNode(e);
170
+ t !== null && t !== this.store.currentRecommendationId && this.store.setCurrentBlock(t), t !== null && this._syncNodeConfigIfChanged(t, { keepRefreshedWrite: !0 }), this._showControlsForBlock(e), t !== null && !((o = this.store.blockStates[t]) != null && o.isInitialized) && this._fetchBlockData(t).then(() => {
161
171
  this._initializeSubControls();
162
172
  }), this._subControls.forEach((n) => {
163
- var s;
164
- n != null && n.api && (n.currentNode = t, (s = n.onTemplateNodeUpdated) == null || s.call(n, t));
173
+ var i;
174
+ n != null && n.api && (n.currentNode = e, (i = n.onTemplateNodeUpdated) == null || i.call(n, e));
165
175
  });
166
176
  }
167
177
  onDestroy() {
168
- this.storeUnsubscription(), this._flushPendingNodeConfig(), this._subControls.forEach((t) => {
169
- var e;
170
- return (e = t == null ? void 0 : t.onDestroy) == null ? void 0 : e.call(t);
178
+ this.isDestroyed = !0, this.storeUnsubscription(), this._finishUnrenderedChange() || this._flushPendingNodeConfig(), this._subControls.forEach((e) => {
179
+ var t;
180
+ return (t = e == null ? void 0 : e.onDestroy) == null ? void 0 : t.call(e);
171
181
  });
172
182
  }
173
183
  /**
@@ -175,9 +185,9 @@ class at extends N {
175
185
  * Each sub-control manages its own form values and event listeners
176
186
  */
177
187
  _initializeSubControls() {
178
- this._subControls.forEach((t) => {
179
- var e;
180
- t && (t.api = this.api, t.currentNode = this.currentNode, (e = t.onRender) == null || e.call(t));
188
+ this._subControls.forEach((e) => {
189
+ var t;
190
+ e && (e.api = this.api, e.currentNode = this.currentNode, (t = e.onRender) == null || t.call(e));
181
191
  });
182
192
  }
183
193
  /**
@@ -204,35 +214,38 @@ class at extends N {
204
214
  * that state and made a re-dropped saved module keep the defaults its wiped
205
215
  * state was rebuilt with (SD-150347).
206
216
  */
207
- _syncNodeConfigIfChanged(t) {
208
- this.pendingNodeConfigWrite && this.pendingNodeConfigWrite.blockId !== t && this._flushPendingNodeConfig();
209
- const e = this.store.blockStates[t];
210
- if (!e)
217
+ _syncNodeConfigIfChanged(e, { keepRefreshedWrite: t = !1 } = {}) {
218
+ var a;
219
+ const o = this.pendingNodeConfigWrite, n = t && o !== null && this._hasUnrenderedChange(o.blockId);
220
+ o && o.blockId !== e && !n && this._flushPendingNodeConfig();
221
+ const i = this.store.blockStates[e];
222
+ if (!i)
211
223
  return;
212
- const o = JSON.stringify(c.getConfig(this.currentNode)), n = e.syncedConfigFingerprint;
213
- e.syncedConfigFingerprint = o, n !== o && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
224
+ const r = JSON.stringify(l.getConfig(this.currentNode)), c = i.syncedConfigFingerprint;
225
+ i.syncedConfigFingerprint = r, c !== r && ((a = this.pendingNodeConfigWrite) == null ? void 0 : a.blockId) !== e && this._syncNodeConfigToStore();
214
226
  }
215
227
  /** Whether the deferred write would move the node's strategyId — see the caller (SD-149916). */
216
228
  _isPendingStrategyIdChange() {
217
- const t = this.pendingNodeConfigWrite;
218
- return t ? c.getConfig(this.currentNode).strategyId !== t.updates.strategyId : !1;
229
+ const e = this.pendingNodeConfigWrite;
230
+ return e ? l.getConfig(this.currentNode).strategyId !== e.updates.strategyId : !1;
219
231
  }
220
- _capturePendingNodeConfigWrite() {
221
- const t = this.store.currentRecommendationId;
222
- if (!this.currentNode || !this.api || t === null)
223
- return;
224
- const { filters: e, strategy: o, strategyId: n, size: s, nodeConfigVersion: r } = this.store.recommendationConfigs, { partnerName: l } = h();
225
- this.pendingNodeConfigWrite = {
226
- blockId: t,
232
+ _capturePendingNodeConfigWrite(e = this.store.currentRecommendationId) {
233
+ const t = e === null ? void 0 : this.store.blockStates[e];
234
+ !this.currentNode || !this.api || e === null || !t || (this.pendingNodeConfigWrite = {
235
+ blockId: e,
227
236
  node: this.currentNode,
228
- updates: {
229
- filters: e,
230
- strategy: o,
231
- strategyId: n,
232
- size: s,
233
- configVersion: r,
234
- ...l.value ? { partnerName: l.value } : {}
235
- }
237
+ updates: this._getNodeConfigUpdates(t.recommendationConfigs)
238
+ });
239
+ }
240
+ _getNodeConfigUpdates(e) {
241
+ const { filters: t, strategy: o, strategyId: n, size: i, nodeConfigVersion: r } = e, { partnerName: c } = f();
242
+ return {
243
+ filters: t,
244
+ strategy: o,
245
+ strategyId: n,
246
+ size: i,
247
+ configVersion: r,
248
+ ...c.value ? { partnerName: c.value } : {}
236
249
  };
237
250
  }
238
251
  /**
@@ -245,9 +258,9 @@ class at extends N {
245
258
  * @param documentModifier - The batch to accumulate into
246
259
  * @returns Whether anything was staged
247
260
  */
248
- _stagePendingNodeConfig(t) {
249
- const e = this.pendingNodeConfigWrite;
250
- return !e || !this.currentNode ? !1 : (c.stageConfig(t, this.currentNode, e.updates), !0);
261
+ _stagePendingNodeConfig(e) {
262
+ const t = this.pendingNodeConfigWrite;
263
+ return !t || !this.currentNode ? !1 : (l.stageConfig(e, this.currentNode, t.updates), !0);
251
264
  }
252
265
  /**
253
266
  * Arms the guaranteed fallback write, once the product fetch has settled. The
@@ -268,41 +281,44 @@ class at extends N {
268
281
  * snapshot the intervening re-render staled, and saveConfig swallows that failure.
269
282
  */
270
283
  _flushPendingNodeConfig() {
271
- const t = this.pendingNodeConfigWrite;
272
- if (this.pendingNodeConfigWrite = null, this._clearConfigFlush(), !t || !this.api)
284
+ const e = this.pendingNodeConfigWrite;
285
+ this.pendingNodeConfigWrite = null, this._clearConfigFlush(), this._writeNodeConfig(e);
286
+ }
287
+ _writeNodeConfig(e) {
288
+ if (!e || !this.api)
273
289
  return;
274
- const e = t.blockId === this.store.currentRecommendationId && this.currentNode ? this.currentNode : t.node, o = c.getConfig(e);
275
- JSON.stringify(o.filters) === JSON.stringify(t.updates.filters) && o.strategy === t.updates.strategy && o.strategyId === t.updates.strategyId && o.size === t.updates.size || c.updateConfig(this.api, e, t.updates, "Update recommendation filters");
290
+ const t = e.blockId === this.store.currentRecommendationId && this.currentNode ? this.currentNode : e.node, o = l.getConfig(t);
291
+ JSON.stringify(o.filters) === JSON.stringify(e.updates.filters) && o.strategy === e.updates.strategy && o.strategyId === e.updates.strategyId && o.size === e.updates.size || l.updateConfig(this.api, t, e.updates, "Update recommendation filters");
276
292
  }
277
293
  _syncNodeConfigToStore() {
278
294
  var n;
279
- const t = c.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((n = this.store.blockStates[e]) == null ? void 0 : n.isInitialized);
295
+ const e = l.getConfig(this.currentNode), t = this.store.currentRecommendationId, o = t !== null && ((n = this.store.blockStates[t]) == null ? void 0 : n.isInitialized);
280
296
  this.store.patchCurrentBlockConfig({
281
- strategy: t.strategy,
282
- strategyId: t.strategyId,
283
- nodeConfigVersion: t.configVersion,
284
- language: t.language,
285
- size: t.size,
286
- productIds: t.productIds,
287
- cardsInRow: t.cardsInRow,
288
- mobileCardsInRow: t.mobileCardsInRow,
289
- mobileLayoutEnabled: t.mobileLayoutEnabled,
290
- orientation: t.layout,
297
+ strategy: e.strategy,
298
+ strategyId: e.strategyId,
299
+ nodeConfigVersion: e.configVersion,
300
+ language: e.language,
301
+ size: e.size,
302
+ productIds: e.productIds,
303
+ cardsInRow: e.cardsInRow,
304
+ mobileCardsInRow: e.mobileCardsInRow,
305
+ mobileLayoutEnabled: e.mobileLayoutEnabled,
306
+ orientation: e.layout,
291
307
  // Only sync filters from node config during initial load.
292
308
  // After initialization, the Pinia store is the source of truth
293
309
  // for filters (edited via the filter drawer).
294
- ...o ? {} : { filters: t.filters },
295
- shuffleProducts: t.shuffleProducts,
296
- priceMovedToNextLine: t.priceMovedToNextLine,
297
- priceHideIfSameAsDiscounted: t.priceHideIfSameAsDiscounted,
310
+ ...o ? {} : { filters: e.filters },
311
+ shuffleProducts: e.shuffleProducts,
312
+ priceMovedToNextLine: e.priceMovedToNextLine,
313
+ priceHideIfSameAsDiscounted: e.priceHideIfSameAsDiscounted,
298
314
  currencySettings: {
299
- name: t.currency.code,
300
- value: t.currency.code,
301
- symbol: t.currency.symbol,
302
- alignment: t.currency.alignment === "before" ? "0" : "1",
303
- decimalCount: t.currency.decimalCount.toString(),
304
- decimalSeparator: t.currency.decimalSeparator,
305
- thousandSeparator: t.currency.thousandSeparator
315
+ name: e.currency.code,
316
+ value: e.currency.code,
317
+ symbol: e.currency.symbol,
318
+ alignment: e.currency.alignment === "before" ? "0" : "1",
319
+ decimalCount: e.currency.decimalCount.toString(),
320
+ decimalSeparator: e.currency.decimalSeparator,
321
+ thousandSeparator: e.currency.thousandSeparator
306
322
  }
307
323
  }, { triggerRefetch: !1 });
308
324
  }
@@ -315,8 +331,8 @@ class at extends N {
315
331
  * Shared by onRender() and onTemplateNodeUpdated() to avoid duplication.
316
332
  * Marks the block as initialized to prevent redundant fetches on re-selection.
317
333
  */
318
- async _fetchBlockData(t) {
319
- t !== null && this.store.markBlockInitialized(t), (await Promise.allSettled([
334
+ async _fetchBlockData(e) {
335
+ e !== null && this.store.markBlockInitialized(e), (await Promise.allSettled([
320
336
  this.store.fetchRecommendationCreateData(),
321
337
  this.store.fetchRecommendationFilters()
322
338
  ])).forEach((o, n) => {
@@ -341,72 +357,140 @@ class at extends N {
341
357
  _applySmartDefaults() {
342
358
  if (!this.currentNode || !this.api)
343
359
  return;
344
- const t = c.getConfig(this.currentNode), e = {};
345
- let o = null, n = null, s = null;
346
- if (t.currency.code === a.currency.code) {
360
+ const e = l.getConfig(this.currentNode), t = {};
361
+ let o = null, n = null, i = null;
362
+ if (e.currency.code === d.currency.code) {
347
363
  const { currencyList: r } = this.store;
348
364
  r.length > 0 && (r.some(
349
- (d) => d.value === `price.${a.currency.code}`
350
- ) || (o = r[0].value.replace("price.", ""), e.currency = {
351
- ...a.currency,
365
+ (a) => a.value === `price.${d.currency.code}`
366
+ ) || (o = r[0].value.replace("price.", ""), t.currency = {
367
+ ...d.currency,
352
368
  code: o,
353
369
  symbol: o
354
370
  }));
355
371
  }
356
- if (t.strategy === a.strategy) {
372
+ if (e.strategy === d.strategy) {
357
373
  const r = this.store.getActivePredictiveAlgorithms;
358
374
  r.length > 0 && (r.some(
359
- (d) => d.value === a.strategy
360
- ) || (n = r[0].value, e.strategy = n));
375
+ (a) => a.value === d.strategy
376
+ ) || (n = r[0].value, t.strategy = n));
361
377
  }
362
- if (t.language === a.language) {
378
+ if (e.language === d.language) {
363
379
  const r = this.store.getLanguages;
364
380
  r.length > 0 && (r.some(
365
- (d) => d.value === a.language
366
- ) || (s = r[0].value, e.language = s));
381
+ (a) => a.value === d.language
382
+ ) || (i = r[0].value, t.language = i));
367
383
  }
368
- !o && !n && !s || (c.updateConfig(
384
+ !o && !n && !i || (l.updateConfig(
369
385
  this.api,
370
386
  this.currentNode,
371
- e,
387
+ t,
372
388
  "Applied smart defaults"
373
- ), o && e.currency && v({
389
+ ), o && t.currency && w({
374
390
  currentNode: this.currentNode,
375
391
  documentModifier: this.api.getDocumentModifier(),
376
- currency: e.currency
392
+ currency: t.currency
377
393
  }), this.store.patchCurrentBlockConfig({
378
394
  ...o ? {
379
395
  currencySettings: {
380
396
  name: o,
381
397
  value: o,
382
398
  symbol: o,
383
- alignment: a.currency.alignment === "before" ? "0" : "1",
384
- decimalCount: a.currency.decimalCount.toString(),
385
- decimalSeparator: a.currency.decimalSeparator,
386
- thousandSeparator: a.currency.thousandSeparator
399
+ alignment: d.currency.alignment === "before" ? "0" : "1",
400
+ decimalCount: d.currency.decimalCount.toString(),
401
+ decimalSeparator: d.currency.decimalSeparator,
402
+ thousandSeparator: d.currency.thousandSeparator
387
403
  }
388
404
  } : {},
389
405
  ...n ? { strategy: n } : {},
390
- ...s ? { language: s } : {}
406
+ ...i ? { language: i } : {}
391
407
  }, { triggerRefetch: !1 }));
392
408
  }
393
409
  /**
394
410
  * Reads the recommendation-id attribute from the block element within the node
395
411
  */
396
- _getRecommendationIdFromNode(t) {
397
- const e = A(t);
398
- if (!e || !("getAttribute" in e))
412
+ _getRecommendationIdFromNode(e) {
413
+ const t = V(e);
414
+ if (!t || !("getAttribute" in t))
399
415
  return null;
400
- const o = e.getAttribute(I);
416
+ const o = t.getAttribute(N);
401
417
  if (!o)
402
418
  return null;
403
419
  const n = parseInt(o);
404
420
  return Number.isNaN(n) ? null : n;
405
421
  }
422
+ /**
423
+ * Hands a config change whose products never reached the canvas to a block-scoped
424
+ * refresh, so it survives the panel closing or moving to another block.
425
+ * @returns whether a refresh was started
426
+ */
427
+ _finishUnrenderedChange() {
428
+ const e = this.trackedBlockId;
429
+ if (e === null || !this._hasUnrenderedChange(e))
430
+ return !1;
431
+ const t = this.fetchedConfigVersion !== this._getBlockConfigVersion(e);
432
+ return this._refreshBlockOutsidePanel(e, t), !0;
433
+ }
434
+ /** A removed block counts as unrendered so its pending write still gets flushed. */
435
+ _hasUnrenderedChange(e) {
436
+ if (e !== this.trackedBlockId)
437
+ return !1;
438
+ const t = this.store.blockStates[e];
439
+ return !t || this.renderedConfigVersion !== t.configVersion;
440
+ }
441
+ _hasPendingWriteFor(e) {
442
+ var t;
443
+ return ((t = this.pendingNodeConfigWrite) == null ? void 0 : t.blockId) === e;
444
+ }
445
+ _getBlockConfigVersion(e) {
446
+ var t;
447
+ return e === null ? 0 : ((t = this.store.blockStates[e]) == null ? void 0 : t.configVersion) ?? 0;
448
+ }
449
+ /**
450
+ * Fetches and renders one block's products without the panel, carrying its config
451
+ * write so both still land as one undo entry.
452
+ */
453
+ async _refreshBlockOutsidePanel(e, t) {
454
+ var c;
455
+ if (((c = this.pendingNodeConfigWrite) == null ? void 0 : c.blockId) !== e && this._flushPendingNodeConfig(), !this.store.blockStates[e]) {
456
+ this._flushPendingNodeConfig();
457
+ return;
458
+ }
459
+ !this.pendingNodeConfigWrite && this._getRecommendationIdFromNode(this.currentNode) === e && this._capturePendingNodeConfigWrite(e);
460
+ const o = this.pendingNodeConfigWrite;
461
+ this.pendingNodeConfigWrite = null, this._clearConfigFlush();
462
+ const n = this.store.blockStates[e].configVersion;
463
+ if (t)
464
+ try {
465
+ await this.store.fetchRecommendationProductsForBlock(e);
466
+ } catch (a) {
467
+ console.warn("Recommendation block: fetchRecommendationProductsForBlock failed", a);
468
+ }
469
+ const i = this.store.blockStates[e];
470
+ if (i && i.configVersion !== n) {
471
+ if (o && !this._hasPendingWriteFor(e)) {
472
+ const a = this._getNodeConfigUpdates(i.recommendationConfigs);
473
+ this._writeNodeConfig({ ...o, updates: a });
474
+ }
475
+ return;
476
+ }
477
+ let r = !1;
478
+ try {
479
+ r = !!i && P(
480
+ e,
481
+ this._getNodeConfigUpdates(i.recommendationConfigs),
482
+ i.recommendationProducts,
483
+ "Update recommendation configuration"
484
+ );
485
+ } catch (a) {
486
+ console.error("Recommendation block: refresh outside the panel failed", a);
487
+ }
488
+ r || this._writeNodeConfig(o);
489
+ }
406
490
  /**
407
491
  * Listen to store changes that require product refresh or regeneration.
408
492
  *
409
- * Uses configVersion counter (incremented only by patchCurrentBlockConfig)
493
+ * Uses the block's configVersion counter (bumped by patchCurrentBlockConfig and legacy conversion)
410
494
  * to distinguish user-initiated config changes from internal mutations
411
495
  * (e.g., fetchRecommendationCreateData setting preferred currency).
412
496
  *
@@ -417,55 +501,55 @@ class at extends N {
417
501
  * We skip that tick and update tracking references instead.
418
502
  */
419
503
  _listenStateUpdates() {
420
- const { store: t } = this;
421
- let e = t.recommendationProducts, o = t.$state.configVersion, n = t.currentRecommendationId;
422
- this.storeUnsubscription = t.$subscribe(() => {
423
- const s = t.currentRecommendationId;
424
- if (s !== n) {
425
- n = s, e = t.recommendationProducts, o = t.$state.configVersion;
504
+ const { store: e } = this;
505
+ let t = e.recommendationProducts, o = this._getBlockConfigVersion(e.currentRecommendationId);
506
+ this.isDestroyed = !1, this.trackedBlockId = e.currentRecommendationId, this.fetchedConfigVersion = o, this.renderedConfigVersion = o, this.storeUnsubscription = e.$subscribe(() => {
507
+ const n = e.currentRecommendationId;
508
+ if (n !== this.trackedBlockId) {
509
+ this._finishUnrenderedChange(), this.trackedBlockId = n, t = e.recommendationProducts, o = this._getBlockConfigVersion(n), this.fetchedConfigVersion = o, this.renderedConfigVersion = o;
426
510
  return;
427
511
  }
428
- const r = t.$state.configVersion;
429
- r !== o && (o = r, this._capturePendingNodeConfigWrite(), this._isPendingStrategyIdChange() && this._flushPendingNodeConfig(), this._debouncedFetchProducts());
430
- const l = t.recommendationProducts, d = l !== e, m = Array.isArray(l) && l.length > 0;
431
- d && m && (e = l, this._debouncedRegenerateWithProducts());
512
+ const i = this._getBlockConfigVersion(n);
513
+ i !== o && (o = i, this._capturePendingNodeConfigWrite(), this._isPendingStrategyIdChange() && this._flushPendingNodeConfig(), this._debouncedFetchProducts(n));
514
+ const r = e.recommendationProducts, c = r !== t, a = Array.isArray(r) && r.length > 0;
515
+ c && a && (t = r, this._debouncedRegenerateWithProducts());
432
516
  });
433
517
  }
434
518
  }
435
519
  export {
436
- ut as ALGORITHM_CONTROL_ID,
437
- T as AlgorithmControl,
520
+ le as ALGORITHM_CONTROL_ID,
521
+ S as AlgorithmControl,
438
522
  W as CONTROL_BLOCK_ID,
439
- gt as CURRENCY_CONTROL_ID,
440
- P as CurrencyControl,
441
- ft as FILTERS_CONTROL_ID,
442
- S as FiltersControl,
443
- Ct as LAYOUT_ORIENTATION_CONTROL_ID,
444
- yt as LOCALE_CONTROL_ID,
445
- O as LayoutOrientationControl,
446
- L as LocaleControl,
447
- _t as PRICE_PLACEMENT_CONTROL_ID,
448
- Rt as PRODUCT_COUNT_CONTROL_ID,
449
- Tt as PRODUCT_LAYOUT_CONTROL_ID,
450
- k as PricePlacementControl,
451
- E as ProductCountControl,
452
- F as ProductLayoutControl,
453
- at as RecommendationBlockControl,
454
- St as SHUFFLE_CONTROL_ID,
455
- Lt as STRATEGY_CONTROL_ID,
523
+ he as CURRENCY_CONTROL_ID,
524
+ b as CurrencyControl,
525
+ ge as FILTERS_CONTROL_ID,
526
+ k as FiltersControl,
527
+ Ce as LAYOUT_ORIENTATION_CONTROL_ID,
528
+ ye as LOCALE_CONTROL_ID,
529
+ T as LayoutOrientationControl,
530
+ O as LocaleControl,
531
+ Ne as PRICE_PLACEMENT_CONTROL_ID,
532
+ Ie as PRODUCT_COUNT_CONTROL_ID,
533
+ Se as PRODUCT_LAYOUT_CONTROL_ID,
534
+ B as PricePlacementControl,
535
+ F as ProductCountControl,
536
+ L as ProductLayoutControl,
537
+ ae as RecommendationBlockControl,
538
+ ke as SHUFFLE_CONTROL_ID,
539
+ Oe as STRATEGY_CONTROL_ID,
456
540
  D as ShuffleControl,
457
- w as StrategyControl,
458
- Et as adjustProductsToSize,
459
- Ft as formatProductPrice,
460
- A as getBlockElement,
461
- Dt as getCardComposition,
462
- wt as getCurrentLayout,
463
- vt as getMainContainerTbody,
464
- B as isPartnerManagedBlock,
465
- At as regenerateMobileProductRows,
466
- U as regenerateProductRowsWithStyles,
467
- v as setCurrencyAttributes,
468
- Bt as updatePricesInPlace,
469
- x as updateProductContentInPlace,
470
- xt as updateSingleProductContent
541
+ E as StrategyControl,
542
+ Fe as adjustProductsToSize,
543
+ Le as formatProductPrice,
544
+ V as getBlockElement,
545
+ De as getCardComposition,
546
+ Ee as getCurrentLayout,
547
+ we as getMainContainerTbody,
548
+ U as isPartnerManagedBlock,
549
+ Ve as regenerateMobileProductRows,
550
+ A as regenerateProductRowsWithStyles,
551
+ w as setCurrencyAttributes,
552
+ Ue as updatePricesInPlace,
553
+ v as updateProductContentInPlace,
554
+ ve as updateSingleProductContent
471
555
  };