@useinsider/guido 3.12.0-beta.841bb6a → 3.12.0-beta.86e34da
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/dist/@types/config/schemas.js +9 -4
- package/dist/components/Guido.vue.js +6 -6
- package/dist/components/Guido.vue2.js +50 -49
- package/dist/components/organisms/email-preview/desktop-preview/DesktopPreview.vue.js +1 -1
- package/dist/components/organisms/email-preview/desktop-preview/DesktopPreview.vue2.js +8 -8
- package/dist/components/organisms/email-preview/mobile-preview/ContentView.vue.js +5 -5
- package/dist/components/organisms/email-preview/mobile-preview/ContentView.vue2.js +10 -10
- package/dist/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue.js +38 -0
- package/dist/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue2.js +271 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue.js +18 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue2.js +42 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue.js +20 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue2.js +18 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue.js +20 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue2.js +60 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue.js +19 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue2.js +19 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue.js +22 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue2.js +29 -0
- package/dist/composables/usePreviewInteractionGuard.js +36 -11
- package/dist/composables/useRecommendation.js +56 -40
- package/dist/composables/useRecommendationPreview.js +61 -60
- package/dist/composables/useStrategyFilters.js +16 -0
- package/dist/config/migrator/recommendationMigrator.js +7 -4
- package/dist/enums/date.js +4 -3
- package/dist/enums/extensions/filteringV2.js +1024 -0
- package/dist/enums/extensions/recommendationBlock.js +45 -24
- package/dist/enums/extensions/strategyDetail.js +148 -0
- package/dist/extensions/Blocks/Recommendation/constants/controlIds.js +1 -1
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +12 -11
- package/dist/extensions/Blocks/Recommendation/controls/blockBackground/index.js +10 -0
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +141 -123
- package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +285 -0
- package/dist/extensions/Blocks/Recommendation/extension.js +23 -21
- package/dist/extensions/Blocks/Recommendation/iconsRegistry.js +16 -2
- package/dist/extensions/Blocks/Recommendation/recommendation.css.js +257 -0
- package/dist/extensions/Blocks/Recommendation/settingsPanel.js +41 -40
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +460 -113
- package/dist/extensions/Blocks/Recommendation/utils/strategyHumanizer.js +97 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategyNavigation.js +8 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategySummary.js +95 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategyUrl.js +43 -0
- package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +24 -10
- package/dist/extensions/Blocks/Unsubscribe/utils/constants.js +3 -2
- package/dist/extensions/Blocks/common-control.js +2 -1
- package/dist/extensions/Blocks/controlFactories.js +125 -75
- package/dist/guido.css +1 -1
- package/dist/services/recommendationApi.js +120 -32
- package/dist/services/stripoApi.js +18 -18
- package/dist/src/@types/config/schemas.d.ts +10 -0
- package/dist/src/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue.d.ts +2 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue.d.ts +43 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue.d.ts +29 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue.d.ts +40 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue.d.ts +38 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue.d.ts +51 -0
- package/dist/src/composables/useConfig.d.ts +2 -0
- package/dist/src/composables/usePreviewInteractionGuard.d.ts +1 -1
- package/dist/src/composables/useRecommendation.d.ts +2 -0
- package/dist/src/composables/useStrategyFilters.d.ts +24 -0
- package/dist/src/enums/extensions/filteringV2.d.ts +72 -0
- package/dist/src/enums/extensions/recommendationBlock.d.ts +33 -0
- package/dist/src/enums/extensions/strategyDetail.d.ts +90 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/controlIds.d.ts +1 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/blockBackground/index.d.ts +14 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +1 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +10 -4
- package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +75 -0
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +903 -1
- package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +7 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyHumanizer.d.ts +50 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyNavigation.d.ts +10 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategySummary.d.ts +34 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyUrl.d.ts +51 -0
- package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +8 -1
- package/dist/src/extensions/Blocks/Unsubscribe/utils/constants.d.ts +1 -0
- package/dist/src/extensions/Blocks/common-control.d.ts +2 -1
- package/dist/src/extensions/Blocks/controlFactories.d.ts +36 -0
- package/dist/src/mock/api/recommendation-strategies.d.ts +2 -0
- package/dist/src/services/recommendationApi.d.ts +9 -1
- package/dist/src/stores/config.d.ts +18 -0
- package/dist/src/utils/genericUtil.d.ts +9 -0
- package/dist/src/utils/urlSchemes.d.ts +6 -0
- package/dist/static/styles/components/base-input.css.js +6 -7
- package/dist/utils/dateUtil.js +23 -10
- package/dist/utils/genericUtil.js +10 -1
- package/dist/utils/pairProductVariables.js +43 -44
- package/dist/utils/templatePreparation.js +70 -57
- package/dist/utils/urlSchemes.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
var $ = Object.defineProperty;
|
|
2
|
+
var O = (g, h, t) => h in g ? $(g, h, { enumerable: !0, configurable: !0, writable: !0, value: t }) : g[h] = t;
|
|
3
|
+
var u = (g, h, t) => O(g, typeof h != "symbol" ? h + "" : h, t);
|
|
4
|
+
import { useTranslations as f } from "../../../../../composables/useTranslations.js";
|
|
5
|
+
import { STRATEGY_PAGES as R } from "../../../../../enums/extensions/recommendationBlock.js";
|
|
6
|
+
import { formatShortDate as I } from "../../../../../utils/dateUtil.js";
|
|
7
|
+
import { UEAttr as b } from "../../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
8
|
+
import { CommonControl as L } from "../../../common-control.js";
|
|
9
|
+
import { useRecommendationExtensionStore as A } from "../../store/recommendation.js";
|
|
10
|
+
import { navigateToStrategyPage as w } from "../../utils/strategyNavigation.js";
|
|
11
|
+
import { buildStrategySummary as H } from "../../utils/strategySummary.js";
|
|
12
|
+
const D = "recommendation-strategy-control", T = {
|
|
13
|
+
CREATE_BUTTON: "strategyCreate",
|
|
14
|
+
DETAILS_BUTTON: "strategyDetails"
|
|
15
|
+
}, E = "guido__btn-strategy-create", C = "guido__btn-strategy-details", s = {
|
|
16
|
+
ROOT: "data-strategy-control",
|
|
17
|
+
TRIGGER: "data-strategy-trigger",
|
|
18
|
+
VALUE: "data-strategy-value",
|
|
19
|
+
MENU: "data-strategy-menu",
|
|
20
|
+
SEARCH: "data-strategy-search",
|
|
21
|
+
LIST: "data-strategy-list",
|
|
22
|
+
OPTION_ID: "data-strategy-id",
|
|
23
|
+
CARD: "data-strategy-card",
|
|
24
|
+
VIEW_MORE: "data-strategy-view-more"
|
|
25
|
+
}, _ = 8, M = 150, N = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zm0-2a7 7 0 1 0 0-14 7 7 0 0 0 0 14zm-1-7a1 1 0 1 1 2 0v4a1 1 0 1 1-2 0v-4zm1-5a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"></path></svg>', G = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 15.999a1.042 1.042 0 0 1-.784-.305l-5.91-5.91a1.045 1.045 0 1 1 1.478-1.478L12 13.522l5.216-5.216a1.045 1.045 0 1 1 1.478 1.478l-5.91 5.91a1.042 1.042 0 0 1-.784.305z"></path></svg>', o = (g) => g.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
26
|
+
class j extends L {
|
|
27
|
+
constructor() {
|
|
28
|
+
super(...arguments);
|
|
29
|
+
u(this, "store", A());
|
|
30
|
+
/**
|
|
31
|
+
* InOne's dictionary, not Stripo's. Every dotted key here
|
|
32
|
+
* (`discovery-strategy.*`, `gpt-app-builder.*`) lives in the host panel's
|
|
33
|
+
* translations, which `this.api.translate` does not read — that one is only
|
|
34
|
+
* for the plain-English control labels the rest of this panel uses.
|
|
35
|
+
*/
|
|
36
|
+
u(this, "trans", f());
|
|
37
|
+
u(this, "events", null);
|
|
38
|
+
u(this, "unsubscribeStore", null);
|
|
39
|
+
u(this, "searchTerm", "");
|
|
40
|
+
u(this, "isOpen", !1);
|
|
41
|
+
u(this, "cardHideTimer", null);
|
|
42
|
+
}
|
|
43
|
+
getId() {
|
|
44
|
+
return D;
|
|
45
|
+
}
|
|
46
|
+
getTemplate() {
|
|
47
|
+
return `
|
|
48
|
+
<div class="strategy-control" ${s.ROOT}>
|
|
49
|
+
${this._GuOneColumn([
|
|
50
|
+
this._GuLabel({ text: this.api.translate("Recommendation Strategy") }),
|
|
51
|
+
// The menu is absolutely positioned against THIS wrapper. Without
|
|
52
|
+
// it the menu is a grid item of the column container and its
|
|
53
|
+
// static position resolves to the container's top, so it opens
|
|
54
|
+
// over the label instead of under the trigger.
|
|
55
|
+
`<div class="strategy-control__field">
|
|
56
|
+
<div class="strategy-control__row">
|
|
57
|
+
<button type="button" class="strategy-select" ${s.TRIGGER}>
|
|
58
|
+
<span class="strategy-select__value" ${s.VALUE}></span>
|
|
59
|
+
<span class="strategy-select__caret">${G}</span>
|
|
60
|
+
</button>
|
|
61
|
+
${this._GuIconButton({
|
|
62
|
+
name: T.DETAILS_BUTTON,
|
|
63
|
+
icon: "strategy-settings-icon",
|
|
64
|
+
className: "strategy-control__details",
|
|
65
|
+
id: C
|
|
66
|
+
})}
|
|
67
|
+
</div>
|
|
68
|
+
<div class="strategy-menu" ${s.MENU} hidden>
|
|
69
|
+
<div class="strategy-menu__search">
|
|
70
|
+
<input type="text" class="strategy-menu__search-input" ${s.SEARCH}
|
|
71
|
+
placeholder="${o(this.trans("discovery-strategy.search"))}">
|
|
72
|
+
</div>
|
|
73
|
+
<ul class="strategy-menu__list" ${s.LIST}></ul>
|
|
74
|
+
</div>
|
|
75
|
+
</div>`,
|
|
76
|
+
`<div class="strategy-control__create-row">
|
|
77
|
+
${this._GuButton({
|
|
78
|
+
name: T.CREATE_BUTTON,
|
|
79
|
+
label: this.api.translate("Create New Strategy"),
|
|
80
|
+
id: E
|
|
81
|
+
})}
|
|
82
|
+
</div>`
|
|
83
|
+
])}
|
|
84
|
+
<div class="strategy-card" ${s.CARD} hidden></div>
|
|
85
|
+
</div>
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
onRender() {
|
|
89
|
+
this._setupEventListeners(), this._subscribeToStoreChanges(), this._render();
|
|
90
|
+
}
|
|
91
|
+
onDestroy() {
|
|
92
|
+
var t, e;
|
|
93
|
+
this._cancelHideCard(), (t = this.events) == null || t.abort(), this.events = null, (e = this.unsubscribeStore) == null || e.call(this), this.unsubscribeStore = null, this.isOpen = !1, this.searchTerm = "", super.onDestroy();
|
|
94
|
+
}
|
|
95
|
+
_root() {
|
|
96
|
+
var t;
|
|
97
|
+
return ((t = this.getContainer()) == null ? void 0 : t.querySelector(`[${s.ROOT}]`)) ?? null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* All listeners are delegated onto nodes that survive `innerHTML` rebuilds and
|
|
101
|
+
* are torn down together by the AbortController — the option rows themselves
|
|
102
|
+
* are replaced on every render and must never own a listener.
|
|
103
|
+
*/
|
|
104
|
+
_setupEventListeners() {
|
|
105
|
+
var d, c, m, p, y, v;
|
|
106
|
+
(d = this.events) == null || d.abort(), this.events = new AbortController();
|
|
107
|
+
const { signal: t } = this.events, e = this._root();
|
|
108
|
+
if (!e)
|
|
109
|
+
return;
|
|
110
|
+
(c = e.querySelector(`[${s.TRIGGER}]`)) == null || c.addEventListener("click", () => this._toggleMenu(), { signal: t }), (m = e.querySelector(`#${C}`)) == null || m.addEventListener("click", () => this.store.openStrategyDrawer(), { signal: t }), (p = e.querySelector(`#${E}`)) == null || p.addEventListener("click", () => w(R.CREATE), { signal: t }), (y = e.querySelector(`[${s.SEARCH}]`)) == null || y.addEventListener("input", (l) => {
|
|
111
|
+
this.searchTerm = l.target.value, this._renderOptions();
|
|
112
|
+
}, { signal: t });
|
|
113
|
+
const r = e.querySelector(`[${s.LIST}]`);
|
|
114
|
+
r == null || r.addEventListener("click", (l) => {
|
|
115
|
+
const n = l.target.closest(`[${s.OPTION_ID}]`), a = n == null ? void 0 : n.getAttribute(s.OPTION_ID);
|
|
116
|
+
a && (this._closeMenu(), this.store.selectStrategy(a));
|
|
117
|
+
}, { signal: t }), r == null || r.addEventListener("mouseenter", (l) => {
|
|
118
|
+
var a, S;
|
|
119
|
+
const n = (S = (a = l.target) == null ? void 0 : a.closest) == null ? void 0 : S.call(a, `[${s.OPTION_ID}]`);
|
|
120
|
+
n && this._showCard(n);
|
|
121
|
+
}, { capture: !0, signal: t }), r == null || r.addEventListener("mouseleave", () => this._scheduleHideCard(), { signal: t });
|
|
122
|
+
const i = e.querySelector(`[${s.CARD}]`);
|
|
123
|
+
i == null || i.addEventListener("mouseenter", () => this._cancelHideCard(), { signal: t }), i == null || i.addEventListener("mouseleave", () => this._hideCard(), { signal: t }), i == null || i.addEventListener("click", (l) => {
|
|
124
|
+
const n = l.target.closest(`[${s.VIEW_MORE}]`), a = n == null ? void 0 : n.getAttribute(s.VIEW_MORE);
|
|
125
|
+
a && (this._closeMenu(), a !== this.store.recommendationConfigs.strategyId && this.store.selectStrategy(a), this.store.openStrategyDrawer());
|
|
126
|
+
}, { signal: t }), (v = this.getContainer()) == null || v.addEventListener("mousedown", (l) => {
|
|
127
|
+
var n, a;
|
|
128
|
+
this.isOpen && !((a = (n = l.target).closest) != null && a.call(n, `[${s.ROOT}]`)) && this._closeMenu();
|
|
129
|
+
}, { signal: t });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Keeps the trigger label and the gear's enabled state in step with the store.
|
|
133
|
+
*
|
|
134
|
+
* Both depend on data that arrives after the first render: the strategy listing
|
|
135
|
+
* is fetched asynchronously, and `strategyId` changes when the user picks,
|
|
136
|
+
* duplicates, or switches blocks.
|
|
137
|
+
*/
|
|
138
|
+
_subscribeToStoreChanges() {
|
|
139
|
+
var e;
|
|
140
|
+
(e = this.unsubscribeStore) == null || e.call(this);
|
|
141
|
+
let t = this._stateKey();
|
|
142
|
+
this.unsubscribeStore = this.store.$subscribe(() => {
|
|
143
|
+
const r = this._stateKey();
|
|
144
|
+
r !== t && (t = r, this._render());
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Fingerprint of everything the rendered markup depends on.
|
|
149
|
+
*
|
|
150
|
+
* Ids rather than a count: a refetch that renames a strategy or swaps one for
|
|
151
|
+
* another of the same length would otherwise leave the trigger and the card
|
|
152
|
+
* showing stale copy until some unrelated store change happened to repaint.
|
|
153
|
+
*/
|
|
154
|
+
_stateKey() {
|
|
155
|
+
return [
|
|
156
|
+
this.store.recommendationConfigs.strategyId,
|
|
157
|
+
this.store.strategiesLoading,
|
|
158
|
+
this.store.strategies.map((t) => `${t.strategy_id}:${t.name}`).join(",")
|
|
159
|
+
].join("|");
|
|
160
|
+
}
|
|
161
|
+
_render() {
|
|
162
|
+
this._renderTrigger(), this._renderOptions(), this.api.setUIEAttribute(
|
|
163
|
+
T.DETAILS_BUTTON,
|
|
164
|
+
b.BUTTON.disabled,
|
|
165
|
+
this.store.getSelectedStrategy ? "false" : "true"
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
_renderTrigger() {
|
|
169
|
+
var r;
|
|
170
|
+
const t = (r = this._root()) == null ? void 0 : r.querySelector(`[${s.VALUE}]`);
|
|
171
|
+
if (!t)
|
|
172
|
+
return;
|
|
173
|
+
const e = this.store.getSelectedStrategy;
|
|
174
|
+
t.textContent = (e == null ? void 0 : e.name) ?? this.trans("smart-recommender.select-recommendation-strategy"), t.classList.toggle("strategy-select__value--placeholder", !e), t.classList.toggle("strategy-select__value--missing", this.store.hasMissingStrategy);
|
|
175
|
+
}
|
|
176
|
+
_renderOptions() {
|
|
177
|
+
var i;
|
|
178
|
+
const t = (i = this._root()) == null ? void 0 : i.querySelector(`[${s.LIST}]`);
|
|
179
|
+
if (!t)
|
|
180
|
+
return;
|
|
181
|
+
if (this._hideCard(), this.store.strategiesLoading) {
|
|
182
|
+
t.innerHTML = `<li class="strategy-menu__empty">${o(
|
|
183
|
+
this.trans("newsletter.loading")
|
|
184
|
+
)}</li>`;
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const e = this._filteredStrategies();
|
|
188
|
+
if (!e.length) {
|
|
189
|
+
t.innerHTML = `<li class="strategy-menu__empty">${o(
|
|
190
|
+
this.trans("discovery-strategy.no-data-title-text")
|
|
191
|
+
)}</li>`;
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const r = this.store.recommendationConfigs.strategyId;
|
|
195
|
+
t.innerHTML = e.map((d) => {
|
|
196
|
+
const c = String(d.strategy_id);
|
|
197
|
+
return `<li class="strategy-menu__option${c === r ? " strategy-menu__option--selected" : ""}"
|
|
198
|
+
${s.OPTION_ID}="${o(c)}">${o(d.name)}</li>`;
|
|
199
|
+
}).join("");
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Client-side filtering: the listing is fetched whole and cached, so narrowing
|
|
203
|
+
* it here avoids a request per keystroke.
|
|
204
|
+
*/
|
|
205
|
+
_filteredStrategies() {
|
|
206
|
+
const t = this.searchTerm.trim().toLowerCase();
|
|
207
|
+
return t ? this.store.strategies.filter((e) => e.name.toLowerCase().includes(t)) : this.store.strategies;
|
|
208
|
+
}
|
|
209
|
+
_toggleMenu() {
|
|
210
|
+
var e, r, i;
|
|
211
|
+
if (this.isOpen) {
|
|
212
|
+
this._closeMenu();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
this.isOpen = !0;
|
|
216
|
+
const t = this._root();
|
|
217
|
+
(e = t == null ? void 0 : t.querySelector(`[${s.MENU}]`)) == null || e.removeAttribute("hidden"), (r = t == null ? void 0 : t.querySelector(`[${s.TRIGGER}]`)) == null || r.classList.add("strategy-select--open"), this._renderOptions(), (i = t == null ? void 0 : t.querySelector(`[${s.SEARCH}]`)) == null || i.focus();
|
|
218
|
+
}
|
|
219
|
+
_closeMenu() {
|
|
220
|
+
var r, i;
|
|
221
|
+
this.isOpen = !1, this.searchTerm = "", this._hideCard();
|
|
222
|
+
const t = this._root(), e = t == null ? void 0 : t.querySelector(`[${s.SEARCH}]`);
|
|
223
|
+
e && (e.value = ""), (r = t == null ? void 0 : t.querySelector(`[${s.MENU}]`)) == null || r.setAttribute("hidden", ""), (i = t == null ? void 0 : t.querySelector(`[${s.TRIGGER}]`)) == null || i.classList.remove("strategy-select--open");
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The hover card is `position: fixed`, so it can sit beside the panel instead of
|
|
227
|
+
* being clipped by it. Placed once per hover — the list cannot scroll under the
|
|
228
|
+
* pointer without the pointer leaving, so there is nothing to keep in sync.
|
|
229
|
+
*/
|
|
230
|
+
_showCard(t) {
|
|
231
|
+
var y;
|
|
232
|
+
const e = (y = this._root()) == null ? void 0 : y.querySelector(`[${s.CARD}]`), r = t.getAttribute(s.OPTION_ID), i = this.store.strategies.find((v) => String(v.strategy_id) === r);
|
|
233
|
+
if (!e || !i)
|
|
234
|
+
return;
|
|
235
|
+
this._cancelHideCard(), e.innerHTML = this._buildCardHtml(i), e.removeAttribute("hidden");
|
|
236
|
+
const d = t.getBoundingClientRect(), c = e.getBoundingClientRect(), m = d.left - c.width - _ >= _ ? d.left - c.width - _ : d.right + _, p = window.innerHeight - c.height - _;
|
|
237
|
+
e.style.left = `${Math.max(_, m)}px`, e.style.top = `${Math.min(Math.max(_, d.top), Math.max(_, p))}px`;
|
|
238
|
+
}
|
|
239
|
+
/** Grace period for the pointer to cross the gap between option and card. */
|
|
240
|
+
_scheduleHideCard() {
|
|
241
|
+
this._cancelHideCard(), this.cardHideTimer = setTimeout(() => this._hideCard(), M);
|
|
242
|
+
}
|
|
243
|
+
_cancelHideCard() {
|
|
244
|
+
this.cardHideTimer && (clearTimeout(this.cardHideTimer), this.cardHideTimer = null);
|
|
245
|
+
}
|
|
246
|
+
_hideCard() {
|
|
247
|
+
var t, e;
|
|
248
|
+
this._cancelHideCard(), (e = (t = this._root()) == null ? void 0 : t.querySelector(`[${s.CARD}]`)) == null || e.setAttribute("hidden", "");
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Mirrors the design system's `InInfoBox`: coloured top rule, heading +
|
|
252
|
+
* "last updated" details, content, then a divided footer holding the View
|
|
253
|
+
* More text button. The component itself cannot render here, so the markup
|
|
254
|
+
* and the CSS reproduce its structure and tokens rather than approximating
|
|
255
|
+
* them — the values in `recommendation.css` are read from its stylesheet.
|
|
256
|
+
*/
|
|
257
|
+
_buildCardHtml(t) {
|
|
258
|
+
const { trans: e } = this, r = H(t, e).map((i) => `
|
|
259
|
+
<div class="strategy-card__row">
|
|
260
|
+
<p class="strategy-card__row-title">${o(i.title)}</p>
|
|
261
|
+
<p class="strategy-card__row-value">${o(i.value)}</p>
|
|
262
|
+
</div>
|
|
263
|
+
`).join("");
|
|
264
|
+
return `
|
|
265
|
+
<div class="strategy-card__body">
|
|
266
|
+
<p class="strategy-card__title">${o(t.name)}</p>
|
|
267
|
+
<p class="strategy-card__updated">${o(e("gpt-app-builder.strategy-last-updated", {
|
|
268
|
+
date: I(t.updated_at)
|
|
269
|
+
}))}</p>
|
|
270
|
+
<div class="strategy-card__rows">${r}</div>
|
|
271
|
+
</div>
|
|
272
|
+
<div class="strategy-card__footer">
|
|
273
|
+
<button type="button" class="strategy-card__more"
|
|
274
|
+
${s.VIEW_MORE}="${o(String(t.strategy_id))}">
|
|
275
|
+
${N}
|
|
276
|
+
<span>${o(e("gpt-app-builder.view-more"))}</span>
|
|
277
|
+
</button>
|
|
278
|
+
</div>
|
|
279
|
+
`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
export {
|
|
283
|
+
D as STRATEGY_CONTROL_ID,
|
|
284
|
+
j as StrategyControl
|
|
285
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExtensionBuilder as
|
|
1
|
+
import { ExtensionBuilder as t } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
2
|
import { RecommendationBlock as m } from "./block.js";
|
|
3
3
|
import n from "./canvasPreview.css.js";
|
|
4
4
|
import { RecommendationBlockControl as i } from "./controls/main/index.js";
|
|
@@ -6,42 +6,44 @@ import "./constants/selectors.js";
|
|
|
6
6
|
import "./store/recommendation.js";
|
|
7
7
|
import "./utils/captureStyleTemplates.js";
|
|
8
8
|
import { NameControls as e } from "./controls/name/index.js";
|
|
9
|
-
import { PriceControls as
|
|
10
|
-
import { OldPriceControls as
|
|
9
|
+
import { PriceControls as l } from "./controls/price/index.js";
|
|
10
|
+
import { OldPriceControls as s } from "./controls/oldPrice/index.js";
|
|
11
11
|
import { OmnibusPriceControls as p } from "./controls/omnibusPrice/index.js";
|
|
12
12
|
import { OmnibusDiscountControls as a } from "./controls/omnibusDiscount/index.js";
|
|
13
13
|
import { ButtonControls as c } from "./controls/button/index.js";
|
|
14
|
-
import { ImageControls as
|
|
15
|
-
import { CustomAttributeControls as
|
|
14
|
+
import { ImageControls as C } from "./controls/image/index.js";
|
|
15
|
+
import { CustomAttributeControls as f } from "./controls/customAttribute/index.js";
|
|
16
16
|
import { SpacingControl as d } from "./controls/spacing/index.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
17
|
+
import { BlockBackgroundColorControl as u } from "./controls/blockBackground/index.js";
|
|
18
|
+
import { CardBackgroundColorControl as g } from "./controls/cardBackground/index.js";
|
|
19
|
+
import { RecommendationCardCompositionControl as y } from "./controls/cardComposition/index.js";
|
|
20
|
+
import { SyncInfoMessageControl as B } from "./controls/syncInfoMessage.js";
|
|
20
21
|
import { RecommendationIconsRegistry as P } from "./iconsRegistry.js";
|
|
21
22
|
import R from "./recommendation.css.js";
|
|
22
23
|
import { SettingsPanel as S } from "./settingsPanel.js";
|
|
23
|
-
const
|
|
24
|
+
const k = [
|
|
24
25
|
e,
|
|
25
|
-
s,
|
|
26
26
|
l,
|
|
27
|
+
s,
|
|
27
28
|
p,
|
|
28
29
|
a,
|
|
29
30
|
c,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
],
|
|
31
|
+
C,
|
|
32
|
+
f
|
|
33
|
+
], w = [
|
|
33
34
|
i,
|
|
34
35
|
u,
|
|
35
|
-
d,
|
|
36
36
|
g,
|
|
37
|
-
|
|
37
|
+
d,
|
|
38
|
+
y,
|
|
39
|
+
B
|
|
38
40
|
], b = [
|
|
39
|
-
...
|
|
40
|
-
...
|
|
41
|
-
],
|
|
42
|
-
(o,
|
|
43
|
-
new
|
|
41
|
+
...w,
|
|
42
|
+
...k.flatMap((o) => Object.values(o))
|
|
43
|
+
], W = b.reduce(
|
|
44
|
+
(o, r) => o.addControl(r),
|
|
45
|
+
new t().addBlock(m).withSettingsPanelRegistry(S)
|
|
44
46
|
).addStyles(R).withPreviewStyles(n).withIconsRegistry(P).build();
|
|
45
47
|
export {
|
|
46
|
-
|
|
48
|
+
W as default
|
|
47
49
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import r from "../../../static/assets/info.svg.js";
|
|
2
2
|
import { IconsRegistry as C } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
3
|
-
class
|
|
3
|
+
class l extends C {
|
|
4
4
|
registerIconsSvg(t) {
|
|
5
5
|
t["recommendation-icon"] = `
|
|
6
6
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
|
@@ -74,9 +74,23 @@ class h extends C {
|
|
|
74
74
|
<path d="M17 2V18C17 18.5523 16.5523 19 16 19H10V1H16C16.5523 1 17 1.44772 17 2Z" stroke="currentColor"
|
|
75
75
|
stroke-width="2" fill="none"/>
|
|
76
76
|
</svg>
|
|
77
|
+
`, t["strategy-settings-icon"] = `
|
|
78
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
|
|
79
|
+
fill="currentColor">
|
|
80
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 4a1 1 0 0 0-1-1h-2a1 1 0 0 0-1 1v.757c0
|
|
81
|
+
.891-1.077 1.337-1.707.708l-.536-.536a1 1 0 0 0-1.414 0L4.93 6.343a1 1 0 0 0 0
|
|
82
|
+
1.414l.535.536c.63.63.184 1.707-.707 1.707H4a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h.757c.891 0
|
|
83
|
+
1.337 1.077.708 1.707l-.536.536a1 1 0 0 0 0 1.414l1.414 1.414a1 1 0 0 0 1.414
|
|
84
|
+
0l.536-.535c.63-.63 1.707-.184 1.707.707V20a1 1 0 0 0 1 1h2a1 1 0 0 0
|
|
85
|
+
1-1v-.757c0-.891 1.077-1.337 1.707-.707l.536.535a1 1 0 0 0 1.414 0l1.414-1.414a1 1 0 0 0
|
|
86
|
+
0-1.414l-.536-.536c-.63-.63-.183-1.707.708-1.707H20a1 1 0 0 0 1-1v-2a1 1 0 0
|
|
87
|
+
0-1-1h-.757c-.891 0-1.337-1.077-.707-1.707l.535-.536a1 1 0 0 0
|
|
88
|
+
0-1.414L17.657 4.93a1 1 0 0 0-1.414 0l-.536.536c-.63.63-1.707.183-1.707-.708V4zm3 8a5 5 0
|
|
89
|
+
1 1-10 0 5 5 0 0 1 10 0zm-5 2a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path>
|
|
90
|
+
</svg>
|
|
77
91
|
`, t["migration-info-icon"] = r;
|
|
78
92
|
}
|
|
79
93
|
}
|
|
80
94
|
export {
|
|
81
|
-
|
|
95
|
+
l as RecommendationIconsRegistry
|
|
82
96
|
};
|
|
@@ -289,6 +289,263 @@ ue-orderable.orderable-disabled .droppable-icon {
|
|
|
289
289
|
font-weight: 400;
|
|
290
290
|
line-height: 16px;
|
|
291
291
|
}
|
|
292
|
+
|
|
293
|
+
/*
|
|
294
|
+
* Recommendation Strategy picker (controls/main/strategy.ts).
|
|
295
|
+
*
|
|
296
|
+
* Lives inside the settings panel, so it scrolls with it and needs no positioning
|
|
297
|
+
* code. Only the hover card escapes the panel, via \`position: fixed\`.
|
|
298
|
+
*
|
|
299
|
+
* The values below are the design system's own, read from its stylesheets
|
|
300
|
+
* (\`combobox.css\` for the trigger, \`InInfoBox\`'s CSS for the card). The \`In*\`
|
|
301
|
+
* components themselves cannot render in this shadow root — they are styled from
|
|
302
|
+
* the host document, and copying their stylesheets across drags normalize.css and
|
|
303
|
+
* a global \`*\`/\`svg\` reset into Stripo's panel.
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
/*
|
|
307
|
+
* Anchors the dropdown. Without a positioned wrapper the menu is a grid item of
|
|
308
|
+
* the column container, and its absolute static position resolves to that
|
|
309
|
+
* container's top — so it opens over the label instead of under the trigger.
|
|
310
|
+
*/
|
|
311
|
+
.strategy-control__field {
|
|
312
|
+
position: relative;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.strategy-control__row {
|
|
316
|
+
display: flex;
|
|
317
|
+
align-items: center;
|
|
318
|
+
gap: 8px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/*
|
|
322
|
+
* Same tokens as \`ue-select .button\` in components/combobox.css, so the strategy
|
|
323
|
+
* trigger is indistinguishable from Recommendation Locale / Currency beside it.
|
|
324
|
+
* It cannot simply reuse that rule: the selector is scoped to \`ue-select\`, and a
|
|
325
|
+
* Stripo select cannot render this control's per-option hover card.
|
|
326
|
+
*/
|
|
327
|
+
.strategy-select {
|
|
328
|
+
display: flex;
|
|
329
|
+
flex: 1;
|
|
330
|
+
align-items: center;
|
|
331
|
+
justify-content: space-between;
|
|
332
|
+
gap: 8px;
|
|
333
|
+
min-width: 0;
|
|
334
|
+
min-height: 40px;
|
|
335
|
+
padding: 8px;
|
|
336
|
+
overflow: hidden;
|
|
337
|
+
background-color: var(--guido-color-gray-0);
|
|
338
|
+
border: 1px solid var(--guido-color-gray-300);
|
|
339
|
+
border-radius: 4px;
|
|
340
|
+
box-shadow: none;
|
|
341
|
+
cursor: pointer;
|
|
342
|
+
font-size: 13px;
|
|
343
|
+
color: var(--guido-color-gray-800);
|
|
344
|
+
text-align: left;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.strategy-select:hover {
|
|
348
|
+
border-color: var(--guido-color-primary-500);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* Matches the focus ring Stripo paints on an open select. */
|
|
352
|
+
.strategy-select--open {
|
|
353
|
+
border-color: var(--guido-color-primary-500);
|
|
354
|
+
box-shadow: 0 0 0 3px var(--guido-color-primary-200);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.strategy-select__value {
|
|
358
|
+
overflow: hidden;
|
|
359
|
+
text-overflow: ellipsis;
|
|
360
|
+
white-space: nowrap;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.strategy-select__value--placeholder {
|
|
364
|
+
color: var(--guido-color-gray-700);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.strategy-select__value--missing {
|
|
368
|
+
color: var(--guido-color-danger-500);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.strategy-select__caret {
|
|
372
|
+
display: flex;
|
|
373
|
+
flex: none;
|
|
374
|
+
color: var(--guido-color-gray-800);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/* The gear button sits beside the trigger and must not stretch with it. */
|
|
378
|
+
.strategy-control__details {
|
|
379
|
+
flex: none;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.strategy-menu {
|
|
383
|
+
position: absolute;
|
|
384
|
+
z-index: 5;
|
|
385
|
+
top: 100%;
|
|
386
|
+
right: 0;
|
|
387
|
+
left: 0;
|
|
388
|
+
margin-top: 4px;
|
|
389
|
+
overflow: hidden;
|
|
390
|
+
background: var(--guido-color-white);
|
|
391
|
+
border: 1px solid var(--guido-color-gray-300);
|
|
392
|
+
border-radius: 4px;
|
|
393
|
+
box-shadow: var(--guido-box-shadow);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.strategy-menu[hidden] {
|
|
397
|
+
display: none;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.strategy-menu__search {
|
|
401
|
+
padding: 8px;
|
|
402
|
+
border-bottom: 1px solid var(--guido-color-gray-300);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.strategy-menu__search-input {
|
|
406
|
+
box-sizing: border-box;
|
|
407
|
+
width: 100%;
|
|
408
|
+
height: 32px;
|
|
409
|
+
padding: 4px 8px;
|
|
410
|
+
border: 1px solid var(--guido-color-gray-300);
|
|
411
|
+
border-radius: 4px;
|
|
412
|
+
font: inherit;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.strategy-menu__list {
|
|
416
|
+
max-height: 240px;
|
|
417
|
+
margin: 0;
|
|
418
|
+
padding: 0;
|
|
419
|
+
overflow-y: auto;
|
|
420
|
+
list-style: none;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.strategy-menu__option {
|
|
424
|
+
overflow: hidden;
|
|
425
|
+
padding: 8px 12px;
|
|
426
|
+
cursor: pointer;
|
|
427
|
+
font-size: 13px;
|
|
428
|
+
text-overflow: ellipsis;
|
|
429
|
+
white-space: nowrap;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.strategy-menu__option:hover {
|
|
433
|
+
background: var(--guido-color-gray-100);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.strategy-menu__option--selected {
|
|
437
|
+
color: var(--guido-color-primary-500);
|
|
438
|
+
background: var(--guido-color-primary-0);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.strategy-menu__empty {
|
|
442
|
+
padding: 12px;
|
|
443
|
+
color: var(--guido-color-gray-600);
|
|
444
|
+
font-size: 13px;
|
|
445
|
+
text-align: center;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.strategy-control__create-row {
|
|
449
|
+
margin-top: 8px;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/*
|
|
453
|
+
* \`_GuButton\` renders <ue-button> > .control-shadow-wrapper > button.button, and
|
|
454
|
+
* every level is shrink-to-fit. Stretching only the innermost one leaves the
|
|
455
|
+
* button its intrinsic width, which is why the design's full-width row needs all
|
|
456
|
+
* three.
|
|
457
|
+
*/
|
|
458
|
+
.strategy-control__create-row ue-button,
|
|
459
|
+
.strategy-control__create-row .control-shadow-wrapper,
|
|
460
|
+
.strategy-control__create-row .button {
|
|
461
|
+
display: block;
|
|
462
|
+
width: 100%;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/*
|
|
466
|
+
* Hover card. Reproduces the design system's \`InInfoBox\` — same 240px medium
|
|
467
|
+
* width, 4px information-blue top rule, 16px body, and a divided footer for the
|
|
468
|
+
* View More button.
|
|
469
|
+
*
|
|
470
|
+
* \`position: fixed\` so the card sits beside the narrow panel instead of being
|
|
471
|
+
* clipped by it.
|
|
472
|
+
*/
|
|
473
|
+
.strategy-card {
|
|
474
|
+
position: fixed;
|
|
475
|
+
z-index: 10;
|
|
476
|
+
width: 240px;
|
|
477
|
+
background: var(--guido-color-white);
|
|
478
|
+
border-top: 4px solid var(--guido-color-border-onpage-message-info);
|
|
479
|
+
border-radius: 4px;
|
|
480
|
+
box-shadow: 0 4px 12px rgba(57, 57, 57, 0.15);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.strategy-card[hidden] {
|
|
484
|
+
display: none;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.strategy-card__body {
|
|
488
|
+
padding: 16px;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.strategy-card__title {
|
|
492
|
+
margin: 0;
|
|
493
|
+
color: var(--guido-color-gray-800);
|
|
494
|
+
font-size: 16px;
|
|
495
|
+
font-weight: 600;
|
|
496
|
+
line-height: 24px;
|
|
497
|
+
word-break: break-word;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.strategy-card__updated {
|
|
501
|
+
margin: 4px 0 0;
|
|
502
|
+
color: var(--guido-color-gray-600);
|
|
503
|
+
font-size: 13px;
|
|
504
|
+
font-weight: 400;
|
|
505
|
+
line-height: 16px;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.strategy-card__rows {
|
|
509
|
+
margin-top: 16px;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.strategy-card__row + .strategy-card__row {
|
|
513
|
+
margin-top: 12px;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
.strategy-card__row-title {
|
|
517
|
+
margin: 0;
|
|
518
|
+
color: var(--guido-color-gray-600);
|
|
519
|
+
font-size: 12px;
|
|
520
|
+
line-height: 16px;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.strategy-card__row-value {
|
|
524
|
+
margin: 0;
|
|
525
|
+
color: var(--guido-color-gray-800);
|
|
526
|
+
font-size: 13px;
|
|
527
|
+
line-height: 18px;
|
|
528
|
+
word-break: break-word;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.strategy-card__footer {
|
|
532
|
+
padding: 8px 16px;
|
|
533
|
+
border-top: 1px solid var(--guido-color-gray-300);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.strategy-card__more {
|
|
537
|
+
display: flex;
|
|
538
|
+
align-items: center;
|
|
539
|
+
gap: 4px;
|
|
540
|
+
padding: 0;
|
|
541
|
+
color: var(--guido-color-primary-500);
|
|
542
|
+
background: none;
|
|
543
|
+
border: 0;
|
|
544
|
+
cursor: pointer;
|
|
545
|
+
font-size: 13px;
|
|
546
|
+
font-weight: 600;
|
|
547
|
+
line-height: 16px;
|
|
548
|
+
}
|
|
292
549
|
`;
|
|
293
550
|
export {
|
|
294
551
|
n as default
|