@useinsider/guido 3.21.0-beta.ff98fc3 → 3.21.1-beta.18ab939

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.
package/README.md CHANGED
@@ -582,9 +582,9 @@ import '@useinsider/guido/style';
582
582
 
583
583
  ### Subpath entries
584
584
 
585
- Two surfaces also ship as their own entry points. Importing one pulls in only its
586
- own dependencies, so a consumer that needs the store or the tracking-id helpers
587
- never loads the editor:
585
+ Three surfaces also ship as their own entry points. Importing one pulls in only its
586
+ own dependencies, so a consumer that needs the store, the tracking-id helpers or the
587
+ runtime prefetch never loads the editor:
588
588
 
589
589
  ```typescript
590
590
  // Live editor state, published by the editor into the host's shared Pinia instance.
@@ -595,11 +595,41 @@ import type { GuidoEmailEditorState } from '@useinsider/guido/editor-state';
595
595
  // Persistent link ids for the click heatmap.
596
596
  import { assignTrackingIds, TRACK_ID_ATTRIBUTE } from '@useinsider/guido/tracking-ids';
597
597
  import type { TrackingIdResult } from '@useinsider/guido/tracking-ids';
598
+
599
+ // Start downloading the Stripo editor runtime before the editor opens.
600
+ import { prefetchGuidoRuntime } from '@useinsider/guido/prefetch';
598
601
  ```
599
602
 
600
- Both are re-exported from the root barrel as well; the subpath is what keeps the
603
+ All three are re-exported from the root barrel as well; the subpath is what keeps the
601
604
  editor out of the consumer's module graph.
602
605
 
