@useinsider/guido 3.17.0 → 3.18.0

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 (110) hide show
  1. package/README.md +6 -5
  2. package/dist/@types/config/schemas.js +7 -6
  3. package/dist/components/Guido.vue.js +10 -10
  4. package/dist/components/Guido.vue2.js +82 -76
  5. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +21 -0
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +106 -0
  7. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue.js +17 -0
  8. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +57 -0
  9. package/dist/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue.js +19 -0
  10. package/dist/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue2.js +63 -0
  11. package/dist/composables/useCustomInterfaceAppearance.js +52 -38
  12. package/dist/composables/useModuleRepair.js +33 -0
  13. package/dist/composables/useRecommendation.js +41 -34
  14. package/dist/composables/useSave.js +30 -29
  15. package/dist/composables/useStripo.js +15 -15
  16. package/dist/composables/useSyncModuleExtractor.js +15 -13
  17. package/dist/composables/validators/useSyncModuleBlockValidator.js +24 -0
  18. package/dist/config/i18n/en/labels.json.js +1 -1
  19. package/dist/config/migrator/index.js +9 -8
  20. package/dist/config/migrator/recommendation/compositionMapper.js +20 -20
  21. package/dist/config/migrator/recommendation/extractors.js +29 -24
  22. package/dist/config/migrator/recommendation/htmlBuilder.js +116 -130
  23. package/dist/config/migrator/recommendation/settingsMapper.js +17 -17
  24. package/dist/config/migrator/recommendationMigrator.js +31 -25
  25. package/dist/config/migrator/recommendationTitleMigrator.js +119 -0
  26. package/dist/enums/academy.js +2 -1
  27. package/dist/enums/date.js +5 -3
  28. package/dist/enums/extensions/recommendationBlock.js +3 -1
  29. package/dist/extensions/Blocks/Items/block.js +118 -49
  30. package/dist/extensions/Blocks/Items/constants/currency.js +25 -0
  31. package/dist/extensions/Blocks/Items/controls/price/currencyLocation.js +25 -24
  32. package/dist/extensions/Blocks/Items/controls/price/currencySymbol.js +12 -11
  33. package/dist/extensions/Blocks/Items/template.js +153 -152
  34. package/dist/extensions/Blocks/Items/utils/constants.js +4 -0
  35. package/dist/extensions/Blocks/Recommendation/block.js +35 -29
  36. package/dist/extensions/Blocks/Recommendation/constants/blockIds.js +1 -1
  37. package/dist/extensions/Blocks/Recommendation/constants/controlIds.js +1 -1
  38. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +29 -27
  39. package/dist/extensions/Blocks/Recommendation/constants/selectors.js +35 -28
  40. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +309 -236
  41. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +241 -180
  42. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +124 -0
  43. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +1 -0
  44. package/dist/extensions/Blocks/Recommendation/controls/title/index.js +44 -0
  45. package/dist/extensions/Blocks/Recommendation/extension.js +31 -29
  46. package/dist/extensions/Blocks/Recommendation/services/configService.js +54 -36
  47. package/dist/extensions/Blocks/Recommendation/settingsPanel.js +23 -4
  48. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +175 -79
  49. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +3 -3
  50. package/dist/extensions/Blocks/Recommendation/templates/titleRows.js +33 -0
  51. package/dist/extensions/Blocks/Recommendation/templates/utils.js +85 -107
  52. package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +22 -0
  53. package/dist/extensions/Blocks/Recommendation/utils/recommendationBlockCount.js +10 -6
  54. package/dist/extensions/Blocks/common-control.js +22 -19
  55. package/dist/guido.css +1 -1
  56. package/dist/services/recommendationApi.js +69 -30
  57. package/dist/src/@types/config/schemas.d.ts +2 -0
  58. package/dist/src/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.d.ts +3 -0
  59. package/dist/src/components/organisms/extensions/recommendation/RemoveStrategyModal.vue.d.ts +2 -0
  60. package/dist/src/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue.d.ts +15 -0
  61. package/dist/src/composables/useConfig.d.ts +2 -0
  62. package/dist/src/composables/useModuleRepair.d.ts +18 -0
  63. package/dist/src/composables/useRecommendation.d.ts +1 -0
  64. package/dist/src/composables/useSyncModuleExtractor.d.ts +2 -0
  65. package/dist/src/composables/validators/useSyncModuleBlockValidator.d.ts +3 -0
  66. package/dist/src/config/migrator/recommendation/extractors.d.ts +8 -0
  67. package/dist/src/config/migrator/recommendationTitleMigrator.d.ts +5 -0
  68. package/dist/src/enums/academy.d.ts +1 -0
  69. package/dist/src/enums/date.d.ts +1 -0
  70. package/dist/src/enums/extensions/recommendationBlock.d.ts +2 -0
  71. package/dist/src/extensions/Blocks/Items/block.d.ts +35 -0
  72. package/dist/src/extensions/Blocks/Items/constants/currency.d.ts +43 -0
  73. package/dist/src/extensions/Blocks/Items/utils/constants.d.ts +6 -0
  74. package/dist/src/extensions/Blocks/Recommendation/constants/blockIds.d.ts +2 -1
  75. package/dist/src/extensions/Blocks/Recommendation/constants/controlIds.d.ts +7 -0
  76. package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +3 -6
  77. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +2 -2
  78. package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +12 -0
  79. package/dist/src/extensions/Blocks/Recommendation/controls/cardComposition/index.d.ts +11 -0
  80. package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +1 -0
  81. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +44 -8
  82. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +16 -0
  83. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +1 -0
  84. package/dist/src/extensions/Blocks/Recommendation/controls/title/index.d.ts +86 -0
  85. package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +12 -1
  86. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +176 -10
  87. package/dist/src/extensions/Blocks/Recommendation/templates/titleRows.d.ts +13 -0
  88. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +7 -0
  89. package/dist/src/extensions/Blocks/Recommendation/utils/nodeConfigWriter.d.ts +31 -0
  90. package/dist/src/extensions/Blocks/Recommendation/utils/recommendationBlockCount.d.ts +6 -2
  91. package/dist/src/extensions/Blocks/common-control.d.ts +4 -1
  92. package/dist/src/mock/api/recommendation-strategies.d.ts +2 -0
  93. package/dist/src/services/recommendationApi.d.ts +4 -1
  94. package/dist/src/stores/config.d.ts +18 -0
  95. package/dist/src/stores/save-as-template.d.ts +4 -3
  96. package/dist/src/utils/genericUtil.d.ts +5 -0
  97. package/dist/src/utils/itemsCurrencyRepair.d.ts +17 -0
  98. package/dist/static/assets/icons/line-change.svg.js +5 -0
  99. package/dist/static/assets/icons/line-delete.svg.js +5 -0
  100. package/dist/static/assets/icons/line-plus.svg.js +5 -0
  101. package/dist/static/styles/components/recommendation-strategy.css.js +155 -0
  102. package/dist/static/styles/customEditorStyle.css.js +3 -1
  103. package/dist/utils/dateUtil.js +23 -10
  104. package/dist/utils/genericUtil.js +28 -27
  105. package/dist/utils/itemsCurrencyRepair.js +39 -0
  106. package/dist/utils/pairProductVariables.js +58 -58
  107. package/dist/utils/templatePreparation.js +35 -34
  108. package/package.json +3 -2
  109. package/dist/composables/useModuleDynamicContentRepair.js +0 -37
  110. package/dist/src/composables/useModuleDynamicContentRepair.d.ts +0 -13
