@useinsider/guido 3.20.1 → 3.20.2-beta.87fb8ae

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.
@@ -0,0 +1,19 @@
1
+ import { useRecommendationExtensionStore as u } from "../store/recommendation.js";
2
+ import { commitBlockChangeOutsidePanel as d } from "./nodeConfigWriter.js";
3
+ async function l(e, { pickUpdates: n, description: i, fetch: s = !0 }) {
4
+ const t = u(), r = t.blockStates[e];
5
+ if (!r)
6
+ return !1;
7
+ const { configVersion: c, adoptedSizeVersion: a } = r, f = n(r.recommendationConfigs);
8
+ if (s)
9
+ try {
10
+ await t.fetchRecommendationProductsForBlock(e);
11
+ } catch (m) {
12
+ console.error("[recommendation] product refetch outside the panel failed", m);
13
+ }
14
+ const o = t.blockStates[e];
15
+ return o ? o.configVersion !== c || o.adoptedSizeVersion !== a ? l(e, { pickUpdates: n, description: i }) : d(e, f, o.recommendationProducts, i) : !1;
16
+ }
17
+ export {
18
+ l as refreshBlockOutsidePanel
19
+ };
@@ -1,53 +1,68 @@
1
- import { ModificationDescription as s } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
- import { RECOMMENDATION_ID_ATTR as a } from "../constants/selectors.js";
3
- import { isPartnerManagedBlock as C, updateProductContentInPlace as p, regenerateProductRowsWithStyles as y } from "../controls/main/utils.js";
4
- import { RecommendationConfigService as m } from "../services/configService.js";
5
- import { useRecommendationExtensionStore as N } from "../store/recommendation.js";
6
- let n = null;
7
- function B(e) {
8
- n = e;
9
- }
10
- function S(e, t) {
11
- const o = N(), i = o.currentRecommendationId;
12
- if (i === e || !o.blockStates[e]) {
13
- t();
1
+ import { ModificationDescription as g } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
2
+ import { RECOMMENDATION_ID_ATTR as l } from "../constants/selectors.js";
3
+ import { isPartnerManagedBlock as m, updateProductContentInPlace as d, regenerateProductRowsWithStyles as C } from "../controls/main/utils.js";
4
+ import { RecommendationConfigService as c } from "../services/configService.js";
5
+ import { useRecommendationExtensionStore as y } from "../store/recommendation.js";
6
+ let r = null;
7
+ function M(n) {
8
+ r = n;
9
+ }
10
+ function a(n) {
11
+ const e = r == null ? void 0 : r.getDocumentRootHtmlNode();
12
+ return !e || !("querySelector" in e) ? null : e.querySelector(`[${l}="${n}"]`) ?? null;
13
+ }
14
+ function N(n, e) {
15
+ const o = c.getConfig(n);
16
+ return Object.keys(e).some((t) => JSON.stringify(o[t]) !== JSON.stringify(e[t]));
17
+ }
18
+ function S(n, e) {
19
+ const o = c.getConfig(n);
20
+ return ["filters", "strategy", "strategyId", "size"].some((t) => t in e && JSON.stringify(o[t]) !== JSON.stringify(e[t]));
21
+ }
22
+ function P(n, e, o) {
23
+ const t = a(n);
24
+ return !r || !t ? !1 : (S(t, e) && c.updateConfig(r, t, e, o), !0);
25
+ }
26
+ function p(n, e) {
27
+ const o = y(), t = o.currentRecommendationId;
28
+ if (t === n || !o.blockStates[n]) {
29
+ e();
14
30
  return;
15
31
  }
16
- o.setCurrentBlock(e);
32
+ o.setCurrentBlock(n);
17
33
  try {
18
- t();
34
+ e();
19
35
  } finally {
20
- o.$patch({ currentRecommendationId: i });
36
+ o.$patch({ currentRecommendationId: t });
21
37
  }
22
38
  }
23
- function P(e) {
24
- const t = n == null ? void 0 : n.getDocumentRootHtmlNode();
25
- return !t || !("querySelectorAll" in t) ? [] : t.querySelectorAll(`[${a}="${e}"]`).map((o) => m.getConfig(o));
39
+ function I(n) {
40
+ const e = r == null ? void 0 : r.getDocumentRootHtmlNode();
41
+ return !e || !("querySelectorAll" in e) ? [] : e.querySelectorAll(`[${l}="${n}"]`).map((o) => c.getConfig(o));
26
42
  }
27
- function $(e, t, o, i) {
28
- const f = n == null ? void 0 : n.getDocumentRootHtmlNode();
29
- if (!n || !f || !("querySelector" in f))
30
- return !1;
31
- const r = f.querySelector(`[${a}="${e}"]`);
32
- if (!r)
43
+ function $(n, e, o, t) {
44
+ const i = a(n);
45
+ if (!r || !i)
33
46
  return !1;
34
- const c = n.getDocumentModifier(), d = m.getConfig(r), g = Object.keys(t).some((l) => JSON.stringify(d[l]) !== JSON.stringify(t[l]));
35
- if (m.stageConfig(c, r, t), C(r))
36
- return c.apply(new s(i)), !0;
47
+ const f = r.getDocumentModifier(), s = N(i, e);
48
+ if (c.stageConfig(f, i, e), m(i))
49
+ return s && f.apply(new g(t)), !0;
37
50
  let u = !1;
38
- return S(e, () => {
39
- p({
40
- currentNode: r,
41
- documentModifier: c,
51
+ return p(n, () => {
52
+ d({
53
+ currentNode: i,
54
+ documentModifier: f,
42
55
  products: o,
43
56
  onApplied: () => {
44
57
  u = !0;
45
58
  }
46
- }) || (u = y({ currentNode: r, documentModifier: c, products: o }));
47
- }), !u && g && c.apply(new s(i)), !0;
59
+ }) || (u = C({ currentNode: i, documentModifier: f, products: o }));
60
+ }), !u && s && f.apply(new g(t)), !0;
48
61
  }
49
62
  export {
50
63
  $ as commitBlockChangeOutsidePanel,
51
- P as readBlockNodeConfigs,
52
- B as registerNodeConfigWriter
64
+ S as hasEditedConfigChange,
65
+ I as readBlockNodeConfigs,
66
+ M as registerNodeConfigWriter,
67
+ P as writeBlockConfigOutsidePanel
53
68
  };
@@ -1,47 +1,43 @@
1
1
  import { useRecommendationExtensionStore as g } from "../store/recommendation.js";
2
- import { toBlockUrlConfig as m } from "./blockUrlConfig.js";
3
- import { commitBlockChangeOutsidePanel as d, readBlockNodeConfigs as y } from "./nodeConfigWriter.js";
4
- function l(t, o) {
5
- const r = JSON.stringify(m(o));
6
- return y(t).find((e) => JSON.stringify(m(e)) !== r) ?? o;
2
+ import { refreshBlockOutsidePanel as y } from "./blockRefresh.js";
3
+ import { toBlockUrlConfig as a } from "./blockUrlConfig.js";
4
+ import { commitBlockChangeOutsidePanel as l, readBlockNodeConfigs as S } from "./nodeConfigWriter.js";
5
+ function d(e, t) {
6
+ const r = JSON.stringify(a(t));
7
+ return S(e).find((o) => JSON.stringify(a(o)) !== r) ?? t;
7
8
  }
8
- async function C(t, o, r) {
9
- const e = g(), c = [t, o];
10
- (/* @__PURE__ */ new Map([[t, l(t, r)], [o, r]])).forEach((n, s) => {
11
- var a;
12
- (!!n.strategyId || s === o) && ((a = e.blockStates[s]) == null ? void 0 : a.recommendationConfigs.strategyId) !== n.strategyId && e.seedBlockUrlConfig(s, m(n));
13
- }), e.resetArrivedBlock(o), await Promise.all(c.map(async (n) => {
14
- if (!await e.refreshStrategyBlock(n))
9
+ async function p(e, t, r) {
10
+ const o = g(), s = [e, t];
11
+ (/* @__PURE__ */ new Map([[e, d(e, r)], [t, r]])).forEach((n, i) => {
12
+ var m;
13
+ (!!n.strategyId || i === t) && ((m = o.blockStates[i]) == null ? void 0 : m.recommendationConfigs.strategyId) !== n.strategyId && o.seedBlockUrlConfig(i, a(n));
14
+ }), o.resetArrivedBlock(t), await Promise.all(s.map(async (n) => {
15
+ if (!await o.refreshStrategyBlock(n))
15
16
  return;
16
- const { recommendationConfigs: s, recommendationProducts: i } = e.blockStates[n];
17
- d(
17
+ const { recommendationConfigs: i, recommendationProducts: f } = o.blockStates[n];
18
+ l(
18
19
  n,
19
- { size: s.size },
20
- i,
20
+ { size: i.size },
21
+ f,
21
22
  "Refresh duplicated recommendation strategy"
22
23
  );
23
24
  }));
24
25
  }
25
- async function B(t, o) {
26
- const r = g(), e = r.blockStates[t];
27
- if (!e)
26
+ async function k(e, t) {
27
+ if (!g().blockStates[e])
28
28
  return !1;
29
- const { strategyId: c, strategy: f, size: n, nodeConfigVersion: s } = e.recommendationConfigs;
30
- if (r.currentRecommendationId === t)
31
- try {
32
- await r.fetchRecommendationProducts();
33
- } catch (a) {
34
- console.error("[recommendation] product refetch after a strategy change failed", a);
35
- }
36
- const i = d(
37
- t,
38
- { strategyId: c, strategy: f, size: n, configVersion: s },
39
- e.recommendationProducts,
40
- o
41
- );
42
- return i || console.error("[recommendation] strategy change did not reach a node", { blockId: t }), i;
29
+ const r = await y(e, {
30
+ pickUpdates: ({ strategyId: o, strategy: s, size: c, nodeConfigVersion: n }) => ({
31
+ strategyId: o,
32
+ strategy: s,
33
+ size: c,
34
+ configVersion: n
35
+ }),
36
+ description: t
37
+ });
38
+ return r || console.error("[recommendation] strategy change did not reach a node", { blockId: e }), r;
43
39
  }
44
40
  export {
45
- B as commitStrategyChange,
46
- C as refreshDuplicatedStrategyBlocks
41
+ k as commitStrategyChange,
42
+ p as refreshDuplicatedStrategyBlocks
47
43
  };
@@ -22,6 +22,11 @@ export declare class RecommendationBlockControl extends CommonControl {
22
22
  private storeUnsubscription;
23
23
  private pendingNodeConfigWrite;
24
24
  private pendingConfigFlushTimer;
25
+ private trackedBlockId;
26
+ private fetchedConfigVersion;
27
+ private hasUnrenderedProducts;
28
+ private panelGeneration;
29
+ private isPanelAlive;
25
30
  private algorithmControl;
26
31
  private localeControl;
27
32
  private currencyControl;
@@ -73,6 +78,7 @@ export declare class RecommendationBlockControl extends CommonControl {
73
78
  /** Whether the deferred write would move the node's strategyId — see the caller (SD-149916). */
74
79
  private _isPendingStrategyIdChange;
75
80
  private _capturePendingNodeConfigWrite;
81
+ private _getNodeConfigUpdates;
76
82
  /**
77
83
  * Accumulates the pending write into `documentModifier` without applying, so the
78
84
  * caller's apply() commits config and re-render as ONE undo entry.
@@ -93,8 +99,8 @@ export declare class RecommendationBlockControl extends CommonControl {
93
99
  private _clearConfigFlush;
94
100
  /**
95
101
  * Writes the deferred change standalone when the batch it was staged into never
96
- * committed. Always targets the LIVE node — the captured one is an immutable
97
- * snapshot the intervening re-render staled, and saveConfig swallows that failure.
102
+ * committed. Always targets a LIVE node — a captured one is an immutable snapshot
103
+ * the intervening re-render staled, and saveConfig swallows that failure.
98
104
  */
99
105
  private _flushPendingNodeConfig;
100
106
  private _syncNodeConfigToStore;
@@ -108,6 +114,7 @@ export declare class RecommendationBlockControl extends CommonControl {
108
114
  * Marks the block as initialized to prevent redundant fetches on re-selection.
109
115
  */
110
116
  private _fetchBlockData;
117
+ private _isPanelOn;
111
118
  /**
112
119
  * Applies smart defaults for newly dropped blocks.
113
120
  *
@@ -127,6 +134,14 @@ export declare class RecommendationBlockControl extends CommonControl {
127
134
  * Debounced product fetch to prevent rapid API calls during config changes
128
135
  */
129
136
  private _debouncedFetchProducts;
137
+ /**
138
+ * Lands what the panel still owes its block before it stops watching it: the config now, the
139
+ * products through a block-scoped refresh. Never throws — it runs from Stripo's teardown.
140
+ */
141
+ private _finishBlockOutsidePanel;
142
+ private _trackedBlockSnapshot;
143
+ private _refreshOutsidePanel;
144
+ private _getBlockConfigVersion;
130
145
  /**
131
146
  * Debounced content update when products arrive from API.
132
147
  *
@@ -144,7 +159,7 @@ export declare class RecommendationBlockControl extends CommonControl {
144
159
  /**
145
160
  * Listen to store changes that require product refresh or regeneration.
146
161
  *
147
- * Uses configVersion counter (incremented only by patchCurrentBlockConfig)
162
+ * Uses the block's configVersion counter (bumped by patchCurrentBlockConfig and legacy conversion)
148
163
  * to distinguish user-initiated config changes from internal mutations
149
164
  * (e.g., fetchRecommendationCreateData setting preferred currency).
150
165
  *
@@ -54,6 +54,8 @@ interface PerBlockState {
54
54
  */
55
55
  syncedConfigFingerprint: string | null;
56
56
  legacyConversionLoading: boolean;
57
+ configVersion: number;
58
+ adoptedSizeVersion: number;
57
59
  }
58
60
  /**
59
61
  * Persisted-config subset used by `seedBlockUrlConfig` to reconstruct
@@ -618,7 +620,12 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
618
620
  */
619
621
  invalidBlockFields(): string[];
620
622
  fetchRecommendationProducts(): Promise<void>;
621
- _doFetchProducts(): Promise<void>;
623
+ /**
624
+ * Fetches one block's products whether or not it is selected: the panel teardown and the
625
+ * strategy drawer refresh the block they were handed after the user may have moved on.
626
+ */
627
+ fetchRecommendationProductsForBlock(blockId: number): Promise<void>;
628
+ _doFetchProducts(targetBlockId?: number): Promise<void>;
622
629
  /**
623
630
  * Block-scoped counterpart of `fetchRecommendationProducts`, which only serves the selected block:
624
631
  * the legacy conversion and the duplicate refresh must reach a block that may no longer be selected.
@@ -0,0 +1,17 @@
1
+ import type { PerBlockConfigs } from '../store/recommendation';
2
+ import type { PartialNodeConfig } from '../types/nodeConfig';
3
+ interface BlockRefreshOptions {
4
+ pickUpdates: (configs: PerBlockConfigs) => PartialNodeConfig;
5
+ description: string;
6
+ fetch?: boolean;
7
+ }
8
+ /**
9
+ * Fetches one block's products and commits them with its config straight to the document, for
10
+ * callers the settings panel can no longer serve (deselect, block switch, host-rendered strategy UI).
11
+ * @param options.pickUpdates - the config keys this caller owns on the node
12
+ * @param options.description - labels the undo entry
13
+ * @param options.fetch - false when the block's products already landed and only need rendering
14
+ * @returns whether the write reached a node
15
+ */
16
+ export declare function refreshBlockOutsidePanel(blockId: number, { pickUpdates, description, fetch }: BlockRefreshOptions): Promise<boolean>;
17
+ export {};
@@ -13,6 +13,13 @@ interface ConfigWriterApi {
13
13
  * itself is torn down.
14
14
  */
15
15
  export declare function registerNodeConfigWriter(api: ConfigWriterApi): void;
16
+ export declare function hasEditedConfigChange(node: ImmutableHtmlNode, updates: PartialNodeConfig): boolean;
17
+ /**
18
+ * Writes a config change to the block's node on its own, found by id — never through a
19
+ * panel-held node, which may already belong to the block the user switched to.
20
+ * @returns whether the block's node was found
21
+ */
22
+ export declare function writeBlockConfigOutsidePanel(blockId: number, updates: PartialNodeConfig, description: string): boolean;
16
23
  /** Reads the persisted config of every node carrying a block id (two while a duplicate still shares it). */
17
24
  export declare function readBlockNodeConfigs(blockId: number): RecommendationNodeConfig[];
18
25
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useinsider/guido",
3
- "version": "3.20.1",
3
+ "version": "3.20.2-beta.87fb8ae",
4
4
  "description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
5
5
  "main": "./dist/guido.umd.cjs",
6
6
  "module": "./dist/library.js",