@askdialog/dialog-sdk 2.6.1 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/Dialog.d.ts +2 -1
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Dialog.js +13 -1
- package/dist/__tests__/dialogAddToCart.spec.js +12 -1
- package/dist/__tests__/dialogLoadAssistant.spec.js +23 -6
- package/dist/__tests__/searchControllerAttribution.spec.js +42 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/searchController.d.ts.map +1 -1
- package/dist/searchController.js +6 -3
- package/dist/types/constructor.d.ts +10 -0
- package/dist/types/constructor.d.ts.map +1 -1
- package/dist/types/searchController.d.ts +16 -3
- package/dist/types/searchController.d.ts.map +1 -1
- package/dist/utils/localization.d.ts +3 -0
- package/dist/utils/localization.d.ts.map +1 -1
- package/dist/utils/localization.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -100,6 +100,26 @@ If your site uses OneTrust auto-blocking, it may neutralize the assistant script
|
|
|
100
100
|
|
|
101
101
|
Either is compliance-safe with regard to analytics: the assistant gates all analytics on consent internally and sends nothing without an explicit opt-in (inspect `window.dialog.audit.consent`).
|
|
102
102
|
|
|
103
|
+
### Disabling add-to-cart
|
|
104
|
+
|
|
105
|
+
Some sessions must hide purchasing actions — for example a B2B storefront that hides its own add-to-cart when a B2B customer is logged in. Pass the optional `disableAddToCart: true` constructor flag (type `boolean`, default `false`) to suppress Dialog add-to-cart for that widget instance/session:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
new Dialog({
|
|
109
|
+
apiKey: 'YOUR_API_KEY',
|
|
110
|
+
locale: 'fr',
|
|
111
|
+
disableAddToCart: true, // hide the add-to-cart CTA for this session
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
When set:
|
|
116
|
+
|
|
117
|
+
- the assistant hides/disables the add-to-cart CTA on both product recommendation cards and conversational product cards;
|
|
118
|
+
- `client.addToCart(...)` becomes a no-op — it never invokes your `callbacks.addToCart` and emits no `TRACK_ADD_TO_CART` event, so a stale UI cannot add to the cart or pollute analytics;
|
|
119
|
+
- product links and recommendation browsing are unaffected.
|
|
120
|
+
|
|
121
|
+
Omit the flag (or set it to `false`) to keep the default behavior — the add-to-cart CTA and analytics are unchanged.
|
|
122
|
+
|
|
103
123
|
### Getters
|
|
104
124
|
|
|
105
125
|
- apiKey
|
package/dist/Dialog.d.ts
CHANGED
|
@@ -18,7 +18,8 @@ export declare class Dialog {
|
|
|
18
18
|
private _userId;
|
|
19
19
|
private _eventsHandler;
|
|
20
20
|
private _ignoreOneTrustAutoBlock;
|
|
21
|
-
|
|
21
|
+
private _disableAddToCart;
|
|
22
|
+
constructor({ apiKey, locale, countryCode, callbacks, theme, userId, ignoreOneTrustAutoBlock, disableAddToCart, }: DialogConstructor);
|
|
22
23
|
get apiKey(): string;
|
|
23
24
|
get theme(): Theme;
|
|
24
25
|
get userId(): string;
|
package/dist/Dialog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../src/Dialog.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EACL,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,cAAc,EAEd,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE9E,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,qBAAa,MAAM;IACjB,gBAAuB,OAAO,SAAuB;IAErD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAAS;IAE9B,OAAO,CAAC,UAAU,CAAC,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,wBAAwB,CAAU;
|
|
1
|
+
{"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../src/Dialog.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EACL,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,cAAc,EAEd,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE9E,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,qBAAa,MAAM;IACjB,gBAAuB,OAAO,SAAuB;IAErD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAAS;IAE9B,OAAO,CAAC,UAAU,CAAC,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,wBAAwB,CAAU;IAC1C,OAAO,CAAC,iBAAiB,CAAU;gBAEvB,EACV,MAAM,EACN,MAAM,EACN,WAAW,EACX,SAAS,EACT,KAAK,EACL,MAAM,EACN,uBAAuB,EACvB,gBAAgB,GACjB,EAAE,iBAAiB;IAcpB,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,KAAK,IAAI,KAAK,CAExB;IACD,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,MAAM,IAAI,MAAM,CAE1B;IACD,IAAW,aAAa,IAAI,aAAa,CAExC;IAEM,2BAA2B,IAAI,kBAAkB,GAAG,IAAI;IAI/D,OAAO,CAAC,uBAAuB;IAkBlB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAInE;;;;;;OAMG;IACI,MAAM,CACX,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,cAAc,CAAC;IAKnB,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAKjD,cAAc,IAAI,IAAI;IAItB,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAIxD,kBAAkB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAOxD,gBAAgB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAIjE,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAInD,UAAU,CACf,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAUhB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB5D,OAAO,CAAC,oBAAoB;IAUrB,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAcnD,2BAA2B,CAChC,MAAM,EAAE,oBAAoB,GAAG,oBAAoB,GAClD,IAAI;IA0BP;;;;OAIG;IACI,sBAAsB,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI;IAUpE;;;OAGG;IACI,uBAAuB,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI;IAUtE,OAAO,CAAC,cAAc;CAsCvB"}
|
package/dist/Dialog.js
CHANGED
|
@@ -20,12 +20,14 @@ export class Dialog {
|
|
|
20
20
|
_userId;
|
|
21
21
|
_eventsHandler;
|
|
22
22
|
_ignoreOneTrustAutoBlock;
|
|
23
|
-
|
|
23
|
+
_disableAddToCart;
|
|
24
|
+
constructor({ apiKey, locale, countryCode, callbacks, theme, userId, ignoreOneTrustAutoBlock, disableAddToCart, }) {
|
|
24
25
|
this._apiKey = apiKey;
|
|
25
26
|
this._locale = locale;
|
|
26
27
|
this._countryCode = countryCode;
|
|
27
28
|
this._callbacks = callbacks;
|
|
28
29
|
this._ignoreOneTrustAutoBlock = ignoreOneTrustAutoBlock ?? false;
|
|
30
|
+
this._disableAddToCart = disableAddToCart ?? false;
|
|
29
31
|
this._theme = { ...defaultTheme, ...theme };
|
|
30
32
|
this._userId = this._createOrRetrieveUserId(userId);
|
|
31
33
|
this._eventsHandler = new EventsHandler(locale, userId);
|
|
@@ -103,6 +105,12 @@ export class Dialog {
|
|
|
103
105
|
// forwarded to the merchant callback and to the tracking event, so
|
|
104
106
|
// integrations can consume the added-product data wherever they hook in.
|
|
105
107
|
async addToCart(input) {
|
|
108
|
+
// No-op when disabled, so a stale UI that still surfaced the CTA cannot
|
|
109
|
+
// add to the cart or emit analytics.
|
|
110
|
+
if (this._disableAddToCart) {
|
|
111
|
+
console.warn("Dialog: addToCart is disabled on this instance (disableAddToCart); ignoring the call.");
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
106
114
|
await this._getCallbacksOrThrow("addToCart").addToCart(input);
|
|
107
115
|
this.registerAddToCartEvent(input);
|
|
108
116
|
return;
|
|
@@ -182,6 +190,10 @@ export class Dialog {
|
|
|
182
190
|
div.dataset.userId = this._userId;
|
|
183
191
|
div.dataset.countryCode = localeInfo.countryCode;
|
|
184
192
|
div.dataset.language = localeInfo.language;
|
|
193
|
+
if (this._disableAddToCart) {
|
|
194
|
+
// Read by the assistant runtime to hide the add-to-cart CTA.
|
|
195
|
+
div.dataset.disableAddToCart = "true";
|
|
196
|
+
}
|
|
185
197
|
document.body.appendChild(div);
|
|
186
198
|
setTimeout(() => {
|
|
187
199
|
const script = document.createElement("script");
|
|
@@ -5,7 +5,7 @@ import { DialogEvents } from "../types/events";
|
|
|
5
5
|
// The full Dialog constructor loads the assistant into the DOM; these tests
|
|
6
6
|
// only exercise the add-to-cart pass-through, so the instance is built from
|
|
7
7
|
// the prototype with just the fields addToCart/registerAddToCartEvent read.
|
|
8
|
-
const buildDialog = (addToCartCallback) => {
|
|
8
|
+
const buildDialog = (addToCartCallback, disableAddToCart = false) => {
|
|
9
9
|
const eventsHandler = new EventsHandler("fr", "user-1");
|
|
10
10
|
const emitExternalEvent = vi.fn();
|
|
11
11
|
eventsHandler.emitExternalEvent =
|
|
@@ -15,6 +15,7 @@ const buildDialog = (addToCartCallback) => {
|
|
|
15
15
|
_callbacks: { addToCart: addToCartCallback, getProduct: vi.fn() },
|
|
16
16
|
_eventsHandler: eventsHandler,
|
|
17
17
|
_userId: "user-1",
|
|
18
|
+
_disableAddToCart: disableAddToCart,
|
|
18
19
|
});
|
|
19
20
|
return { dialog, emitExternalEvent };
|
|
20
21
|
};
|
|
@@ -56,4 +57,14 @@ describe("Dialog.addToCart", () => {
|
|
|
56
57
|
expect(addToCartCallback).toHaveBeenCalledWith(legacyInput);
|
|
57
58
|
expect(emitExternalEvent).toHaveBeenCalledWith(DialogEvents.TRACK_ADD_TO_CART, { userId: "user-1", ...legacyInput });
|
|
58
59
|
});
|
|
60
|
+
it("is a no-op when disableAddToCart is set: no callback, no event", async () => {
|
|
61
|
+
const addToCartCallback = vi.fn().mockResolvedValue(undefined);
|
|
62
|
+
const { dialog, emitExternalEvent } = buildDialog(addToCartCallback, true);
|
|
63
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
64
|
+
await expect(dialog.addToCart(enrichedInput)).resolves.toBeUndefined();
|
|
65
|
+
expect(addToCartCallback).not.toHaveBeenCalled();
|
|
66
|
+
expect(emitExternalEvent).not.toHaveBeenCalled();
|
|
67
|
+
expect(warn).toHaveBeenCalledOnce();
|
|
68
|
+
warn.mockRestore();
|
|
69
|
+
});
|
|
59
70
|
});
|
|
@@ -3,25 +3,28 @@ import { Dialog } from "../Dialog";
|
|
|
3
3
|
// The full Dialog constructor touches window/localStorage; these tests only
|
|
4
4
|
// exercise the assistant script injection, so the instance is built from the
|
|
5
5
|
// prototype with just the fields _loadAssistant reads.
|
|
6
|
-
const buildDialog = (
|
|
6
|
+
const buildDialog = (overrides = {}) => {
|
|
7
7
|
const dialog = Object.create(Dialog.prototype);
|
|
8
8
|
Object.assign(dialog, {
|
|
9
9
|
_apiKey: "api-key-1",
|
|
10
10
|
_userId: "user-1",
|
|
11
11
|
_locale: "fr-FR",
|
|
12
|
-
_ignoreOneTrustAutoBlock:
|
|
12
|
+
_ignoreOneTrustAutoBlock: false,
|
|
13
|
+
_disableAddToCart: false,
|
|
14
|
+
...overrides,
|
|
13
15
|
});
|
|
14
16
|
return dialog;
|
|
15
17
|
};
|
|
16
18
|
const stubDocument = () => {
|
|
17
19
|
const script = { setAttribute: vi.fn() };
|
|
20
|
+
const div = { dataset: {} };
|
|
18
21
|
const insertBefore = vi.fn();
|
|
19
22
|
vi.stubGlobal("document", {
|
|
20
|
-
createElement: (tag) => tag === "script" ? script :
|
|
23
|
+
createElement: (tag) => (tag === "script" ? script : div),
|
|
21
24
|
body: { appendChild: vi.fn() },
|
|
22
25
|
head: { insertBefore, firstChild: null },
|
|
23
26
|
});
|
|
24
|
-
return { script, insertBefore };
|
|
27
|
+
return { script, div, insertBefore };
|
|
25
28
|
};
|
|
26
29
|
const loadAssistant = (dialog) => {
|
|
27
30
|
dialog._loadAssistant();
|
|
@@ -36,15 +39,29 @@ describe("Dialog._loadAssistant OneTrust exemption", () => {
|
|
|
36
39
|
it("sets data-ot-ignore on the injected script when opted in", () => {
|
|
37
40
|
vi.useFakeTimers();
|
|
38
41
|
const { script, insertBefore } = stubDocument();
|
|
39
|
-
loadAssistant(buildDialog(true));
|
|
42
|
+
loadAssistant(buildDialog({ _ignoreOneTrustAutoBlock: true }));
|
|
40
43
|
expect(script.setAttribute).toHaveBeenCalledWith("data-ot-ignore", "");
|
|
41
44
|
expect(insertBefore).toHaveBeenCalledWith(script, null);
|
|
42
45
|
});
|
|
43
46
|
it("leaves the injected script untouched by default", () => {
|
|
44
47
|
vi.useFakeTimers();
|
|
45
48
|
const { script, insertBefore } = stubDocument();
|
|
46
|
-
loadAssistant(buildDialog(false));
|
|
49
|
+
loadAssistant(buildDialog({ _ignoreOneTrustAutoBlock: false }));
|
|
47
50
|
expect(script.setAttribute).not.toHaveBeenCalled();
|
|
48
51
|
expect(insertBefore).toHaveBeenCalledWith(script, null);
|
|
49
52
|
});
|
|
50
53
|
});
|
|
54
|
+
describe("Dialog._loadAssistant add-to-cart toggle", () => {
|
|
55
|
+
it("flags the injected div when disableAddToCart is set", () => {
|
|
56
|
+
vi.useFakeTimers();
|
|
57
|
+
const { div } = stubDocument();
|
|
58
|
+
loadAssistant(buildDialog({ _disableAddToCart: true }));
|
|
59
|
+
expect(div.dataset.disableAddToCart).toBe("true");
|
|
60
|
+
});
|
|
61
|
+
it("leaves the div free of the flag by default", () => {
|
|
62
|
+
vi.useFakeTimers();
|
|
63
|
+
const { div } = stubDocument();
|
|
64
|
+
loadAssistant(buildDialog({ _disableAddToCart: false }));
|
|
65
|
+
expect(div.dataset.disableAddToCart).toBeUndefined();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -165,6 +165,48 @@ describe("search controller attribution", () => {
|
|
|
165
165
|
expect(trackSelectSearchResult).toHaveBeenCalledWith(expect.objectContaining({ items: [{ product_id: "p2", position: 2 }] }));
|
|
166
166
|
expect(navigate).not.toHaveBeenCalled();
|
|
167
167
|
});
|
|
168
|
+
it("returns true when the navigate adapter handles the transition", async () => {
|
|
169
|
+
const controller = createController();
|
|
170
|
+
search.mockResolvedValue(response());
|
|
171
|
+
controller.submit("shoes");
|
|
172
|
+
await settle();
|
|
173
|
+
expect(controller.selectResult(0)).toBe(true);
|
|
174
|
+
expect(navigate).toHaveBeenCalledTimes(1);
|
|
175
|
+
});
|
|
176
|
+
it("returns false when the selected hit has no URL", async () => {
|
|
177
|
+
const controller = createController();
|
|
178
|
+
search.mockResolvedValue(response());
|
|
179
|
+
controller.submit("shoes");
|
|
180
|
+
await settle();
|
|
181
|
+
expect(controller.selectResult(1)).toBe(false);
|
|
182
|
+
});
|
|
183
|
+
it("returns false before any response", () => {
|
|
184
|
+
expect(createController().selectResult(0)).toBe(false);
|
|
185
|
+
});
|
|
186
|
+
it("records attribution but skips the adapter when navigation is opted out", async () => {
|
|
187
|
+
const controller = createController();
|
|
188
|
+
search.mockResolvedValue(response());
|
|
189
|
+
controller.submit("shoes");
|
|
190
|
+
await settle();
|
|
191
|
+
expect(controller.selectResult(0, { navigate: false })).toBe(false);
|
|
192
|
+
expect(trackSelectSearchResult).toHaveBeenCalledTimes(1);
|
|
193
|
+
expect(navigate).not.toHaveBeenCalled();
|
|
194
|
+
});
|
|
195
|
+
it("returns false when no navigate adapter is configured", async () => {
|
|
196
|
+
const controller = createSearchController({
|
|
197
|
+
search,
|
|
198
|
+
analytics: {
|
|
199
|
+
surface: "search_page",
|
|
200
|
+
trackViewSearchResults,
|
|
201
|
+
trackSelectSearchResult,
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
search.mockResolvedValue(response());
|
|
205
|
+
controller.submit("shoes");
|
|
206
|
+
await settle();
|
|
207
|
+
expect(controller.selectResult(0)).toBe(false);
|
|
208
|
+
expect(navigate).not.toHaveBeenCalled();
|
|
209
|
+
});
|
|
168
210
|
it("disconnects the impression tracker on dispose", async () => {
|
|
169
211
|
const controller = createController();
|
|
170
212
|
search.mockResolvedValue(response());
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,9 @@ export * from "./Dialog";
|
|
|
2
2
|
export * from "./DialogSearchError";
|
|
3
3
|
export * from "./EventsHandler";
|
|
4
4
|
export * from "./searchController";
|
|
5
|
+
export * from "./services/search";
|
|
5
6
|
export * from "./types";
|
|
7
|
+
export { isRtlLanguageCode, resolveTextDirection, type TextDirection, } from "./utils/localization";
|
|
6
8
|
export * from "./utils/searchImpressions";
|
|
7
9
|
export * from "./windowAudit";
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,SAAS,CAAC;AACxB,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@ export * from "./Dialog";
|
|
|
2
2
|
export * from "./DialogSearchError";
|
|
3
3
|
export * from "./EventsHandler";
|
|
4
4
|
export * from "./searchController";
|
|
5
|
+
export * from "./services/search";
|
|
5
6
|
export * from "./types";
|
|
7
|
+
export { isRtlLanguageCode, resolveTextDirection, } from "./utils/localization";
|
|
6
8
|
export * from "./utils/searchImpressions";
|
|
7
9
|
export * from "./windowAudit";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../src/searchController.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../src/searchController.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EAGxB,MAAM,0BAA0B,CAAC;AAgBlC,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,SAAS,EACT,QAAQ,EACR,UAAgC,EAChC,WAAmC,GACpC,EAAE,uBAAuB,GAAG,gBAAgB,CAgL5C"}
|
package/dist/searchController.js
CHANGED
|
@@ -134,16 +134,19 @@ export function createSearchController({ search, analytics, navigate, debounceMs
|
|
|
134
134
|
}
|
|
135
135
|
controllerAnalytics.observeResult(element, state.response, index);
|
|
136
136
|
},
|
|
137
|
-
selectResult(index) {
|
|
137
|
+
selectResult(index, options) {
|
|
138
138
|
const response = state.response;
|
|
139
139
|
if (response === undefined) {
|
|
140
|
-
return;
|
|
140
|
+
return false;
|
|
141
141
|
}
|
|
142
142
|
controllerAnalytics.select(response, index);
|
|
143
143
|
const url = response.hits[index].product.url;
|
|
144
|
-
|
|
144
|
+
const runAdapter = options?.navigate ?? true;
|
|
145
|
+
if (runAdapter && navigate !== undefined && url !== undefined) {
|
|
145
146
|
navigate(url, response.hits[index]);
|
|
147
|
+
return true;
|
|
146
148
|
}
|
|
149
|
+
return false;
|
|
147
150
|
},
|
|
148
151
|
subscribe(listener) {
|
|
149
152
|
listeners.add(listener);
|
|
@@ -30,5 +30,15 @@ export interface DialogConstructor {
|
|
|
30
30
|
* call, hence opt-in. No effect outside OneTrust auto-blocking setups.
|
|
31
31
|
*/
|
|
32
32
|
ignoreOneTrustAutoBlock?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Disables Dialog add-to-cart for this widget instance/session. Defaults to
|
|
35
|
+
* `false`. When `true`, the SDK flags the injected assistant so it hides the
|
|
36
|
+
* add-to-cart CTA on product recommendation and conversational product cards,
|
|
37
|
+
* and `addToCart()` becomes a no-op that emits no tracking event — nothing is
|
|
38
|
+
* added to the cart even if a stale UI still calls it. Meant for sessions
|
|
39
|
+
* where the merchant hides purchasing actions (e.g. logged-in B2B shoppers).
|
|
40
|
+
* Product links and recommendation browsing are unaffected.
|
|
41
|
+
*/
|
|
42
|
+
disableAddToCart?: boolean;
|
|
33
43
|
}
|
|
34
44
|
//# sourceMappingURL=constructor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constructor.d.ts","sourceRoot":"","sources":["../../src/types/constructor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,EAAE,CACV,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"constructor.d.ts","sourceRoot":"","sources":["../../src/types/constructor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,EAAE,CACV,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B"}
|
|
@@ -67,10 +67,23 @@ export interface SearchController {
|
|
|
67
67
|
observeResult(element: Element, index: number): void;
|
|
68
68
|
/**
|
|
69
69
|
* Record selection attribution for `state.response.hits[index]` (forced
|
|
70
|
-
* impression + select event), then
|
|
71
|
-
* adapter. Call it on click AND
|
|
70
|
+
* impression + select event), then — unless `options.navigate` is `false` —
|
|
71
|
+
* hand navigation to the `navigate` adapter. Call it on click AND
|
|
72
|
+
* middle-click/cmd+click.
|
|
73
|
+
*
|
|
74
|
+
* Pass `{ navigate: false }` for gestures the browser should handle natively
|
|
75
|
+
* (middle-click, or cmd/ctrl/shift/alt+click → new tab/window): attribution
|
|
76
|
+
* is still recorded, but the in-app adapter — which cannot open a new tab —
|
|
77
|
+
* is skipped so the native `<a href>` navigation runs.
|
|
78
|
+
*
|
|
79
|
+
* Returns `true` when the adapter handled the transition, so a rendering
|
|
80
|
+
* layer wrapping results in `<a href>` can `preventDefault()` and avoid a
|
|
81
|
+
* second (native) navigation. Returns `false` otherwise (adapter skipped, no
|
|
82
|
+
* adapter, or the hit has no URL) — let the native navigation proceed.
|
|
72
83
|
*/
|
|
73
|
-
selectResult(index: number
|
|
84
|
+
selectResult(index: number, options?: {
|
|
85
|
+
navigate?: boolean;
|
|
86
|
+
}): boolean;
|
|
74
87
|
/** Register a state listener; returns its unsubscribe function. */
|
|
75
88
|
subscribe(listener: (state: SearchControllerState) => void): () => void;
|
|
76
89
|
getState(): SearchControllerState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../../src/types/searchController.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,aAAa,EACb,aAAa,EACb,cAAc,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,YAAY;;;;IAIvB,yGAAyG;;;CAGjG,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE5E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,aAAa,CAAC;IACvB,sBAAsB,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAClE,uBAAuB,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACrE;AAED,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,yBAAyB,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,2EAA2E;IAC3E,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrD
|
|
1
|
+
{"version":3,"file":"searchController.d.ts","sourceRoot":"","sources":["../../src/types/searchController.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,aAAa,EACb,aAAa,EACb,cAAc,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,YAAY;;;;IAIvB,yGAAyG;;;CAGjG,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE5E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,KACpB,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,aAAa,CAAC;IACvB,sBAAsB,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAClE,uBAAuB,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACrE;AAED,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,yBAAyB,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,2EAA2E;IAC3E,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrD;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC;IACvE,mEAAmE;IACnE,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACxE,QAAQ,IAAI,qBAAqB,CAAC;IAClC,kEAAkE;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB"}
|
|
@@ -6,6 +6,9 @@ export interface DetailedLocaleInfo {
|
|
|
6
6
|
locale: string;
|
|
7
7
|
}
|
|
8
8
|
export declare const isValidCountryCode: (countryCode: string | undefined) => countryCode is string;
|
|
9
|
+
export type TextDirection = "ltr" | "rtl";
|
|
10
|
+
export declare const isRtlLanguageCode: (code?: string) => boolean;
|
|
11
|
+
export declare const resolveTextDirection: (code?: string) => TextDirection;
|
|
9
12
|
/**
|
|
10
13
|
* Resolves the detailed locale information used by the assistant.
|
|
11
14
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localization.d.ts","sourceRoot":"","sources":["../../src/utils/localization.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,GAC7B,aAAa,MAAM,GAAG,SAAS,KAC9B,WAAW,IAAI,MAC8C,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,MAAM,EACd,sBAAsB,MAAM,KAC3B,kBAAkB,GAAG,IAoCvB,CAAC"}
|
|
1
|
+
{"version":3,"file":"localization.d.ts","sourceRoot":"","sources":["../../src/utils/localization.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,GAC7B,aAAa,MAAM,GAAG,SAAS,KAC9B,WAAW,IAAI,MAC8C,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,CAAC;AAQ1C,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,OAEa,CAAC;AAEhE,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,aACZ,CAAC;AAE1C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,MAAM,EACd,sBAAsB,MAAM,KAC3B,kBAAkB,GAAG,IAoCvB,CAAC"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export const isValidCountryCode = (countryCode) => countryCode !== undefined && /^[A-Za-z]{2}$/.test(countryCode);
|
|
2
|
+
// ISO-639 codes whose scripts read right-to-left. `iw` is the legacy code for
|
|
3
|
+
// Hebrew that some storefronts still emit.
|
|
4
|
+
const RTL_LANGUAGE_CODES = new Set(["ar", "he", "iw", "fa", "ur"]);
|
|
5
|
+
// Accepts a bare ISO-639 code ("ar") or a full BCP-47 locale ("ar-SA"): only
|
|
6
|
+
// the leading language subtag decides direction.
|
|
7
|
+
export const isRtlLanguageCode = (code) => code !== undefined &&
|
|
8
|
+
RTL_LANGUAGE_CODES.has(code.trim().toLowerCase().slice(0, 2));
|
|
9
|
+
export const resolveTextDirection = (code) => isRtlLanguageCode(code) ? "rtl" : "ltr";
|
|
2
10
|
/**
|
|
3
11
|
* Resolves the detailed locale information used by the assistant.
|
|
4
12
|
*
|