@@ -1,54 +1,71 @@
1
- var f = Object.defineProperty;
2
- var p = (d, l, t) => l in d ? f(d, l, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[l] = t;
3
- var s = (d, l, t) => p(d, typeof l != "symbol" ? l + "" : l, t);
4
- import { CommonControl as g } from "../../../common-control.js";
5
- import { DEFAULT_NODE_CONFIG as c } from "../../constants/defaultConfig.js";
6
- import { RecommendationConfigService as h } from "../../services/configService.js";
7
- import { useRecommendationExtensionStore as y } from "../../store/recommendation.js";
8
- import { AlgorithmControl as N } from "./algorithm.js";
9
- import { ALGORITHM_CONTROL_ID as tt } from "./algorithm.js";
10
- import { CurrencyControl as R } from "./currency.js";
11
- import { CURRENCY_CONTROL_ID as ot } from "./currency.js";
12
- import { FiltersControl as I } from "./filters.js";
13
- import { FILTERS_CONTROL_ID as nt } from "./filters.js";
14
- import { LayoutOrientationControl as _ } from "./layoutOrientation.js";
15
- import { LAYOUT_ORIENTATION_CONTROL_ID as st } from "./layoutOrientation.js";
16
- import { LocaleControl as b } from "./locale.js";
17
- import { LOCALE_CONTROL_ID as lt } from "./locale.js";
18
- import { PricePlacementControl as T } from "./pricePlacement.js";
19
- import { PRICE_PLACEMENT_CONTROL_ID as ut } from "./pricePlacement.js";
20
- import { ProductCountControl as O } from "./productCount.js";
21
- import { PRODUCT_COUNT_CONTROL_ID as ht } from "./productCount.js";
22
- import { ProductLayoutControl as P } from "./productLayout.js";
23
- import { PRODUCT_LAYOUT_CONTROL_ID as Ct } from "./productLayout.js";
24
- import { ShuffleControl as S } from "./shuffle.js";
25
- import { SHUFFLE_CONTROL_ID as pt } from "./shuffle.js";
26
- import { setCurrencyAttributes as L, getBlockElement as k, isPartnerManagedBlock as D, updateProductContentInPlace as E, regenerateProductRowsWithStyles as A } from "./utils.js";
27
- import { adjustProductsToSize as yt, formatProductPrice as Nt, getCardComposition as Rt, getCurrentLayout as It, regenerateMobileProductRows as _t, updatePricesInPlace as bt, updateSingleProductContent as Tt } from "./utils.js";
28
- import { useDebounceFn as m } from "../../../../../node_modules/@vueuse/shared/index.js";
29
- const v = "recommendation-id", w = "ui-elements-recommendation-block";
30
- class Q extends g {
1
+ var m = Object.defineProperty;
2
+ var C = (h, l, t) => l in h ? m(h, l, { enumerable: !0, configurable: !0, writable: !0, value: t }) : h[l] = t;
3
+ var n = (h, l, t) => C(h, typeof l != "symbol" ? l + "" : l, t);
4
+ import { useConfig as p } 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 { CURRENT_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";
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 ht } from "./currency.js";
16
+ import { FiltersControl as S } from "./filters.js";
17
+ import { FILTERS_CONTROL_ID as gt } 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 E } from "./pricePlacement.js";
23
+ import { PRICE_PLACEMENT_CONTROL_ID as _t } from "./pricePlacement.js";
24
+ import { ProductCountControl as k } from "./productCount.js";
25
+ import { PRODUCT_COUNT_CONTROL_ID as Rt } from "./productCount.js";
26
+ import { ProductLayoutControl as D } from "./productLayout.js";
27
+ import { PRODUCT_LAYOUT_CONTROL_ID as Tt } from "./productLayout.js";
28
+ import { ShuffleControl as F } 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 A, getBlockElement as v, isPartnerManagedBlock as x, updateProductContentInPlace as B, regenerateProductRowsWithStyles as U } from "./utils.js";
33
+ import { adjustProductsToSize as kt, formatProductPrice as Dt, getCardComposition as Ft, getCurrentLayout as wt, getMainContainerTbody as At, regenerateMobileProductRows as vt, updatePricesInPlace as xt, updateSingleProductContent as Bt } from "./utils.js";
34
+ import { useDebounceFn as f } from "../../../../../node_modules/@vueuse/shared/index.js";
35
+ const $ = "ui-elements-recommendation-block";
36
+ class at extends N {
31
37
  constructor() {
32
38
  super(...arguments);
33
- s(this, "store", y());
34
- s(this, "storeUnsubscription", () => {
39
+ n(this, "store", R());
40
+ n(this, "storeUnsubscription", () => {
35
41
  });
36
- s(this, "syncedBlockIds", /* @__PURE__ */ new Set());
42
+ // blockId -> fingerprint of the node config as it looked at the last sync.
43
+ n(this, "syncedConfigs", /* @__PURE__ */ new Map());
44
+ // A config change waiting to reach the node config. Deferred so it can ride the
45
+ // re-render's single apply() — one user action must cost one undo press.
46
+ n(this, "pendingNodeConfigWrite", null);
47
+ n(this, "pendingConfigFlushTimer", null);
37
48
  // Sub-control instances for lifecycle management
38
- s(this, "algorithmControl", null);
39
- s(this, "localeControl", null);
40
- s(this, "currencyControl", null);
41
- s(this, "productCountControl", null);
42
- s(this, "productLayoutControl", null);
43
- s(this, "filtersControl", null);
44
- s(this, "shuffleControl", null);
45
- s(this, "pricePlacementControl", null);
46
- s(this, "layoutOrientationControl", null);
49
+ n(this, "algorithmControl", null);
50
+ n(this, "localeControl", null);
51
+ n(this, "currencyControl", null);
52
+ n(this, "productCountControl", null);
53
+ n(this, "productLayoutControl", null);
54
+ n(this, "filtersControl", null);
55
+ n(this, "shuffleControl", null);
56
+ n(this, "pricePlacementControl", null);
57
+ n(this, "layoutOrientationControl", null);
58
+ n(this, "strategyControl", null);
59
+ n(this, "rrsEnabled", !1);
47
60
  /**
48
61
  * Debounced product fetch to prevent rapid API calls during config changes
49
62
  */
50
- s(this, "_debouncedFetchProducts", m(() => {
51
- this.store.fetchRecommendationProducts();
63
+ n(this, "_debouncedFetchProducts", f(async () => {
64
+ try {
65
+ await this.store.fetchRecommendationProducts();
66
+ } finally {
67
+ this._scheduleConfigFlush();
68
+ }
52
69
  }, 500));
53
70
  /**
54
71
  * Debounced content update when products arrive from API.
@@ -61,16 +78,20 @@ class Q extends g {
61
78
  * count. The store pads products to the configured size, so in-place only
62
79
  * fails when the size actually changed.
63
80
  */
64
- s(this, "_debouncedRegenerateWithProducts", m(() => {
81
+ n(this, "_debouncedRegenerateWithProducts", f(() => {
65
82
  const t = this.store.recommendationProducts;
66
- if (!this.currentNode || !this.api || D(this.currentNode))
83
+ if (!this.currentNode || !this.api)
84
+ return;
85
+ const e = this.api.getDocumentModifier(), o = this._stagePendingNodeConfig(e);
86
+ if (x(this.currentNode)) {
87
+ o && (e.apply(new y("Update recommendation configuration")), this.pendingNodeConfigWrite = null, this._clearConfigFlush());
67
88
  return;
68
- const e = this.api.getDocumentModifier();
69
- E({
89
+ }
90
+ B({
70
91
  currentNode: this.currentNode,
71
92
  documentModifier: e,
72
93
  products: t
73
- }) || A({
94
+ }) || U({
74
95
  currentNode: this.currentNode,
75
96
  documentModifier: e,
76
97
  products: t
@@ -78,23 +99,32 @@ class Q extends g {
78
99
  }, 100));
79
100
  }
80
101
  getId() {
81
- return w;
102
+ return $;
82
103
  }
83
- getTemplate() {
84
- return this.algorithmControl = new N(), this.localeControl = new b(), this.currencyControl = new R(), this.productCountControl = new O(), this.productLayoutControl = new P(), this.filtersControl = new I(), this.shuffleControl = new S(), this.pricePlacementControl = new T(), this.layoutOrientationControl = new _(), [
104
+ get _subControls() {
105
+ return [
106
+ this.layoutOrientationControl,
107
+ this.productCountControl,
85
108
  this.algorithmControl,
86
109
  this.localeControl,
87
110
  this.currencyControl,
88
- this.productCountControl,
89
111
  this.productLayoutControl,
90
112
  this.filtersControl,
91
113
  this.shuffleControl,
92
114
  this.pricePlacementControl,
93
- this.layoutOrientationControl
94
- ].forEach((e) => {
95
- e.api = this.api;
115
+ this.strategyControl
116
+ ];
117
+ }
118
+ getTemplate() {
119
+ var t;
120
+ return this.rrsEnabled = p().isFeatureEnabled("reusableRecommendationStrategy"), this._subControls.forEach((e) => {
121
+ var o;
122
+ return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
123
+ }), this.algorithmControl = new T(), this.localeControl = new L(), this.currencyControl = new P(), this.productCountControl = new k(), this.productLayoutControl = new D(), this.filtersControl = new S(), this.shuffleControl = new F(), this.pricePlacementControl = new E(), this.layoutOrientationControl = new O(), this.strategyControl = this.rrsEnabled ? new w() : null, this._subControls.forEach((e) => {
124
+ e && (e.api = this.api);
96
125
  }), `
97
126
  <div class="recommendation-controls-container">
127
+ ${((t = this.strategyControl) == null ? void 0 : t.getTemplate()) ?? ""}
98
128
  ${this.layoutOrientationControl.getTemplate()}
99
129
  ${this.productCountControl.getTemplate()}
100
130
  ${this.productLayoutControl.getTemplate()}
@@ -107,50 +137,39 @@ class Q extends g {
107
137
  </div>
108
138
  `;
109
139
  }
140
+ _showControlsForBlock(t) {
141
+ var i;
142
+ const e = (i = this.getContainer()) == null ? void 0 : i.querySelector(".recommendation-controls-container");
143
+ if (!e)
144
+ return;
145
+ const o = this._getRecommendationIdFromNode(t) === null ? null : c.getConfig(t), r = this.rrsEnabled && !!o && (!!(o != null && o.strategyId) || ((o == null ? void 0 : o.configVersion) ?? 0) >= _);
146
+ e.classList.toggle("strategy-block", r);
147
+ }
110
148
  async onRender() {
111
149
  var o;
150
+ b(this.api);
112
151
  const t = this._getRecommendationIdFromNode(this.currentNode), e = t ?? this.store.currentRecommendationId;
113
- if (e !== null && this.store.setCurrentBlock(e), t !== null && !this.syncedBlockIds.has(t) && (this.syncedBlockIds.add(t), this._syncNodeConfigToStore()), this._listenStateUpdates(), e !== null && ((o = this.store.blockStates[e]) != null && o.isInitialized)) {
152
+ if (e !== null && this.store.setCurrentBlock(e), t !== null && this._syncNodeConfigIfChanged(t), this._listenStateUpdates(), this._showControlsForBlock(this.currentNode), e !== null && ((o = this.store.blockStates[e]) != null && o.isInitialized)) {
114
153
  this._initializeSubControls();
115
154
  return;
116
155
  }
117
156
  await this._fetchBlockData(e), this._initializeSubControls();
118
157
  }
119
158
  onTemplateNodeUpdated(t) {
120
- var r;
159
+ var o;
121
160
  super.onTemplateNodeUpdated(t);
122
161
  const e = this._getRecommendationIdFromNode(t);
123
- e !== null && e !== this.store.currentRecommendationId && this.store.setCurrentBlock(e), e !== null && !this.syncedBlockIds.has(e) && (this.syncedBlockIds.add(e), this._syncNodeConfigToStore()), e !== null && !((r = this.store.blockStates[e]) != null && r.isInitialized) && this._fetchBlockData(e).then(() => {
162
+ 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(() => {
124
163
  this._initializeSubControls();
125
- }), [
126
- this.layoutOrientationControl,
127
- this.productCountControl,
128
- this.algorithmControl,
129
- this.localeControl,
130
- this.currencyControl,
131
- this.productLayoutControl,
132
- this.filtersControl,
133
- this.shuffleControl,
134
- this.pricePlacementControl
135
- ].forEach((n) => {
164
+ }), this._subControls.forEach((r) => {
136
165
  var i;
137
- n != null && n.api && (n.currentNode = t, (i = n.onTemplateNodeUpdated) == null || i.call(n, t));
166
+ r != null && r.api && (r.currentNode = t, (i = r.onTemplateNodeUpdated) == null || i.call(r, t));
138
167
  });
139
168
  }
140
169
  onDestroy() {
141
- this.storeUnsubscription(), [
142
- this.layoutOrientationControl,
143
- this.productCountControl,
144
- this.algorithmControl,
145
- this.localeControl,
146
- this.currencyControl,
147
- this.productLayoutControl,
148
- this.filtersControl,
149
- this.shuffleControl,
150
- this.pricePlacementControl
151
- ].forEach((e) => {
152
- var o;
153
- return (o = e == null ? void 0 : e.onDestroy) == null ? void 0 : o.call(e);
170
+ this.storeUnsubscription(), this._flushPendingNodeConfig(), this._subControls.forEach((t) => {
171
+ var e;
172
+ return (e = t == null ? void 0 : t.onDestroy) == null ? void 0 : e.call(t);
154
173
  });
155
174
  }
156
175
  /**
@@ -158,25 +177,14 @@ class Q extends g {
158
177
  * Each sub-control manages its own form values and event listeners
159
178
  */
160
179
  _initializeSubControls() {
161
- [
162
- this.layoutOrientationControl,
163
- this.productCountControl,
164
- this.algorithmControl,
165
- this.localeControl,
166
- this.currencyControl,
167
- this.productLayoutControl,
168
- this.filtersControl,
169
- this.shuffleControl,
170
- this.pricePlacementControl
171
- ].forEach((e) => {
172
- var o;
173
- e && (e.api = this.api, e.currentNode = this.currentNode, (o = e.onRender) == null || o.call(e));
180
+ this._subControls.forEach((t) => {
181
+ var e;
182
+ t && (t.api = this.api, t.currentNode = this.currentNode, (e = t.onRender) == null || e.call(t));
174
183
  });
175
184
  }
176
185
  /**
177
186
  * Syncs persisted node config into the Pinia store's block state.
178
187
  *
179
- * setCurrentBlock() creates a default entry (USD, en_US, mostPopular).
180
188
  * For saved templates, the real config lives in the node (e.g., TRY, tr_TR).
181
189
  * This method reads it and patches the store so fetchRecommendationProducts()
182
190
  * uses the correct values.
@@ -184,11 +192,76 @@ class Q extends g {
184
192
  * Uses triggerRefetch: false because the fetch hasn't happened yet —
185
193
  * values are being prepared for the upcoming initial fetch.
186
194
  */
195
+ /**
196
+ * Re-syncs the store when the node config moved since we last read it.
197
+ *
198
+ * Undo/redo, the code editor and version-history restore rewrite the node
199
+ * config behind the store's back — Stripo exposes no undo signal, so a
200
+ * fingerprint diff on this hook is the only way to notice (SD-149105).
201
+ * An unchanged fingerprint means the move came from us, so runtime store
202
+ * edits are never clobbered (SD-141049).
203
+ */
204
+ _syncNodeConfigIfChanged(t) {
205
+ this.pendingNodeConfigWrite && this.pendingNodeConfigWrite.blockId !== t && this._flushPendingNodeConfig();
206
+ const e = JSON.stringify(c.getConfig(this.currentNode)), o = this.syncedConfigs.get(t);
207
+ this.syncedConfigs.set(t, e), o !== e && (this.pendingNodeConfigWrite || this._syncNodeConfigToStore());
208
+ }
209
+ _capturePendingNodeConfigWrite() {
210
+ const t = this.store.currentRecommendationId;
211
+ if (!this.currentNode || !this.api || t === null)
212
+ return;
213
+ const { filters: e, strategyId: o, size: r } = this.store.recommendationConfigs;
214
+ this.pendingNodeConfigWrite = {
215
+ blockId: t,
216
+ node: this.currentNode,
217
+ updates: { filters: e, strategyId: o, size: r }
218
+ };
219
+ }
220
+ /**
221
+ * Accumulates the pending write into `documentModifier` without applying, so the
222
+ * caller's apply() commits config and re-render as ONE undo entry.
223
+ *
224
+ * Deliberately does not consume the pending record: the product helpers call
225
+ * apply() only when they actually changed something, so this batch may never be
226
+ * committed and the flush has to stay able to write it standalone.
227
+ * @param documentModifier - The batch to accumulate into
228
+ * @returns Whether anything was staged
229
+ */
230
+ _stagePendingNodeConfig(t) {
231
+ const e = this.pendingNodeConfigWrite;
232
+ return !e || !this.currentNode ? !1 : (c.stageConfig(t, this.currentNode, e.updates), !0);
233
+ }
234
+ /**
235
+ * Arms the guaranteed fallback write, once the product fetch has settled. The
236
+ * delay only has to outlast the re-render debounce that fetch triggers — firing
237
+ * earlier writes the config on its own and the undo entry splits in two again.
238
+ */
239
+ _scheduleConfigFlush() {
240
+ this._clearConfigFlush(), this.pendingConfigFlushTimer = setTimeout(() => {
241
+ this.pendingConfigFlushTimer = null, this._flushPendingNodeConfig();
242
+ }, 800);
243
+ }
244
+ _clearConfigFlush() {
245
+ this.pendingConfigFlushTimer !== null && (clearTimeout(this.pendingConfigFlushTimer), this.pendingConfigFlushTimer = null);
246
+ }
247
+ /**
248
+ * Writes the deferred change standalone when the batch it was staged into never
249
+ * committed. Always targets the LIVE node — the captured one is an immutable
250
+ * snapshot the intervening re-render staled, and saveConfig swallows that failure.
251
+ */
252
+ _flushPendingNodeConfig() {
253
+ const t = this.pendingNodeConfigWrite;
254
+ if (this.pendingNodeConfigWrite = null, this._clearConfigFlush(), !t || !this.api)
255
+ return;
256
+ const e = t.blockId === this.store.currentRecommendationId && this.currentNode ? this.currentNode : t.node, o = c.getConfig(e);
257
+ JSON.stringify(o.filters) === JSON.stringify(t.updates.filters) && o.strategyId === t.updates.strategyId && o.size === t.updates.size || c.updateConfig(this.api, e, t.updates, "Update recommendation filters");
258
+ }
187
259
  _syncNodeConfigToStore() {
188
260
  var r;
189
- const t = h.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((r = this.store.blockStates[e]) == null ? void 0 : r.isInitialized);
261
+ const t = c.getConfig(this.currentNode), e = this.store.currentRecommendationId, o = e !== null && ((r = this.store.blockStates[e]) == null ? void 0 : r.isInitialized);
190
262
  this.store.patchCurrentBlockConfig({
191
263
  strategy: t.strategy,
264
+ strategyId: t.strategyId,
192
265
  language: t.language,
193
266
  size: t.size,
194
267
  productIds: t.productIds,
@@ -249,36 +322,36 @@ class Q extends g {
249
322
  _applySmartDefaults() {
250
323
  if (!this.currentNode || !this.api)
251
324
  return;
252
- const t = h.getConfig(this.currentNode), e = {};
253
- let o = null, r = null, n = null;
254
- if (t.currency.code === c.currency.code) {
255
- const { currencyList: i } = this.store;
256
- i.length > 0 && (i.some(
257
- (u) => u.value === `price.${c.currency.code}`
258
- ) || (o = i[0].value.replace("price.", ""), e.currency = {
259
- ...c.currency,
325
+ const t = c.getConfig(this.currentNode), e = {};
326
+ let o = null, r = null, i = null;
327
+ if (t.currency.code === a.currency.code) {
328
+ const { currencyList: s } = this.store;
329
+ s.length > 0 && (s.some(
330
+ (d) => d.value === `price.${a.currency.code}`
331
+ ) || (o = s[0].value.replace("price.", ""), e.currency = {
332
+ ...a.currency,
260
333
  code: o,
261
334
  symbol: o
262
335
  }));
263
336
  }
264
- if (t.strategy === c.strategy) {
265
- const i = this.store.getActivePredictiveAlgorithms;
266
- i.length > 0 && (i.some(
267
- (u) => u.value === c.strategy
268
- ) || (r = i[0].value, e.strategy = r));
337
+ if (t.strategy === a.strategy) {
338
+ const s = this.store.getActivePredictiveAlgorithms;
339
+ s.length > 0 && (s.some(
340
+ (d) => d.value === a.strategy
341
+ ) || (r = s[0].value, e.strategy = r));
269
342
  }
270
- if (t.language === c.language) {
271
- const i = this.store.getLanguages;
272
- i.length > 0 && (i.some(
273
- (u) => u.value === c.language
274
- ) || (n = i[0].value, e.language = n));
343
+ if (t.language === a.language) {
344
+ const s = this.store.getLanguages;
345
+ s.length > 0 && (s.some(
346
+ (d) => d.value === a.language
347
+ ) || (i = s[0].value, e.language = i));
275
348
  }
276
- !o && !r && !n || (h.updateConfig(
349
+ !o && !r && !i || (c.updateConfig(
277
350
  this.api,
278
351
  this.currentNode,
279
352
  e,
280
353
  "Applied smart defaults"
281
- ), o && e.currency && L({
354
+ ), o && e.currency && A({
282
355
  currentNode: this.currentNode,
283
356
  documentModifier: this.api.getDocumentModifier(),
284
357
  currency: e.currency
@@ -288,24 +361,24 @@ class Q extends g {
288
361
  name: o,
289
362
  value: o,
290
363
  symbol: o,
291
- alignment: c.currency.alignment === "before" ? "0" : "1",
292
- decimalCount: c.currency.decimalCount.toString(),
293
- decimalSeparator: c.currency.decimalSeparator,
294
- thousandSeparator: c.currency.thousandSeparator
364
+ alignment: a.currency.alignment === "before" ? "0" : "1",
365
+ decimalCount: a.currency.decimalCount.toString(),
366
+ decimalSeparator: a.currency.decimalSeparator,
367
+ thousandSeparator: a.currency.thousandSeparator
295
368
  }
296
369
  } : {},
297
370
  ...r ? { strategy: r } : {},
298
- ...n ? { language: n } : {}
371
+ ...i ? { language: i } : {}
299
372
  }, { triggerRefetch: !1 }));
300
373
  }
301
374
  /**
302
375
  * Reads the recommendation-id attribute from the block element within the node
303
376
  */
304
377
  _getRecommendationIdFromNode(t) {
305
- const e = k(t);
378
+ const e = v(t);
306
379
  if (!e || !("getAttribute" in e))
307
380
  return null;
308
- const o = e.getAttribute(v);
381
+ const o = e.getAttribute(I);
309
382
  if (!o)
310
383
  return null;
311
384
  const r = parseInt(o);
@@ -328,64 +401,52 @@ class Q extends g {
328
401
  const { store: t } = this;
329
402
  let e = t.recommendationProducts, o = t.$state.configVersion, r = t.currentRecommendationId;
330
403
  this.storeUnsubscription = t.$subscribe(() => {
331
- const n = t.currentRecommendationId;
332
- if (n !== r) {
333
- r = n, e = t.recommendationProducts, o = t.$state.configVersion;
404
+ const i = t.currentRecommendationId;
405
+ if (i !== r) {
406
+ r = i, e = t.recommendationProducts, o = t.$state.configVersion;
334
407
  return;
335
408
  }
336
- const i = t.$state.configVersion;
337
- i !== o && (o = i, this._persistFiltersToNodeConfig(), this._debouncedFetchProducts());
338
- const a = t.recommendationProducts, u = a !== e, C = Array.isArray(a) && a.length > 0;
339
- u && C && (e = a, this._debouncedRegenerateWithProducts());
409
+ const s = t.$state.configVersion;
410
+ s !== o && (o = s, this._capturePendingNodeConfigWrite(), this._debouncedFetchProducts());
411
+ const u = t.recommendationProducts, d = u !== e, g = Array.isArray(u) && u.length > 0;
412
+ d && g && (e = u, this._debouncedRegenerateWithProducts());
340
413
  });
341
414
  }
342
- /**
343
- * Persists the current filter state from Pinia store to the Stripo node config.
344
- * This ensures filters survive template save/reload cycles.
345
- */
346
- _persistFiltersToNodeConfig() {
347
- if (!this.currentNode || !this.api)
348
- return;
349
- const { filters: t } = this.store.recommendationConfigs, e = h.getConfig(this.currentNode).filters;
350
- JSON.stringify(e) !== JSON.stringify(t) && h.updateConfig(
351
- this.api,
352
- this.currentNode,
353
- { filters: t },
354
- "Update recommendation filters"
355
- );
356
- }
357
415
  }
358
416
  export {
359
- tt as ALGORITHM_CONTROL_ID,
360
- N as AlgorithmControl,
361
- w as CONTROL_BLOCK_ID,
362
- ot as CURRENCY_CONTROL_ID,
363
- R as CurrencyControl,
364
- nt as FILTERS_CONTROL_ID,
365
- I as FiltersControl,
366
- st as LAYOUT_ORIENTATION_CONTROL_ID,
367
- lt as LOCALE_CONTROL_ID,
368
- _ as LayoutOrientationControl,
369
- b as LocaleControl,
370
- ut as PRICE_PLACEMENT_CONTROL_ID,
371
- ht as PRODUCT_COUNT_CONTROL_ID,
372
- Ct as PRODUCT_LAYOUT_CONTROL_ID,
373
- T as PricePlacementControl,
374
- O as ProductCountControl,
375
- P as ProductLayoutControl,
376
- Q as RecommendationBlockControl,
377
- pt as SHUFFLE_CONTROL_ID,
378
- S as ShuffleControl,
379
- yt as adjustProductsToSize,
380
- Nt as formatProductPrice,
381
- k as getBlockElement,
382
- Rt as getCardComposition,
383
- It as getCurrentLayout,
384
- D as isPartnerManagedBlock,
385
- _t as regenerateMobileProductRows,
386
- A as regenerateProductRowsWithStyles,
387
- L as setCurrencyAttributes,
388
- bt as updatePricesInPlace,
389
- E as updateProductContentInPlace,
390
- Tt as updateSingleProductContent
417
+ ut as ALGORITHM_CONTROL_ID,
418
+ T as AlgorithmControl,
419
+ $ as CONTROL_BLOCK_ID,
420
+ ht as CURRENCY_CONTROL_ID,
421
+ P as CurrencyControl,
422
+ gt as FILTERS_CONTROL_ID,
423
+ S as FiltersControl,
424
+ Ct as LAYOUT_ORIENTATION_CONTROL_ID,
425
+ yt as LOCALE_CONTROL_ID,
426
+ O as LayoutOrientationControl,
427
+ L as LocaleControl,
428
+ _t as PRICE_PLACEMENT_CONTROL_ID,
429
+ Rt as PRODUCT_COUNT_CONTROL_ID,
430
+ Tt as PRODUCT_LAYOUT_CONTROL_ID,
431
+ E as PricePlacementControl,
432
+ k as ProductCountControl,
433
+ D as ProductLayoutControl,
434
+ at as RecommendationBlockControl,
435
+ St as SHUFFLE_CONTROL_ID,
436
+ Lt as STRATEGY_CONTROL_ID,
437
+ F as ShuffleControl,
438
+ w as StrategyControl,
439
+ kt as adjustProductsToSize,
440
+ Dt as formatProductPrice,
441
+ v as getBlockElement,
442
+ Ft as getCardComposition,
443
+ wt as getCurrentLayout,
444
+ At as getMainContainerTbody,
445
+ x as isPartnerManagedBlock,
446
+ vt as regenerateMobileProductRows,
447
+ U as regenerateProductRowsWithStyles,
448
+ A as setCurrencyAttributes,
449
+ xt as updatePricesInPlace,
450
+ B as updateProductContentInPlace,
451
+ Bt as updateSingleProductContent
391
452
  };