@useinsider/guido 3.22.0-beta.e1b5da2 → 3.22.0-beta.e9b6f94
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 +35 -4
- package/dist/components/Guido.vue.js +1 -1
- package/dist/components/Guido.vue2.js +118 -108
- package/dist/composables/useEditorOpenMetrics.js +167 -0
- package/dist/composables/useStripo.js +93 -82
- package/dist/config/compiler/utils/recommendationCompilerUtils.js +22 -22
- package/dist/config/migrator/recommendation/compositionMapper.js +49 -56
- package/dist/config/migrator/recommendation/extractors.js +40 -100
- package/dist/config/migrator/recommendation/htmlBuilder.js +207 -285
- package/dist/config/migrator/recommendation/settingsMapper.js +36 -37
- package/dist/config/migrator/recommendation/themeMapper.js +41 -53
- package/dist/config/migrator/recommendationMigrator.js +61 -68
- package/dist/config/migrator/unsubscribeMigrator.js +60 -87
- package/dist/extensions/Blocks/Recommendation/block.js +24 -33
- package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +19 -20
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +163 -148
- package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +22 -23
- package/dist/extensions/Blocks/Recommendation/templates/list/template.js +18 -19
- package/dist/extensions/Blocks/Recommendation/templates/utils.js +91 -82
- package/dist/extensions/Blocks/Recommendation/utils/legacyStrategyMap.js +2 -3
- package/dist/guido.css +1 -1
- package/dist/library.js +12 -10
- package/dist/package.json.js +6 -4
- package/dist/public/prefetchRuntime.js +4 -0
- package/dist/src/composables/useEditorOpenMetrics.d.ts +27 -0
- package/dist/src/composables/useStripo.d.ts +2 -1
- package/dist/src/config/migrator/recommendation/compositionMapper.d.ts +1 -3
- package/dist/src/config/migrator/recommendation/extractors.d.ts +6 -35
- package/dist/src/config/migrator/recommendation/htmlBuilder.d.ts +1 -3
- package/dist/src/config/migrator/recommendation/themeMapper.d.ts +1 -3
- package/dist/src/config/migrator/recommendation/types.d.ts +1 -11
- package/dist/src/extensions/Blocks/Recommendation/block.d.ts +0 -1
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +8 -2
- package/dist/src/extensions/Blocks/Recommendation/templates/utils.d.ts +13 -1
- package/dist/src/extensions/Blocks/Recommendation/utils/legacyStrategyMap.d.ts +19 -2
- package/dist/src/library.d.ts +1 -0
- package/dist/src/public/prefetchRuntime.d.ts +1 -0
- package/dist/src/utils/runtimePrefetch.d.ts +4 -0
- package/dist/src/utils/stripoRuntime.d.ts +3 -0
- package/dist/static/stripo-runtime-manifest.json.js +9 -0
- package/dist/utils/runtimePrefetch.js +26 -0
- package/dist/utils/stripoRuntime.js +13 -0
- package/package.json +6 -1
- package/dist/extensions/Blocks/Recommendation/utils/inlinePriceOrder.js +0 -12
- package/dist/src/extensions/Blocks/Recommendation/utils/inlinePriceOrder.d.ts +0 -9
|
@@ -2,24 +2,23 @@ var b = Object.defineProperty;
|
|
|
2
2
|
var A = (m, c, e) => c in m ? b(m, c, { enumerable: !0, configurable: !0, writable: !0, value: e }) : m[c] = e;
|
|
3
3
|
var u = (m, c, e) => A(m, typeof c != "symbol" ? c + "" : c, e);
|
|
4
4
|
import { useConfig as g } from "../../../composables/useConfig.js";
|
|
5
|
-
import { BlockId as
|
|
6
|
-
import { getMigrationBannerHtml as
|
|
5
|
+
import { BlockId as D } from "../../../enums/block.js";
|
|
6
|
+
import { getMigrationBannerHtml as E } from "../../../utils/migrationBannerHtml.js";
|
|
7
7
|
import { Block as S, BlockCompositionType as v, ModificationDescription as _ } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
8
|
-
import { CURRENT_CONFIG_VERSION as
|
|
8
|
+
import { CURRENT_CONFIG_VERSION as N, PRE_RRS_CONFIG_VERSION as M } from "./constants/defaultConfig.js";
|
|
9
9
|
import { RECOMMENDATION_ID_ATTR as f } from "./constants/selectors.js";
|
|
10
|
-
import { ensureMobileFitRule as
|
|
11
|
-
import { regenerateMobileProductRows as
|
|
12
|
-
import { ensureMobileCssRulesExist as I, setMobileLayoutOptOut as R, hasMobileLayoutOptOut as
|
|
13
|
-
import { CSS_CLASS_TEXT_TRIM as H, ensureTextTrimCssRulesExist as $ } from "./controls/shared/textTrimCssRules.js";
|
|
10
|
+
import { ensureMobileFitRule as w, syncHeightBound as O } from "./controls/image/index.js";
|
|
11
|
+
import { regenerateMobileProductRows as H } from "./controls/main/utils.js";
|
|
12
|
+
import { ensureMobileCssRulesExist as I, setMobileLayoutOptOut as R, hasMobileLayoutOptOut as T } from "./controls/mobileLayout/cssRules.js";
|
|
14
13
|
import { RecommendationConfigService as a } from "./services/configService.js";
|
|
15
14
|
import { useRecommendationExtensionStore as p } from "./store/recommendation.js";
|
|
16
|
-
import { getDefaultTemplate as
|
|
15
|
+
import { getDefaultTemplate as x } from "./templates/grid/template.js";
|
|
17
16
|
import { useRecommendationBlockWarning as F } from "./useRecommendationBlockWarning.js";
|
|
18
|
-
import { registerNodeConfigWriter as y, readBlockNodeConfigs as
|
|
19
|
-
import { refreshArrivedStrategyBlocks as
|
|
20
|
-
const k =
|
|
17
|
+
import { registerNodeConfigWriter as y, readBlockNodeConfigs as $ } from "./utils/nodeConfigWriter.js";
|
|
18
|
+
import { refreshArrivedStrategyBlocks as q, resolveSourceConfig as L, refreshDuplicatedStrategyBlocks as P } from "./utils/strategyCommit.js";
|
|
19
|
+
const k = D.Recommendation, h = "recommendation-block-v2", C = "hide-price";
|
|
21
20
|
let B = !1;
|
|
22
|
-
class
|
|
21
|
+
class se extends S {
|
|
23
22
|
constructor() {
|
|
24
23
|
super();
|
|
25
24
|
/**
|
|
@@ -53,7 +52,7 @@ class ae extends S {
|
|
|
53
52
|
);
|
|
54
53
|
}
|
|
55
54
|
getSettingsPanelTitleHtml() {
|
|
56
|
-
return
|
|
55
|
+
return E(
|
|
57
56
|
k,
|
|
58
57
|
this.api.translate("Recommendation Block"),
|
|
59
58
|
this.api.translate("This block is switched from the Old Version to the New Version. We recommend you check the Recommendation block and test your message to ensure it works properly.")
|
|
@@ -77,7 +76,7 @@ class ae extends S {
|
|
|
77
76
|
*/
|
|
78
77
|
getTemplate() {
|
|
79
78
|
const e = this._generateNextId();
|
|
80
|
-
return this._pendingBlockId = e,
|
|
79
|
+
return this._pendingBlockId = e, x(e);
|
|
81
80
|
}
|
|
82
81
|
/**
|
|
83
82
|
* Called when a new block is dropped into the template
|
|
@@ -111,7 +110,7 @@ class ae extends S {
|
|
|
111
110
|
e,
|
|
112
111
|
{
|
|
113
112
|
recommendationId: i,
|
|
114
|
-
configVersion: r ?
|
|
113
|
+
configVersion: r ? N : M,
|
|
115
114
|
...s ? { partnerName: g().partnerName.value } : {},
|
|
116
115
|
// An RRS block picks a strategy, not an algorithm, and its algorithm control is
|
|
117
116
|
// hidden. Keeping the `mostPopular` default would bake a most-popular feed URL
|
|
@@ -122,7 +121,7 @@ class ae extends S {
|
|
|
122
121
|
if (l.setCurrentBlock(i), this._stampHidePrice(e, n.priceHideIfSameAsDiscounted), o) {
|
|
123
122
|
I(this.api);
|
|
124
123
|
const d = this._getBlockElement(e);
|
|
125
|
-
d && (R(this.api, d, !0),
|
|
124
|
+
d && (R(this.api, d, !0), H({
|
|
126
125
|
currentNode: e,
|
|
127
126
|
documentModifier: this.api.getDocumentModifier()
|
|
128
127
|
}));
|
|
@@ -156,13 +155,13 @@ class ae extends S {
|
|
|
156
155
|
"Assign recommendation ID to legacy block"
|
|
157
156
|
);
|
|
158
157
|
}
|
|
159
|
-
this._healLingeringDuplicate(e), a.needsMigration(e) && this._migrateFromLegacy(e), this._healHidePriceAttr(e), this._ensureMobileFitRule(e), this._syncHeightBound(e)
|
|
158
|
+
this._healLingeringDuplicate(e), a.needsMigration(e) && this._migrateFromLegacy(e), this._healHidePriceAttr(e), this._ensureMobileFitRule(e), this._syncHeightBound(e);
|
|
160
159
|
try {
|
|
161
160
|
B || (I(this.api), B = !0);
|
|
162
161
|
const t = a.getConfig(e), i = this._getBlockElement(e);
|
|
163
162
|
if (i) {
|
|
164
163
|
const r = !t.mobileLayoutEnabled;
|
|
165
|
-
|
|
164
|
+
T(i) !== r && R(this.api, i, r);
|
|
166
165
|
}
|
|
167
166
|
} catch {
|
|
168
167
|
}
|
|
@@ -180,15 +179,7 @@ class ae extends S {
|
|
|
180
179
|
}
|
|
181
180
|
_ensureMobileFitRule(e) {
|
|
182
181
|
try {
|
|
183
|
-
|
|
184
|
-
} catch {
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
// A migrated block arrives with trimmed cells but without the stylesheet rules the toggle would have added.
|
|
188
|
-
_ensureTextTrimCss(e) {
|
|
189
|
-
var t;
|
|
190
|
-
try {
|
|
191
|
-
(t = this._getBlockElement(e)) != null && t.querySelector(`.${H}`) && $(this.api);
|
|
182
|
+
w(this.api, e);
|
|
192
183
|
} catch {
|
|
193
184
|
}
|
|
194
185
|
}
|
|
@@ -196,7 +187,7 @@ class ae extends S {
|
|
|
196
187
|
const t = this._getBlockElement(e);
|
|
197
188
|
if (t)
|
|
198
189
|
try {
|
|
199
|
-
|
|
190
|
+
O(this.api, t);
|
|
200
191
|
} catch {
|
|
201
192
|
}
|
|
202
193
|
}
|
|
@@ -279,7 +270,7 @@ class ae extends S {
|
|
|
279
270
|
const d = { strategyId: l.strategyId };
|
|
280
271
|
return t.add(n), this._refreshClaims.set(n, d), [{ id: n, config: l, claim: d }];
|
|
281
272
|
});
|
|
282
|
-
i.length &&
|
|
273
|
+
i.length && q(i.map(({ id: r, config: s }) => ({ id: r, config: s }))).catch((r) => console.error("[recommendation] refreshing an arrived strategy failed", r)).finally(() => i.forEach(({ id: r, claim: s }) => this._releaseRefreshClaim(r, s)));
|
|
283
274
|
}
|
|
284
275
|
/**
|
|
285
276
|
* A new document reports each block to onCreated and onDocumentInit, not always in one batch, so a
|
|
@@ -291,7 +282,7 @@ class ae extends S {
|
|
|
291
282
|
return !0;
|
|
292
283
|
if (i.strategyId === t)
|
|
293
284
|
return !1;
|
|
294
|
-
const r =
|
|
285
|
+
const r = $(e);
|
|
295
286
|
return r.length > 0 && r.every((s) => s.strategyId === t);
|
|
296
287
|
}
|
|
297
288
|
_releaseRefreshClaim(e, t) {
|
|
@@ -353,10 +344,10 @@ class ae extends S {
|
|
|
353
344
|
if (r.cloneBlockState(t, i), r.setCurrentBlock(i), g().isFeatureEnabled("reusableRecommendationStrategy")) {
|
|
354
345
|
this._resetSourceIds.add(t), y(this.api);
|
|
355
346
|
const s = a.getConfig(e), n = [
|
|
356
|
-
{ id: t, claim: { strategyId:
|
|
347
|
+
{ id: t, claim: { strategyId: L(t, s).strategyId } },
|
|
357
348
|
{ id: i, claim: { strategyId: s.strategyId } }
|
|
358
349
|
].filter(({ id: o }) => !this._refreshClaims.has(o));
|
|
359
|
-
n.forEach(({ id: o, claim: l }) => this._refreshClaims.set(o, l)),
|
|
350
|
+
n.forEach(({ id: o, claim: l }) => this._refreshClaims.set(o, l)), P(t, i, s).catch((o) => console.error("[recommendation] refreshing a duplicated strategy failed", o)).finally(() => n.forEach(({ id: o, claim: l }) => this._releaseRefreshClaim(o, l)));
|
|
360
351
|
}
|
|
361
352
|
this._warnIfMultipleBlocks();
|
|
362
353
|
}
|
|
@@ -460,5 +451,5 @@ class ae extends S {
|
|
|
460
451
|
}
|
|
461
452
|
export {
|
|
462
453
|
k as BLOCK_ID,
|
|
463
|
-
|
|
454
|
+
se as RecommendationBlock
|
|
464
455
|
};
|
|
@@ -11,11 +11,10 @@ import { useRecommendationExtensionStore as ft } from "../../store/recommendatio
|
|
|
11
11
|
import { ATTRIBUTE_CELL_CLASS as bt, gridElementRenderer as yt, DEFAULT_CELL_PADDING as Tt, buildFillerCell as Ct } from "../../templates/grid/elementRenderer.js";
|
|
12
12
|
import { listElementRenderer as St } from "../../templates/list/elementRenderer.js";
|
|
13
13
|
import { buildTitleRows as At, DEFAULT_TITLE_PARAGRAPH as It, DEFAULT_TITLE_TEXT as $t } from "../../templates/titleRows.js";
|
|
14
|
-
import {
|
|
15
|
-
import { normalizeCompositionKeys as
|
|
16
|
-
import { getTableDisplayValue as
|
|
17
|
-
import { isPartnerManagedBlock as
|
|
18
|
-
import { resolveInlinePriceOrder as Mt } from "../../utils/inlinePriceOrder.js";
|
|
14
|
+
import { resolveInlinePriceOrder as vt, toDisplayName as Nt, toDisplayableAttributeValue as Et, buildElementRenderer as J } from "../../templates/utils.js";
|
|
15
|
+
import { normalizeCompositionKeys as Rt, normalizeCustomAttrValues as Lt, compositionKeyToProductAttr as k, resolveRowVisibilityKeys as Ot, filterToProductAttrValue as C, findAttributeRow as Dt, rewriteLegacyRowKeyHtml as Q, bareAttributeName as H, isDefaultProductAttr as Ht, productAttrToCompositionKey as M } from "../../utils/compositionKeys.js";
|
|
16
|
+
import { getTableDisplayValue as Pt } from "../../utils/tagName.js";
|
|
17
|
+
import { isPartnerManagedBlock as wt, regenerateProductRowsWithStyles as Bt, getMainContainerTbody as kt, getCurrentLayout as Mt } from "../main/utils.js";
|
|
19
18
|
const Ut = "ui-elements-recommendation-card-composition", U = ".product-card-wrapper > tbody", Z = ".product-info-cell > table > tbody", tt = {
|
|
20
19
|
ADD_ATTRIBUTE: "addAttribute"
|
|
21
20
|
}, b = 5, P = "reorderIcon_", qt = '<svg width="14" height="10" viewBox="0 0 14 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><circle cx="2" cy="2.5" r="1.2"/><circle cx="7" cy="2.5" r="1.2"/><circle cx="12" cy="2.5" r="1.2"/><circle cx="2" cy="7.5" r="1.2"/><circle cx="7" cy="7.5" r="1.2"/><circle cx="12" cy="7.5" r="1.2"/></svg>', m = [
|
|
@@ -27,7 +26,7 @@ const Ut = "ui-elements-recommendation-card-composition", U = ".product-card-wra
|
|
|
27
26
|
{ key: pt, label: "Omnibus Discount" },
|
|
28
27
|
{ key: F, label: "Product Button" }
|
|
29
28
|
], L = { key: $, label: "Title" }, Ft = new Set(m.map((_) => _.key)), A = "customAttr_", w = "deleteAttr_";
|
|
30
|
-
class
|
|
29
|
+
class se extends ut {
|
|
31
30
|
constructor() {
|
|
32
31
|
super(...arguments);
|
|
33
32
|
v(this, "store", ft());
|
|
@@ -156,7 +155,7 @@ class oe extends ut {
|
|
|
156
155
|
const t = (r = this.getContainer()) == null ? void 0 : r.querySelector("[data-card-composition-control]");
|
|
157
156
|
if (!t)
|
|
158
157
|
return;
|
|
159
|
-
const e =
|
|
158
|
+
const e = wt(this.currentNode);
|
|
160
159
|
t.style.pointerEvents = e ? "none" : "", t.style.opacity = e ? "0.5" : "";
|
|
161
160
|
}
|
|
162
161
|
onTemplateNodeUpdated(t) {
|
|
@@ -199,7 +198,7 @@ class oe extends ut {
|
|
|
199
198
|
}
|
|
200
199
|
/** Upgrades legacy bare-name custom keys to the canonical form. (SD-147101) */
|
|
201
200
|
_normalizeComposition(t) {
|
|
202
|
-
return
|
|
201
|
+
return Rt(t, this.currentNode, this.store.filterList);
|
|
203
202
|
}
|
|
204
203
|
_readCustomAttributesFromNode() {
|
|
205
204
|
if (!this.currentNode || !("getAttribute" in this.currentNode))
|
|
@@ -207,7 +206,7 @@ class oe extends ut {
|
|
|
207
206
|
const t = this.currentNode.getAttribute(W);
|
|
208
207
|
if (t)
|
|
209
208
|
try {
|
|
210
|
-
return
|
|
209
|
+
return Lt(
|
|
211
210
|
JSON.parse(t).map((e) => String(e)),
|
|
212
211
|
this.currentNode,
|
|
213
212
|
this.store.filterList
|
|
@@ -242,7 +241,7 @@ class oe extends ut {
|
|
|
242
241
|
if (!("getAttribute" in r))
|
|
243
242
|
return;
|
|
244
243
|
const i = r.getAttribute(D);
|
|
245
|
-
i !== null &&
|
|
244
|
+
i !== null && Ot(r).forEach((s) => {
|
|
246
245
|
e[s] = this._parseVisibilityValue(i);
|
|
247
246
|
});
|
|
248
247
|
}), e;
|
|
@@ -277,7 +276,7 @@ class oe extends ut {
|
|
|
277
276
|
if (!(i.dataset.inlinePrices !== String(s)) && this._tryReorderInPlace(i, t))
|
|
278
277
|
return !1;
|
|
279
278
|
i.dataset.inlinePrices = String(s);
|
|
280
|
-
const n = new Set(e), l =
|
|
279
|
+
const n = new Set(e), l = vt(t);
|
|
281
280
|
let a = 0, d = 0;
|
|
282
281
|
const c = t.map((u) => {
|
|
283
282
|
if (s && (u === p || u === I))
|
|
@@ -654,7 +653,7 @@ class oe extends ut {
|
|
|
654
653
|
try {
|
|
655
654
|
this._updateBothAttributes(t, e);
|
|
656
655
|
const r = this._isInlinePrices();
|
|
657
|
-
this._getCurrentLayout() === "grid" && !r ? this._reorderProductAttributes(t) : this.currentNode &&
|
|
656
|
+
this._getCurrentLayout() === "grid" && !r ? this._reorderProductAttributes(t) : this.currentNode && Bt({
|
|
658
657
|
currentNode: this.currentNode,
|
|
659
658
|
documentModifier: this.api.getDocumentModifier()
|
|
660
659
|
});
|
|
@@ -672,7 +671,7 @@ class oe extends ut {
|
|
|
672
671
|
* DOM converge on the next composition change without writing on open.
|
|
673
672
|
*/
|
|
674
673
|
_getExistingRowHtml(t, e) {
|
|
675
|
-
const r =
|
|
674
|
+
const r = Dt(t, e);
|
|
676
675
|
if (r && "getOuterHTML" in r)
|
|
677
676
|
return Q(r.getOuterHTML(), e);
|
|
678
677
|
const i = t.querySelector(
|
|
@@ -816,7 +815,7 @@ class oe extends ut {
|
|
|
816
815
|
return;
|
|
817
816
|
const o = e ? "1" : "0", n = e ? this.api.translate("visible") : this.api.translate("hidden"), l = `${this.api.translate("Set visibility")}: ${t} → ${n}`, a = this.api.getDocumentModifier();
|
|
818
817
|
s.forEach((c) => {
|
|
819
|
-
const u =
|
|
818
|
+
const u = Pt(c), h = e ? u : "none";
|
|
820
819
|
a.modifyHtml(c).setStyle("display", h).setAttribute(D, o);
|
|
821
820
|
});
|
|
822
821
|
const d = {
|
|
@@ -878,7 +877,7 @@ class oe extends ut {
|
|
|
878
877
|
return "children" in t && t.children().some((e) => "hasClass" in e && e.hasClass(_t));
|
|
879
878
|
}
|
|
880
879
|
_findTitleContainerBody() {
|
|
881
|
-
return (this.currentNode ?
|
|
880
|
+
return (this.currentNode ? kt(this.currentNode) : null) ?? void 0;
|
|
882
881
|
}
|
|
883
882
|
_readInnerHtml(t) {
|
|
884
883
|
return "getInnerHTML" in t && typeof t.getInnerHTML == "function" ? t.getInnerHTML().trim() : null;
|
|
@@ -905,7 +904,7 @@ class oe extends ut {
|
|
|
905
904
|
return -1;
|
|
906
905
|
}
|
|
907
906
|
_getCurrentLayout() {
|
|
908
|
-
return this.store.recommendationConfigs.orientation ||
|
|
907
|
+
return this.store.recommendationConfigs.orientation || Mt(this.currentNode);
|
|
909
908
|
}
|
|
910
909
|
/**
|
|
911
910
|
* Extracts background color properties from existing card elements.
|
|
@@ -1001,7 +1000,7 @@ class oe extends ut {
|
|
|
1001
1000
|
*/
|
|
1002
1001
|
_getDisplayNameForAttribute(t) {
|
|
1003
1002
|
const e = Object.values(this.store.filterList).find((r) => C(r) === t);
|
|
1004
|
-
return e ? e.displayName :
|
|
1003
|
+
return e ? e.displayName : Nt(H(t));
|
|
1005
1004
|
}
|
|
1006
1005
|
/**
|
|
1007
1006
|
* Resolves the display content for a custom attribute cell.
|
|
@@ -1009,8 +1008,8 @@ class oe extends ut {
|
|
|
1009
1008
|
*/
|
|
1010
1009
|
_resolveAttributeContent(t, e, r) {
|
|
1011
1010
|
var l;
|
|
1012
|
-
const s = this.store.recommendationProducts[r], o = H(t), n =
|
|
1013
|
-
return
|
|
1011
|
+
const s = this.store.recommendationProducts[r], o = H(t), n = Ht(t) ? s == null ? void 0 : s[o] : (l = s == null ? void 0 : s.product_attributes) == null ? void 0 : l[o];
|
|
1012
|
+
return Et(n) ?? e;
|
|
1014
1013
|
}
|
|
1015
1014
|
_getGridCellHtml(t, e, r, i = "", s = "", o = "") {
|
|
1016
1015
|
const n = M(t), l = H(t), a = J(yt, [n], this.store.filterList), d = {
|
|
@@ -1033,5 +1032,5 @@ class oe extends ut {
|
|
|
1033
1032
|
}
|
|
1034
1033
|
export {
|
|
1035
1034
|
Ut as COMPOSITION_CONTROL_BLOCK_ID,
|
|
1036
|
-
|
|
1035
|
+
se as RecommendationCardCompositionControl
|
|
1037
1036
|
};
|