606
+ ### Runtime prefetch
607
+
608
+ ```typescript
609
+ import { prefetchGuidoRuntime } from '@useinsider/guido/prefetch';
610
+
611
+ prefetchGuidoRuntime(); // e.g. when the user lands on the page that opens the editor
612
+ ```
613
+
614
+ Call it as early as the host knows an editor is likely to open. It appends one
615
+ `<link rel="prefetch" data-guido-prefetch>` per file of the pinned Stripo runtime
616
+ (`src/static/stripo-runtime-manifest.json`) from
617
+ `https://email-static.useinsider.com/guido/<stripo version>/`, so the files are in the
618
+ HTTP cache when `<Guido>` mounts. It only downloads: no Stripo code runs and the
619
+ editor's startup order does not change.
620
+
621
+ - Returns `void` and never throws.
622
+ - Idempotent: later calls add nothing.
623
+ - Adds nothing when the runtime is already loading or loaded (`#UiEditorScript` exists
624
+ or `window.UIEditor` is defined), when `navigator.connection.saveData` is on, or when
625
+ `navigator.connection.effectiveType` is `slow-2g` or `2g`.
626
+ - The `guido_editor_open` metric reports it as `runtime_prefetch`: `none` (not called
627
+ before Guido's setup), `pending` (some files still downloading) or `done`.
628
+
629
+ After bumping `guido.stripo.version`, regenerate the file list with
630
+ `npm run stripo:manifest`; a unit test fails while the manifest's version differs from
631
+ the pinned one.
632
+
603
633
  ---
604
634
 
605
635
  ## Constants
@@ -1,6 +1,7 @@
1
- import { SYNC_MODULE_CLASS as S } from "./useSyncModuleExtractor.js";
2
- import g from "../package.json.js";
3
- const s = "guido:open:", b = "total", P = [
1
+ import { SYNC_MODULE_CLASS as w } from "./useSyncModuleExtractor.js";
2
+ import { readRuntimePrefetchState as M } from "../utils/runtimePrefetch.js";
3
+ import f from "../package.json.js";
4
+ const s = "guido:open:", k = "total", A = [
4
5
  "setup",
5
6
  "host_ready",
6
7
  "migration_start",
@@ -28,7 +29,7 @@ const s = "guido:open:", b = "total", P = [
28
29
  ["editor_config", "blocks_config_ready", "init_editor"],
29
30
  ["stripo_load", "init_editor", "ready"],
30
31
  ["token", "token_start", "token_end"]
31
- ], h = (e) => new RegExp(`(?:^|[\\s"'])(?:${e})(?=[\\s"'])`, "g"), A = /<img\b/gi, N = h(S), $ = /\srecommendation-id=/g, C = h("items-block-v2|esd-(?:cart|browsed|purchased)-items-block"), O = "esd-timer-id", f = {
32
+ ], b = (e) => new RegExp(`(?:^|[\\s"'])(?:${e})(?=[\\s"'])`, "g"), N = /<img\b/gi, $ = b(w), C = /\srecommendation-id=/g, O = b("items-block-v2|esd-(?:cart|browsed|purchased)-items-block"), I = "esd-timer-id", g = {
32
33
  html_bytes: null,
33
34
  css_bytes: null,
34
35
  image_count: null,
@@ -38,8 +39,8 @@ const s = "guido:open:", b = "total", P = [
38
39
  has_timers: null,
39
40
  force_recreate: null
40
41
  };
41
- let c = null;
42
- const d = (e) => {
42
+ let d = null;
43
+ const i = (e) => {
43
44
  try {
44
45
  e();
45
46
  } catch (t) {
@@ -48,27 +49,27 @@ const d = (e) => {
48
49
  }, E = () => window.DD_RUM, y = (e, t) => e === void 0 || t === void 0 ? null : Math.round(t - e), _ = (e, t) => {
49
50
  var r;
50
51
  return ((r = e.match(t)) == null ? void 0 : r.length) ?? 0;
51
- }, k = (e) => new TextEncoder().encode(e).length, I = (e) => {
52
+ }, h = (e) => new TextEncoder().encode(e).length, L = (e) => {
52
53
  if (!e)
53
- return f;
54
+ return g;
54
55
  try {
55
56
  const { html: t, css: r, forceRecreate: o } = e;
56
57
  return {
57
- html_bytes: k(t),
58
- css_bytes: k(r),
59
- image_count: _(t, A),
60
- synced_module_count: _(t, N),
61
- recommendation_block_count: _(t, $),
62
- items_block_count: _(t, C),
63
- has_timers: t.includes(O),
58
+ html_bytes: h(t),
59
+ css_bytes: h(r),
60
+ image_count: _(t, N),
61
+ synced_module_count: _(t, $),
62
+ recommendation_block_count: _(t, C),
63
+ items_block_count: _(t, O),
64
+ has_timers: t.includes(I),
64
65
  force_recreate: o
65
66
  };
66
67
  } catch (t) {
67
- return console.debug("guido:open: template weight failed", t), f;
68
+ return console.debug("guido:open: template weight failed", t), g;
68
69
  }
69
70
  }, T = () => {
70
- d(() => {
71
- P.forEach((e) => performance.clearMarks(`${s}${e}`)), [...p.map(([e]) => e), b].forEach((e) => performance.clearMeasures(`${s}${e}`));
71
+ i(() => {
72
+ A.forEach((e) => performance.clearMarks(`${s}${e}`)), [...p.map(([e]) => e), k].forEach((e) => performance.clearMeasures(`${s}${e}`));
72
73
  });
73
74
  }, v = (e) => {
74
75
  const t = {
@@ -76,6 +77,7 @@ const d = (e) => {
76
77
  context: null,
77
78
  template: null,
78
79
  scriptPreloaded: null,
80
+ runtimePrefetch: null,
79
81
  wasBackgrounded: document.visibilityState === "hidden",
80
82
  finished: e,
81
83
  onVisibilityChange: () => {
@@ -87,41 +89,42 @@ const d = (e) => {
87
89
  if (e.finished || e.marks[t] !== void 0)
88
90
  return;
89
91
  const r = performance.now();
90
- e.marks[t] = r, e === c && d(() => performance.mark(`${s}${t}`, { startTime: r }));
92
+ e.marks[t] = r, e === d && i(() => performance.mark(`${s}${t}`, { startTime: r }));
91
93
  }, u = (e) => {
92
94
  e.finished = !0, document.removeEventListener("visibilitychange", e.onVisibilityChange);
93
- }, L = (e, t) => {
94
- const { marks: r } = e, o = p.map(([n, a, i]) => [n, r[a], r[i]]);
95
- o.push([b, r.setup, t]), o.forEach(([n, a, i]) => {
96
- a !== void 0 && i !== void 0 && d(() => performance.measure(`${s}${n}`, { start: a, end: i }));
95
+ }, B = (e, t) => {
96
+ const { marks: r } = e, o = p.map(([n, a, c]) => [n, r[a], r[c]]);
97
+ o.push([k, r.setup, t]), o.forEach(([n, a, c]) => {
98
+ a !== void 0 && c !== void 0 && i(() => performance.measure(`${s}${n}`, { start: a, end: c }));
97
99
  });
98
- }, B = (e, t, r) => {
100
+ }, D = (e, t, r) => {
99
101
  const { marks: o, context: n } = e, a = Object.fromEntries(
100
- p.map(([i, M, R]) => [`${i}_ms`, y(o[M], o[R])])
102
+ p.map(([c, R, S]) => [`${c}_ms`, y(o[R], o[S])])
101
103
  );
102
104
  return {
103
105
  outcome: t,
104
106
  open_ms: y(o.setup, r),
105
107
  ...a,
106
108
  script_preloaded: e.scriptPreloaded,
107
- ...I(e.template),
109
+ runtime_prefetch: e.runtimePrefetch,
110
+ ...L(e.template),
108
111
  partner_name: (n == null ? void 0 : n.partnerName) ?? null,
109
112
  product_type: (n == null ? void 0 : n.productType) ?? null,
110
113
  template_id: (n == null ? void 0 : n.templateId) ?? null,
111
114
  variation_id: (n == null ? void 0 : n.variationId) ?? null,
112
- guido_version: g.version,
113
- stripo_version: g.guido.stripo.version,
115
+ guido_version: f.version,
116
+ stripo_version: f.guido.stripo.version,
114
117
  was_backgrounded: e.wasBackgrounded
115
118
  };
116
119
  }, m = (e, t) => {
117
- d(() => {
118
- const r = e.marks.ready ?? performance.now(), o = B(e, t, r);
119
- e.template = null, e === c && L(e, r), console.debug("guido:open", o), d(() => {
120
+ i(() => {
121
+ const r = e.marks.ready ?? performance.now(), o = D(e, t, r);
122
+ e.template = null, e === d && B(e, r), console.debug("guido:open", o), i(() => {
120
123
  var n, a;
121
124
  return (a = (n = E()) == null ? void 0 : n.addAction) == null ? void 0 : a.call(n, "guido_editor_open", o);
122
125
  });
123
126
  });
124
- }, w = (e) => ({
127
+ }, P = (e) => ({
125
128
  mark: (t) => l(e, t),
126
129
  timed: async (t, r) => {
127
130
  l(e, `${t}_start`);
@@ -138,7 +141,7 @@ const d = (e) => {
138
141
  e.scriptPreloaded = t;
139
142
  },
140
143
  markReady: () => {
141
- e.finished || (l(e, "ready"), u(e), d(() => {
144
+ e.finished || (l(e, "ready"), u(e), i(() => {
142
145
  var t, r;
143
146
  return (r = (t = E()) == null ? void 0 : t.addTiming) == null ? void 0 : r.call(t, "guido_editor_ready");
144
147
  }), setTimeout(() => m(e, "ready"), 0));
@@ -147,13 +150,15 @@ const d = (e) => {
147
150
  e.finished || (u(e), m(e, "error"));
148
151
  },
149
152
  dispose: () => {
150
- e.finished || (u(e), m(e, "abandoned")), e === c && (T(), c = null);
153
+ e.finished || (u(e), m(e, "abandoned")), e === d && (T(), d = null);
151
154
  }
152
- }), U = () => {
155
+ }), F = () => {
153
156
  const e = v(!1);
154
- return T(), c = e, document.addEventListener("visibilitychange", e.onVisibilityChange), l(e, "setup"), w(e);
155
- }, V = () => w(c ?? v(!0));
157
+ return T(), d = e, i(() => {
158
+ e.runtimePrefetch = M();
159
+ }), document.addEventListener("visibilitychange", e.onVisibilityChange), l(e, "setup"), P(e);
160
+ }, G = () => P(d ?? v(!0));
156
161
  export {
157
- U as startEditorOpenMetrics,
158
- V as useEditorOpenMetrics
162
+ F as startEditorOpenMetrics,
163
+ G as useEditorOpenMetrics
159
164
  };
@@ -5,44 +5,50 @@ import { useCustomInterfaceAppearance as _ } from "./useCustomInterfaceAppearanc
5
5
  import { useEditorOpenMetrics as z } from "./useEditorOpenMetrics.js";
6
6
  import { useFullStoryBridge as $ } from "./useFullStoryBridge.js";
7
7
  import { useModuleRepair as G } from "./useModuleRepair.js";
8
- import { useStripoEventHandler as J } from "./useStripoEventHandler.js";
9
- import { useStripoNotifications as X } from "./useStripoNotifications.js";
8
+ import { useStripoEventHandler as X } from "./useStripoEventHandler.js";
9
+ import { useStripoNotifications as J } from "./useStripoNotifications.js";
10
10
  import { useToaster as K } from "./useToaster.js";
11
11
  import { localePatch as Q } from "../config/i18n/index.js";
12
- import { en as M } from "../config/i18n/en/index.js";
12
+ import { en as B } from "../config/i18n/en/index.js";
13
13
  import { ToasterTypeOptions as W } from "../enums/toaster.js";
14
14
  import { useStripoApi as Y } from "../services/stripoApi.js";
15
15
  import Z from "../static/styles/customEditorStyle.css.js";
16
- import { useEditorStore as T } from "../stores/editor.js";
16
+ import { useEditorStore as M } from "../stores/editor.js";
17
17
  import { buildMergeTagEntries as ee, flattenDynamicContentList as te } from "../utils/genericUtil.js";
18
- import oe from "../package.json.js";
19
- let a = null, v = !1;
18
+ import { getStripoRuntimeBaseUrl as oe } from "../utils/stripoRuntime.js";
19
+ let d = null, v = !1;
20
20
  const be = () => {
21
- const { features: u, template: m, isFeatureEnabled: p } = j(), { handleError: f, showToaster: B } = K(), { getToken: F, getCustomFonts: A, getSyncModulesStatus: V } = Y(), { handleEvent: P } = J(), { handleModuleAdd: R } = G(), { getStripoBlocksConfig: D } = N(), { getStripoNotifications: U } = X(), t = z(), g = () => a || (a = new Promise((i, d) => {
22
- var s;
21
+ const { features: u, template: m, isFeatureEnabled: p } = j(), { handleError: f, showToaster: T } = K(), { getToken: F, getCustomFonts: A, getSyncModulesStatus: P } = Y(), { handleEvent: R } = X(), { handleModuleAdd: U } = G(), { getStripoBlocksConfig: V } = N(), { getStripoNotifications: D } = J(), e = z(), g = () => d || (d = new Promise((s, a) => {
23
22
  if (document.getElementById("UiEditorScript")) {
24
- i();
23
+ s();
25
24
  return;
26
25
  }
27
- const r = oe.guido, n = `https://email-static.useinsider.com/guido/${(s = r == null ? void 0 : r.stripo) == null ? void 0 : s.version}/UIEditor.js`, e = document.createElement("script");
28
- e.id = "UiEditorScript", e.type = "module", e.src = n, e.onload = () => {
29
- v = !0, i();
30
- }, e.onerror = () => {
31
- e.remove(), d(new Error(`Failed to load Stripo UIEditor script from S3: ${n}`));
32
- }, document.body.appendChild(e);
33
- }), a.catch(() => {
34
- a = null;
35
- }), a), I = async (i, d, r, l = [], n = !1) => {
36
- var C, k, w, b;
37
- const e = T(), { html: s, css: y } = i, { baseBlocks: S, extensions: L } = await D();
38
- t.mark("blocks_config_ready");
39
- const E = ((C = u.value) == null ? void 0 : C.displayConditions) ?? !0, O = ((k = u.value) == null ? void 0 : k.modulesDisabled) ?? !1, h = !!s || (((w = m.value) == null ? void 0 : w.forceRecreate) ?? !1), q = "https://email-static.useinsider.com https://edge.fullstory.com https://rs.fullstory.com";
40
- t.setTemplate({ html: s, css: y, forceRecreate: h }), _().importCss(), t.mark("init_editor"), await window.UIEditor.initEditor(
26
+ const i = oe();
27
+ if (!i) {
28
+ a(
29
+ new Error("guido.stripo.version is not set in package.json. Please configure the Stripo version.")
30
+ );
31
+ return;
32
+ }
33
+ const n = `${i}UIEditor.js`, t = document.createElement("script");
34
+ t.id = "UiEditorScript", t.type = "module", t.src = n, t.onload = () => {
35
+ v = !0, s();
36
+ }, t.onerror = () => {
37
+ t.remove(), a(new Error(`Failed to load Stripo UIEditor script from S3: ${n}`));
38
+ }, document.body.appendChild(t);
39
+ }), d.catch(() => {
40
+ d = null;
41
+ }), d), I = async (s, a, i, n = [], t = !1) => {
42
+ var C, w, k, b;
43
+ const o = M(), { html: c, css: S } = s, { baseBlocks: y, extensions: L } = await V();
44
+ e.mark("blocks_config_ready");
45
+ const E = ((C = u.value) == null ? void 0 : C.displayConditions) ?? !0, O = ((w = u.value) == null ? void 0 : w.modulesDisabled) ?? !1, h = !!c || (((k = m.value) == null ? void 0 : k.forceRecreate) ?? !1), q = "https://email-static.useinsider.com https://edge.fullstory.com https://rs.fullstory.com";
46
+ e.setTemplate({ html: c, css: S, forceRecreate: h }), _().importCss(), e.mark("init_editor"), await window.UIEditor.initEditor(
41
47
  document.querySelector("#guido-editor"),
42
48
  {
43
- metadata: d,
44
- html: s,
45
- css: y,
49
+ metadata: a,
50
+ html: c,
51
+ css: S,
46
52
  forceRecreate: h,
47
53
  locale: "en",
48
54
  undoButtonSelector: "#guido__undo-button",
@@ -58,7 +64,7 @@ const be = () => {
58
64
  customConditionsEnabled: E,
59
65
  enableXSSSecurity: !0,
60
66
  modulesDisabled: O,
61
- syncModulesEnabled: n,
67
+ syncModulesEnabled: t,
62
68
  messageSettingsEnabled: !0,
63
69
  displayGmailAnnotations: !0,
64
70
  displayHiddenPreheader: !1,
@@ -69,55 +75,55 @@ const be = () => {
69
75
  selectElementAfterDrop: !0,
70
76
  sameFontSizeForOutlook: !0,
71
77
  allowedScriptSourceDomains: q,
72
- ...S ? { baseBlocks: S } : {},
78
+ ...y ? { baseBlocks: y } : {},
73
79
  editorFonts: {
74
80
  showDefaultStandardFonts: !0,
75
81
  showDefaultNotStandardFonts: !0,
76
- customFonts: l
82
+ customFonts: n
77
83
  },
78
84
  mergeTags: [
79
85
  {
80
86
  entries: ee(
81
- r.preselectedDynamicContentList,
87
+ i.preselectedDynamicContentList,
82
88
  te((b = m.value) == null ? void 0 : b.dynamicContentList),
83
89
  p("liquidSyntax")
84
90
  )
85
91
  }
86
92
  ],
87
- async onTokenRefreshRequest(o) {
93
+ async onTokenRefreshRequest(r) {
88
94
  try {
89
- t.mark("token_start");
90
- const c = await F();
91
- t.mark("token_end"), o(c);
92
- } catch (c) {
93
- f(c, "Failed to refresh token");
95
+ e.mark("token_start");
96
+ const l = await F();
97
+ e.mark("token_end"), r(l);
98
+ } catch (l) {
99
+ f(l, "Failed to refresh token");
94
100
  }
95
101
  },
96
102
  onTemplateLoaded() {
97
103
  try {
98
- const { activateCustomViewStyles: o, updateTimerInClonedTemplate: c } = H(), { injectFullStory: x } = $();
99
- _().importCss(), o(), x(), c(), r.onReady(), e.isStripoInitialized = !0, e.loadingStatus = !1, setTimeout(() => {
100
- e.hasChanges = !1;
101
- }, 1e3), t.markReady();
102
- } catch (o) {
103
- f(o, "Failed to load custom interface appearance");
104
+ const { activateCustomViewStyles: r, updateTimerInClonedTemplate: l } = H(), { injectFullStory: x } = $();
105
+ _().importCss(), r(), x(), l(), i.onReady(), o.isStripoInitialized = !0, o.loadingStatus = !1, setTimeout(() => {
106
+ o.hasChanges = !1;
107
+ }, 1e3), e.markReady();
108
+ } catch (r) {
109
+ f(r, "Failed to load custom interface appearance");
104
110
  }
105
111
  },
106
- onCodeEditorVisibilityChanged(o) {
107
- e.isCodeEditorOpen = o;
112
+ onCodeEditorVisibilityChanged(r) {
113
+ o.isCodeEditorOpen = r;
108
114
  },
109
- onEditorVisualModeChanged(o) {
110
- e.editorVisualMode = o.toLowerCase();
115
+ onEditorVisualModeChanged(r) {
116
+ o.editorVisualMode = r.toLowerCase();
111
117
  },
112
- onVersionHistoryVisibilityChanged(o) {
113
- e.isVersionHistoryOpen = o;
118
+ onVersionHistoryVisibilityChanged(r) {
119
+ o.isVersionHistoryOpen = r;
114
120
  },
115
121
  onDataChanged() {
116
- e.hasChanges = !0, e.changeSeq += 1;
122
+ o.hasChanges = !0, o.changeSeq += 1;
117
123
  },
118
- onEvent: P,
119
- onModuleAdd: R,
120
- notifications: U(),
124
+ onEvent: R,
125
+ onModuleAdd: U,
126
+ notifications: D(),
121
127
  // Stripo deselects the block on any click outside the canvas, so every surface
122
128
  // that belongs to the block's own flow has to be listed here (SD-153273).
123
129
  ignoreClickOutsideSelectors: [
@@ -132,24 +138,24 @@ const be = () => {
132
138
  }
133
139
  );
134
140
  };
135
- return { initPlugin: async (i, d, r) => {
136
- const l = T();
141
+ return { initPlugin: async (s, a, i) => {
142
+ const n = M();
137
143
  try {
138
- t.mark("plugin_start"), t.setScriptPreloaded(v), await g(), t.mark("script_ready");
139
- const [n, e] = await Promise.all([
144
+ e.mark("plugin_start"), e.setScriptPreloaded(v), await g(), e.mark("script_ready");
145
+ const [t, o] = await Promise.all([
140
146
  A(),
141
- V()
147
+ P()
142
148
  ]);
143
- t.mark("fonts_sync_ready"), l.syncModulesEnabled = e, await I(i, d, r, n, e);
149
+ e.mark("fonts_sync_ready"), n.syncModulesEnabled = o, await I(s, a, i, t, o);
144
150
  } catch {
145
- l.loadingStatus = !1, B({
151
+ n.loadingStatus = !1, T({
146
152
  type: W.Error,
147
- message: M["An error has occurred. Please report the error code to support."],
153
+ message: B["An error has occurred. Please report the error code to support."],
148
154
  actionButton: {
149
- text: M["Reload page"],
155
+ text: B["Reload page"],
150
156
  onClick: () => window.location.reload()
151
157
  }
152
- }), t.markFailed();
158
+ }), e.markFailed();
153
159
  }
154
160
  }, preloadRuntime: () => {
155
161
  g().catch(() => {
@@ -88,7 +88,7 @@ const d = [
88
88
  /<!--\[if\s\(mso 16\)\]>\s*<style\s*\S*>\s*a\s*\{\s*text-decoration\s*:\s*none\s*;*\s*\}\s*<\/style>\s*<!\[endif\]-->/g,
89
89
  /<!--\[if\sgte mso 9\]>\s*<style\s*\S*>\s*sup\s*\{\s*font-size\s*:\s*100%\s*!important\s*;*\s*\}\s*<\/style>\s*<!\[endif\]-->/g,
90
90
  /<!--\[if\sgte mso 9\]>\s*<noscript>\s*<xml>\s*<o:OfficeDocumentSettings>\s*<o:AllowPNG>\s*<\/o:AllowPNG>\s*<o:PixelsPerInch>\d+<\/o:PixelsPerInch>\s*<\/o:OfficeDocumentSettings>\s*<\/xml>\s*<\/noscript>\s*<!\[endif\]-->/g,
91
- /<!--\[if mso\]>\s*<xml>\s*<w:WordDocument\s+xmlns:w="urn:schemas-microsoft-com:office:word">\s*<w:DontUseAdvancedTypographyReadingMail><\/w:DontUseAdvancedTypographyReadingMail>\s*<\/w:WordDocument>\s*<\/xml>\s*<!\[endif\]-->/g,
91
+ /<!--\[if mso\]>\s*<xml>\s*<w:WordDocument\s+xmlns:w="urn:schemas-microsoft-com:office:word">\s*<w:DontUseAdvancedTypographyReadingMail\s*(?:\/>|><\/w:DontUseAdvancedTypographyReadingMail>)\s*<\/w:WordDocument>\s*<\/xml>\s*<!\[endif\]-->/g,
92
92
  /<\!--\[if \!mso\]><\!--\s*\d*\s*-->\s*<\!--\[if \!mso\]><\!--\s*\d*\s*-->\s*<\!--<!\[endif\]-->/g,
93
93
  /<!--\[if\s\!mso\]>\s*<!-- \d -->/g
94
94
  ],
@@ -1,23 +1,23 @@
1
- var d = Object.defineProperty;
2
- var h = (r, s, t) => s in r ? d(r, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[s] = t;
3
- var c = (r, s, t) => h(r, typeof s != "symbol" ? s + "" : s, t);
4
- import { UEAttr as l } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
- import { CommonControl as g } from "../../../common-control.js";
1
+ var h = Object.defineProperty;
2
+ var l = (r, s, t) => s in r ? h(r, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[s] = t;
3
+ var d = (r, s, t) => l(r, typeof s != "symbol" ? s + "" : s, t);
4
+ import { UEAttr as g } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
5
+ import { CommonControl as m } from "../../../common-control.js";
6
6
  import { RecommendationConfigService as n } from "../../services/configService.js";
7
- import { useRecommendationExtensionStore as m } from "../../store/recommendation.js";
8
- import { mapLegacyStrategy as u } from "../../utils/legacyStrategyMap.js";
9
- const p = "recommendation-algorithm-control", i = {
7
+ import { useRecommendationExtensionStore as u } from "../../store/recommendation.js";
8
+ import { mapLegacyStrategy as p } from "../../utils/legacyStrategyMap.js";
9
+ const C = "recommendation-algorithm-control", i = {
10
10
  ALGORITHM: "strategy",
11
11
  PRODUCT_IDS: "productIds"
12
12
  };
13
- class R extends g {
13
+ class S extends m {
14
14
  constructor() {
15
15
  super(...arguments);
16
16
  // Store is used ONLY for API-fetched data (algorithms list), not for config
17
- c(this, "store", m());
17
+ d(this, "store", u());
18
18
  }
19
19
  getId() {
20
- return p;
20
+ return C;
21
21
  }
22
22
  getTemplate() {
23
23
  return `
@@ -46,10 +46,10 @@ class R extends g {
46
46
  super.onTemplateNodeUpdated(t), this._initializeSelectItems(), this._setFormValues();
47
47
  }
48
48
  _setFormValues() {
49
- const t = n.getConfig(this.currentNode), e = u(t.strategy) ?? t.strategy;
49
+ const t = n.getConfig(this.currentNode), e = p(t.strategy) ?? t.strategy;
50
50
  this._setProductIdsVisibility(e);
51
- const o = { [i.ALGORITHM]: e }, a = t.productIds.join(",");
52
- this.api.getValues()[i.PRODUCT_IDS] !== a && (o[i.PRODUCT_IDS] = a), this.api.updateValues(o);
51
+ const o = { [i.ALGORITHM]: e }, a = t.productIds.join(","), c = this.api.getValues()[i.PRODUCT_IDS];
52
+ c !== a && c !== this.store.recommendationConfigs.productIds.join(",") && (o[i.PRODUCT_IDS] = a), this.api.updateValues(o);
53
53
  }
54
54
  _initializeSelectItems() {
55
55
  var e;
@@ -58,7 +58,7 @@ class R extends g {
58
58
  try {
59
59
  this.api.setUIEAttribute(
60
60
  i.ALGORITHM,
61
- l.SELECTPICKER.items,
61
+ g.SELECTPICKER.items,
62
62
  t
63
63
  );
64
64
  } catch (o) {
@@ -93,12 +93,7 @@ class R extends g {
93
93
  return;
94
94
  }
95
95
  const o = t === "" ? [] : t.split(",");
96
- n.updateConfig(
97
- this.api,
98
- this.currentNode,
99
- { productIds: o },
100
- "Updated product IDs"
101
- ), this.store.patchCurrentBlockConfig({ productIds: o });
96
+ this.store.recommendationConfigs.productIds.join(",") !== t && this.store.patchCurrentBlockConfig({ productIds: o });
102
97
  }
103
98
  _listenToFormUpdates() {
104
99
  this.api.onValueChanged(i.ALGORITHM, (t) => {
@@ -109,6 +104,6 @@ class R extends g {
109
104
  }
110
105
  }
111
106
  export {
112
- p as ALGORITHM_CONTROL_ID,
113
- R as AlgorithmControl
107
+ C as ALGORITHM_CONTROL_ID,
108
+ S as AlgorithmControl
114
109
  };