@searchspring/snap-preact 0.76.1 → 0.77.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.
@@ -57,6 +57,7 @@ export declare class RecommendationInstantiator {
57
57
  plugin(func: (cntrlr: AbstractController, ...args: any) => Promise<void>, ...args: unknown[]): void;
58
58
  on(event: string, ...func: Middleware<unknown>[]): void;
59
59
  use(attachments: Attachments): void;
60
+ cleanupStaleControllers(): void;
60
61
  }
61
62
  type DefinedProps = {
62
63
  [key: string]: any;
@@ -1 +1 @@
1
- {"version":3,"file":"RecommendationInstantiator.d.ts","sourceRoot":"","sources":["../../../src/Instantiators/RecommendationInstantiator.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RecommendationInstantiator.d.ts","sourceRoot":"","sources":["../../../src/Instantiators/RecommendationInstantiator.tsx"],"names":[],"mappings":"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"}
@@ -10,29 +10,6 @@ var __assign = (this && this.__assign) || function () {
10
10
  };
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- var desc = Object.getOwnPropertyDescriptor(m, k);
16
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
- desc = { enumerable: true, get: function() { return m[k]; } };
18
- }
19
- Object.defineProperty(o, k2, desc);
20
- }) : (function(o, m, k, k2) {
21
- if (k2 === undefined) k2 = k;
22
- o[k2] = m[k];
23
- }));
24
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
- Object.defineProperty(o, "default", { enumerable: true, value: v });
26
- }) : function(o, v) {
27
- o["default"] = v;
28
- });
29
- var __importStar = (this && this.__importStar) || function (mod) {
30
- if (mod && mod.__esModule) return mod;
31
- var result = {};
32
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
33
- __setModuleDefault(result, mod);
34
- return result;
35
- };
36
13
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
14
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
15
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -90,6 +67,7 @@ var snap_toolbox_1 = require("@searchspring/snap-toolbox");
90
67
  var snap_client_1 = require("@searchspring/snap-client");
91
68
  var snap_logger_1 = require("@searchspring/snap-logger");
92
69
  var snap_tracker_1 = require("@searchspring/snap-tracker");
70
+ var create_1 = require("../create");
93
71
  var DEFAULT_BRANCH = 'production';
94
72
  var RecommendationInstantiator = /** @class */ (function () {
95
73
  function RecommendationInstantiator(config, services, context) {
@@ -127,20 +105,13 @@ var RecommendationInstantiator = /** @class */ (function () {
127
105
  this.tracker = (services === null || services === void 0 ? void 0 : services.tracker) || new snap_tracker_1.Tracker(this.config.client.globals);
128
106
  this.logger = (services === null || services === void 0 ? void 0 : services.logger) || new snap_logger_1.Logger({ prefix: 'RecommendationInstantiator ', mode: this.mode });
129
107
  var profileCount = {};
108
+ // script block targeter for "grouped" and "legacy" blocks
130
109
  this.targeter = new snap_toolbox_1.DomTargeter([
131
110
  {
132
111
  selector: "".concat(this.config.selector || 'script[type="searchspring/recommend"], script[type="searchspring/personalized-recommendations"]', ", script[type=\"searchspring/recommend\"][profile=\"email\"]"),
133
112
  autoRetarget: true,
134
113
  clickRetarget: true,
135
- inject: {
136
- action: 'before',
137
- element: function (target, origElement) {
138
- var profile = origElement.getAttribute('profile') || '';
139
- var recsContainer = document.createElement('div');
140
- recsContainer.setAttribute('searchspring-recommend', profile);
141
- return recsContainer;
142
- },
143
- },
114
+ emptyTarget: false,
144
115
  },
145
116
  {
146
117
  selector: 'script[type="searchspring/recommendations"]',
@@ -148,11 +119,13 @@ var RecommendationInstantiator = /** @class */ (function () {
148
119
  clickRetarget: true,
149
120
  emptyTarget: false,
150
121
  },
151
- ], function (target, elem, originalElem) { return __awaiter(_this, void 0, void 0, function () {
152
- var elemContext, scriptContextProfiles, scriptContextGlobals_1, requestGlobals_1, targetsArr_1, profile, products, product, seed, filters, blockedItems, options, shopper, shopperId, combinedProducts, shopperIdentifier, profileRequestGlobals;
122
+ ], function (target, elem, _originalElem, targeter) { return __awaiter(_this, void 0, void 0, function () {
123
+ var scriptElement, elemContext, scriptContextProfiles, scriptContextGlobals_1, requestGlobals_1, profile, products, product, seed, filters, blockedItems, options, shopper, shopperId, combinedProducts, shopperIdentifier, profileRequestGlobals_1, profileAttr, recsContainer, legacyContext_1;
153
124
  var _this = this;
154
125
  var _a;
155
126
  return __generator(this, function (_b) {
127
+ this.targeter = this.targeter || targeter;
128
+ scriptElement = elem;
156
129
  elemContext = (0, snap_toolbox_1.getContext)([
157
130
  'shopperId',
158
131
  'shopper',
@@ -167,7 +140,7 @@ var RecommendationInstantiator = /** @class */ (function () {
167
140
  'custom',
168
141
  'profiles',
169
142
  'globals',
170
- ], (originalElem || elem));
143
+ ], scriptElement);
171
144
  if (elemContext.profiles && elemContext.profiles.length) {
172
145
  scriptContextProfiles = elemContext.profiles;
173
146
  scriptContextGlobals_1 = elemContext.globals;
@@ -177,42 +150,58 @@ var RecommendationInstantiator = /** @class */ (function () {
177
150
  cart: (scriptContextGlobals_1 === null || scriptContextGlobals_1 === void 0 ? void 0 : scriptContextGlobals_1.cart) && getArrayFunc(scriptContextGlobals_1.cart),
178
151
  products: scriptContextGlobals_1 === null || scriptContextGlobals_1 === void 0 ? void 0 : scriptContextGlobals_1.products,
179
152
  shopper: (_a = scriptContextGlobals_1 === null || scriptContextGlobals_1 === void 0 ? void 0 : scriptContextGlobals_1.shopper) === null || _a === void 0 ? void 0 : _a.id,
180
- batchId: Math.random(),
153
+ batchId: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER),
181
154
  }));
182
- targetsArr_1 = [];
183
- // build out the targets array for each profile
155
+ // create a per-profile DomTargeter for each profile so each controller
156
+ // gets its own targeter tracking its specific element
184
157
  scriptContextProfiles.forEach(function (profile) {
185
158
  if (profile.selector) {
186
- var targetObj = {
159
+ var profileTarget = {
187
160
  selector: profile.selector,
188
161
  autoRetarget: true,
189
- clickRetarget: true,
190
162
  profile: profile,
191
163
  };
192
- targetsArr_1.push(targetObj);
164
+ // track the controller for this profile so multiple matched elements share it
165
+ var profileControllerPromise_1;
166
+ new snap_toolbox_1.DomTargeter([profileTarget], function (target, targetElem, _originalElem, targeter) { return __awaiter(_this, void 0, void 0, function () {
167
+ var profileRequestGlobals, profileContext, controller;
168
+ var _a, _b, _c;
169
+ return __generator(this, function (_d) {
170
+ switch (_d.label) {
171
+ case 0:
172
+ // skip retarget if the source script element was removed from the DOM (SPA navigation)
173
+ if (!scriptElement.isConnected) {
174
+ return [2 /*return*/];
175
+ }
176
+ if (!(((_a = target.profile) === null || _a === void 0 ? void 0 : _a.profile) || ((_b = target.profile) === null || _b === void 0 ? void 0 : _b.tag))) return [3 /*break*/, 3];
177
+ profileRequestGlobals = __assign(__assign({}, requestGlobals_1), { profile: (_c = target.profile) === null || _c === void 0 ? void 0 : _c.options, tag: target.profile.tag || target.profile.profile });
178
+ profileContext = (0, deepmerge_1.default)(this.context, defined({ globals: scriptContextGlobals_1, profile: target.profile }));
179
+ if (elemContext.custom) {
180
+ profileContext.custom = elemContext.custom;
181
+ }
182
+ if (!!profileControllerPromise_1) return [3 /*break*/, 1];
183
+ // first element match — create the controller
184
+ profileControllerPromise_1 = readyTheController(this, targetElem, profileContext, profileCount, scriptElement, profileRequestGlobals, targeter);
185
+ return [3 /*break*/, 3];
186
+ case 1: return [4 /*yield*/, profileControllerPromise_1];
187
+ case 2:
188
+ controller = _d.sent();
189
+ if (controller && targetElem) {
190
+ renderController(this, controller, targetElem, scriptElement);
191
+ }
192
+ _d.label = 3;
193
+ case 3: return [2 /*return*/];
194
+ }
195
+ });
196
+ }); });
193
197
  }
194
198
  });
195
- new snap_toolbox_1.DomTargeter(targetsArr_1, function (target, elem, originalElem) { return __awaiter(_this, void 0, void 0, function () {
196
- var profileRequestGlobals, profileContext;
197
- var _a, _b, _c;
198
- return __generator(this, function (_d) {
199
- if (((_a = target.profile) === null || _a === void 0 ? void 0 : _a.profile) || ((_b = target.profile) === null || _b === void 0 ? void 0 : _b.tag)) {
200
- profileRequestGlobals = __assign(__assign({}, requestGlobals_1), { profile: (_c = target.profile) === null || _c === void 0 ? void 0 : _c.options, tag: target.profile.tag || target.profile.profile });
201
- profileContext = (0, deepmerge_1.default)(this.context, defined({ globals: scriptContextGlobals_1, profile: target.profile }));
202
- if (elemContext.custom) {
203
- profileContext.custom = elemContext.custom;
204
- }
205
- readyTheController(this, elem, profileContext, profileCount, originalElem, profileRequestGlobals);
206
- }
207
- return [2 /*return*/];
208
- });
209
- }); });
210
199
  }
211
200
  else {
212
201
  profile = elemContext.profile, products = elemContext.products, product = elemContext.product, seed = elemContext.seed, filters = elemContext.filters, blockedItems = elemContext.blockedItems, options = elemContext.options, shopper = elemContext.shopper, shopperId = elemContext.shopperId;
213
202
  combinedProducts = [].concat(products || product || seed || []);
214
203
  shopperIdentifier = [shopper, shopper === null || shopper === void 0 ? void 0 : shopper.id, shopperId, shopperId === null || shopperId === void 0 ? void 0 : shopperId.id].filter(function (val) { return val && typeof val === 'string'; }).pop();
215
- profileRequestGlobals = __assign({ tag: profile }, defined({
204
+ profileRequestGlobals_1 = __assign({ tag: profile }, defined({
216
205
  products: combinedProducts.length ? combinedProducts : undefined,
217
206
  cart: elemContext.cart && getArrayFunc(elemContext.cart),
218
207
  shopper: shopperIdentifier,
@@ -220,7 +209,22 @@ var RecommendationInstantiator = /** @class */ (function () {
220
209
  blockedItems: blockedItems,
221
210
  profile: options,
222
211
  }));
223
- readyTheController(this, elem, (0, deepmerge_1.default)(this.context, elemContext), profileCount, originalElem, profileRequestGlobals);
212
+ profileAttr = scriptElement.getAttribute('profile') || '';
213
+ recsContainer = document.createElement('div');
214
+ recsContainer.setAttribute('searchspring-recommend', profileAttr);
215
+ scriptElement.before(recsContainer);
216
+ legacyContext_1 = (0, deepmerge_1.default)(this.context, elemContext);
217
+ // create a per-element DomTargeter for the injected div (mirrors grouped block pattern)
218
+ new snap_toolbox_1.DomTargeter([{ selector: "[searchspring-recommend=\"".concat(profileAttr, "\"]"), name: "legacy_".concat(profile, "_").concat(profileCount[profile || ''] || 0) }], function (_target, targetElem, _originalElem, targeter) { return __awaiter(_this, void 0, void 0, function () {
219
+ return __generator(this, function (_a) {
220
+ // skip retarget if the source script element was removed from the DOM (SPA navigation)
221
+ if (!scriptElement.isConnected) {
222
+ return [2 /*return*/];
223
+ }
224
+ readyTheController(this, targetElem, legacyContext_1, profileCount, scriptElement, profileRequestGlobals_1, targeter);
225
+ return [2 /*return*/];
226
+ });
227
+ }); });
224
228
  }
225
229
  return [2 /*return*/];
226
230
  });
@@ -243,59 +247,57 @@ var RecommendationInstantiator = /** @class */ (function () {
243
247
  RecommendationInstantiator.prototype.use = function (attachments) {
244
248
  this.uses.push(attachments);
245
249
  };
250
+ // cleanup to ensure we release controllers no longer rendering in the DOM (memory leak prevention for SPA's)
251
+ RecommendationInstantiator.prototype.cleanupStaleControllers = function () {
252
+ var _this = this;
253
+ Object.keys(this.controller).forEach(function (id) {
254
+ var _a;
255
+ var controller = _this.controller[id];
256
+ var targeters = Object.values(controller.targeters);
257
+ var hasConnectedTarget = targeters.some(function (targeter) { return targeter.getTargetedElems().some(function (elem) { return elem.isConnected; }); });
258
+ if (!hasConnectedTarget) {
259
+ controller.targeters = {};
260
+ delete _this.controller[id];
261
+ if ((_a = window.searchspring) === null || _a === void 0 ? void 0 : _a.controller) {
262
+ delete window.searchspring.controller[id];
263
+ }
264
+ }
265
+ });
266
+ };
246
267
  return RecommendationInstantiator;
247
268
  }());
248
269
  exports.RecommendationInstantiator = RecommendationInstantiator;
249
- function readyTheController(instance, injectedElem, context, profileCount, elem, controllerGlobals) {
250
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
270
+ function readyTheController(instance, targetElem, context, profileCount, scriptElem, controllerGlobals, targeter) {
271
+ var _a, _b, _c, _d, _e, _f, _g, _h;
251
272
  return __awaiter(this, void 0, void 0, function () {
252
- var profile, batchId, cart, tag, batched, globals, controllerConfig, controller, createRecommendationController, profileVars, component, RecommendationsComponent, _k;
253
- return __generator(this, function (_l) {
254
- switch (_l.label) {
273
+ var profile, batchId, cart, tag, batched, globals, controllerConfigBase, controllerConfig, controller, profileVars;
274
+ return __generator(this, function (_j) {
275
+ switch (_j.label) {
255
276
  case 0:
256
277
  profile = controllerGlobals.profile, batchId = controllerGlobals.batchId, cart = controllerGlobals.cart, tag = controllerGlobals.tag;
257
278
  batched = (_b = (_a = profile === null || profile === void 0 ? void 0 : profile.batched) !== null && _a !== void 0 ? _a : controllerGlobals.batched) !== null && _b !== void 0 ? _b : true;
258
279
  if (!tag) {
259
280
  // FEEDBACK: change message depending on script integration type (profile vs. legacy)
260
- instance.logger.warn("'tag' is missing from <script> tag, skipping this profile", elem);
281
+ instance.logger.warn("'tag' is missing from <script> tag, skipping this profile", scriptElem);
261
282
  return [2 /*return*/];
262
283
  }
263
284
  if (Array.isArray(cart)) {
264
285
  instance.tracker.cookies.cart.set(cart);
265
286
  }
266
- profileCount[tag] = profileCount[tag] + 1 || 1;
267
287
  globals = deepmerge_1.default.all([
268
288
  ((_c = instance.config.client) === null || _c === void 0 ? void 0 : _c.globals) || {},
269
289
  ((_d = instance.config.config) === null || _d === void 0 ? void 0 : _d.globals) || {},
270
290
  controllerGlobals,
271
291
  ]);
272
- controllerConfig = __assign(__assign({ id: "recommend_".concat(tag, "_").concat(profileCount[tag] - 1), tag: tag, batched: batched !== null && batched !== void 0 ? batched : true, realtime: Boolean((_f = (_e = context.options) === null || _e === void 0 ? void 0 : _e.realtime) !== null && _f !== void 0 ? _f : (_h = (_g = context.profile) === null || _g === void 0 ? void 0 : _g.options) === null || _h === void 0 ? void 0 : _h.realtime), batchId: batchId }, instance.config.config), { globals: globals });
292
+ controllerConfigBase = __assign(__assign({ tag: tag, batched: batched !== null && batched !== void 0 ? batched : true, realtime: Boolean((_f = (_e = context.options) === null || _e === void 0 ? void 0 : _e.realtime) !== null && _f !== void 0 ? _f : (_h = (_g = context.profile) === null || _g === void 0 ? void 0 : _g.options) === null || _h === void 0 ? void 0 : _h.realtime), batchId: batchId }, instance.config.config), { globals: globals });
273
293
  if (profile === null || profile === void 0 ? void 0 : profile.branch) {
274
- controllerConfig.branch = profile === null || profile === void 0 ? void 0 : profile.branch;
294
+ controllerConfigBase.branch = profile === null || profile === void 0 ? void 0 : profile.branch;
275
295
  }
276
- controller = Object.keys(instance.controller)
277
- .map(function (id) { return instance.controller[id]; })
278
- .filter(function (controller) {
279
- return (JSON.stringify({
280
- batched: controller.config.batched,
281
- branch: controller.config.branch,
282
- globals: controller.config.globals,
283
- tag: controller.config.tag,
284
- realtime: controller.config.realtime,
285
- }) ==
286
- JSON.stringify({
287
- batched: controllerConfig.batched,
288
- branch: controllerConfig.branch,
289
- globals: controllerConfig.globals,
290
- tag: controllerConfig.tag,
291
- realtime: controllerConfig.realtime,
292
- }));
293
- })[0];
294
- if (!!controller) return [3 /*break*/, 2];
295
- return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require('../create/createRecommendationController')); })];
296
- case 1:
297
- createRecommendationController = (_l.sent()).default;
298
- controller = createRecommendationController({
296
+ // clean up controllers whose rendered elements are no longer in the DOM (SPA navigation)
297
+ instance.cleanupStaleControllers();
298
+ profileCount[tag] = profileCount[tag] + 1 || 1;
299
+ controllerConfig = __assign({ id: "recommend_".concat(tag, "_").concat(profileCount[tag] - 1) }, controllerConfigBase);
300
+ controller = (0, create_1.createRecommendationController)({
299
301
  url: instance.config.url,
300
302
  controller: controllerConfig,
301
303
  context: context,
@@ -304,53 +306,70 @@ function readyTheController(instance, injectedElem, context, profileCount, elem,
304
306
  instance.uses.forEach(function (attachements) { return controller.use(attachements); });
305
307
  instance.plugins.forEach(function (plugin) { return controller.plugin.apply(controller, __spreadArray([plugin.func], plugin.args, false)); });
306
308
  instance.middleware.forEach(function (middleware) { return controller.on.apply(controller, __spreadArray([middleware.event], middleware.func, false)); });
307
- _l.label = 2;
308
- case 2:
309
- if (!!controller.store.loading) return [3 /*break*/, 4];
310
- return [4 /*yield*/, controller.search()];
311
- case 3:
312
- _l.sent();
313
- _l.label = 4;
314
- case 4:
315
- controller.addTargeter(instance.targeter);
309
+ // add controller to instantiator and global namespace
316
310
  instance.controller[controller.config.id] = controller;
317
311
  window.searchspring.controller = window.searchspring.controller || {};
318
312
  window.searchspring.controller[controller.config.id] = controller;
313
+ // register targeter on the controller for element tracking
314
+ controller.addTargeter(targeter);
315
+ if (!!controller.store.loading) return [3 /*break*/, 2];
316
+ return [4 /*yield*/, controller.search()];
317
+ case 1:
318
+ _j.sent();
319
+ _j.label = 2;
320
+ case 2:
319
321
  profileVars = controller.store.profile.display.templateParameters;
320
- component = (_j = controller.store.profile.display.template) === null || _j === void 0 ? void 0 : _j.component;
321
322
  if (controller.store.error) {
322
323
  //something went wrong
323
324
  //err was already logged - nothing to do.
324
325
  return [2 /*return*/];
325
326
  }
326
327
  if (!controller.store.profile.display.template) {
327
- instance.logger.error("profile '".concat(tag, "' found on the following element is missing a template!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
328
+ instance.logger.error("profile '".concat(tag, "' found on the following element is missing a template!\n").concat(scriptElem === null || scriptElem === void 0 ? void 0 : scriptElem.outerHTML));
328
329
  return [2 /*return*/];
329
330
  }
330
331
  if (!profileVars) {
331
- instance.logger.error("profile '".concat(tag, "' found on the following element is missing templateParameters!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
332
+ instance.logger.error("profile '".concat(tag, "' found on the following element is missing templateParameters!\n").concat(scriptElem === null || scriptElem === void 0 ? void 0 : scriptElem.outerHTML));
332
333
  return [2 /*return*/];
333
334
  }
335
+ if (!targetElem) return [3 /*break*/, 4];
336
+ return [4 /*yield*/, renderController(instance, controller, targetElem, scriptElem)];
337
+ case 3:
338
+ _j.sent();
339
+ _j.label = 4;
340
+ case 4: return [2 /*return*/, controller];
341
+ }
342
+ });
343
+ });
344
+ }
345
+ function renderController(instance, controller, targetElem, scriptElem) {
346
+ var _a;
347
+ return __awaiter(this, void 0, void 0, function () {
348
+ var tag, component, RecommendationsComponent, _b;
349
+ return __generator(this, function (_c) {
350
+ switch (_c.label) {
351
+ case 0:
352
+ tag = controller.config.tag;
353
+ component = (_a = controller.store.profile.display.template) === null || _a === void 0 ? void 0 : _a.component;
334
354
  if (!component) {
335
- instance.logger.error("profile '".concat(tag, "' found on the following element is missing a component!\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
355
+ instance.logger.error("profile '".concat(tag, "' found on the following element is missing a component!\n").concat(scriptElem === null || scriptElem === void 0 ? void 0 : scriptElem.outerHTML));
336
356
  return [2 /*return*/];
337
357
  }
338
- _k = instance.config.components[component];
339
- if (!_k) return [3 /*break*/, 6];
358
+ _b = instance.config.components[component];
359
+ if (!_b) return [3 /*break*/, 2];
340
360
  return [4 /*yield*/, instance.config.components[component]()];
341
- case 5:
342
- _k = (_l.sent());
343
- _l.label = 6;
344
- case 6:
345
- RecommendationsComponent = _k;
361
+ case 1:
362
+ _b = (_c.sent());
363
+ _c.label = 2;
364
+ case 2:
365
+ RecommendationsComponent = _b;
346
366
  if (!RecommendationsComponent) {
347
- instance.logger.error("profile '".concat(tag, "' found on the following element is expecting component mapping for '").concat(component, "' - verify instantiator config.\n").concat(elem === null || elem === void 0 ? void 0 : elem.outerHTML));
367
+ instance.logger.error("profile '".concat(tag, "' found on the following element is expecting component mapping for '").concat(component, "' - verify instantiator config.\n").concat(scriptElem === null || scriptElem === void 0 ? void 0 : scriptElem.outerHTML));
348
368
  return [2 /*return*/];
349
369
  }
350
370
  setTimeout(function () {
351
- if (injectedElem) {
352
- (0, preact_1.render)((0, jsx_runtime_1.jsx)(RecommendationsComponent, { controller: controller }), injectedElem);
353
- }
371
+ targetElem.setAttribute('ss-controller-id', controller.config.id);
372
+ (0, preact_1.render)((0, jsx_runtime_1.jsx)(RecommendationsComponent, { controller: controller }), targetElem);
354
373
  });
355
374
  return [2 /*return*/];
356
375
  }
@@ -9,7 +9,7 @@ import type { Controllers, AbstractController, SearchControllerConfig, Autocompl
9
9
  import type { TrackerConfig, TrackerGlobals } from '@searchspring/snap-tracker';
10
10
  import type { Target, OnTarget } from '@searchspring/snap-toolbox';
11
11
  import type { UrlTranslatorConfig } from '@searchspring/snap-url-manager';
12
- import { RecommendationInstantiator, RecommendationInstantiatorConfig } from './Instantiators/RecommendationInstantiator';
12
+ import type { RecommendationInstantiator, RecommendationInstantiatorConfig } from './Instantiators/RecommendationInstantiator';
13
13
  import type { SnapControllerServices, InitialUrlConfig } from './types';
14
14
  export declare const BRANCH_COOKIE = "ssBranch";
15
15
  export declare const BRANCH_PARAM = "searchspring-preview";
@@ -1 +1 @@
1
- {"version":3,"file":"Snap.d.ts","sourceRoot":"","sources":["../../src/Snap.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,OAAO,EAAgE,MAAM,4BAA4B,CAAC;AACnH,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAIhE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EACX,WAAW,EACX,kBAAkB,EAElB,sBAAsB,EACtB,4BAA4B,EAC5B,sBAAsB,EACtB,8BAA8B,EAC9B,iBAAiB,EACjB,gBAAgB,EAChB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAmB,MAAM,4BAA4B,CAAC;AACjG,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAI1E,OAAO,EAAE,0BAA0B,EAAE,gCAAgC,EAAE,MAAM,4CAA4C,CAAC;AAC1H,OAAO,KAAK,EAAE,sBAAsB,EAAwB,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAM9F,eAAO,MAAM,aAAa,aAAa,CAAC;AACxC,eAAO,MAAM,YAAY,yBAAyB,CAAC;AACnD,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAE5D,KAAK,cAAc,GAAG,MAAM,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACpC,KAAK,CAAC,EAAE;QACP,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC;KACxB,CAAC;IACF,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,KAAK,YAAY,GAAG;IACnB,yBAAyB,CAAC,EAAE;QAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACF,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,OAAO,OAAO,GAAG,OAAO,CAAC;IACtC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,MAAM,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;QACjC,MAAM,CAAC,EAAE,YAAY,CAAC;KACtB,CAAC;IACF,OAAO,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,cAAc,CAAC;QACzB,MAAM,CAAC,EAAE,aAAa,CAAC;KACvB,CAAC;IACF,aAAa,CAAC,EAAE;QACf,cAAc,CAAC,EAAE,gCAAgC,CAAC;KAClD,CAAC;IACF,WAAW,CAAC,EAAE;QACb,MAAM,CAAC,EAAE;YACR,MAAM,EAAE,sBAAsB,CAAC;YAC/B,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;YAC7B,QAAQ,CAAC,EAAE,sBAAsB,CAAC;YAClC,GAAG,CAAC,EAAE,mBAAmB,GAAG;gBAC3B,OAAO,CAAC,EAAE,gBAAgB,CAAC;aAC3B,CAAC;YACF,OAAO,CAAC,EAAE,gBAAgB,CAAC;SAC3B,EAAE,CAAC;QACJ,YAAY,CAAC,EAAE;YACd,MAAM,EAAE,4BAA4B,CAAC;YACrC,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;YAC7B,QAAQ,CAAC,EAAE,sBAAsB,CAAC;YAClC,GAAG,CAAC,EAAE,mBAAmB,CAAC;YAC1B,OAAO,CAAC,EAAE,gBAAgB,CAAC;SAC3B,EAAE,CAAC;QACJ,MAAM,CAAC,EAAE;YACR,MAAM,EAAE,sBAAsB,CAAC;YAC/B,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;YAC7B,QAAQ,CAAC,EAAE,sBAAsB,CAAC;YAClC,GAAG,CAAC,EAAE,mBAAmB,CAAC;YAC1B,OAAO,CAAC,EAAE,gBAAgB,CAAC;SAC3B,EAAE,CAAC;QACJ,cAAc,CAAC,EAAE;YAChB,MAAM,EAAE,8BAA8B,CAAC;YACvC,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;YAC7B,QAAQ,CAAC,EAAE,sBAAsB,CAAC;YAClC,GAAG,CAAC,EAAE,mBAAmB,CAAC;YAC1B,OAAO,CAAC,EAAE,gBAAgB,CAAC;SAC3B,EAAE,CAAC;KACJ,CAAC;CACF,CAAC;AAEF,KAAK,YAAY,GAAG;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAoCF,qBAAa,IAAI;IAChB,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,qBAAqB,CAEtB;IACP,OAAO,CAAC,mBAAmB,CAEpB;IAEA,MAAM,EAAG,MAAM,CAAC;IAChB,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAG,OAAO,CAAC;IAClB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,WAAW,EAAE;QACnB,CAAC,kBAAkB,EAAE,MAAM,GAAG,WAAW,CAAC;KAC1C,CAAM;IAEA,YAAY,EAAE,YAAY,CAAC;IAE3B,eAAe,OAAQ,MAAM,KAAG,QAAQ,0BAA0B,CAAC,CAExE;IAEK,aAAa,OAAQ,MAAM,KAAG,QAAQ,WAAW,CAAC,CAEvD;IAEK,cAAc,qBAAsB,MAAM,EAAE,KAAG,QAAQ,WAAW,EAAE,CAAC,CAI1E;IAGK,gBAAgB,SAChB,MAAM,sBAAsB,UAC1B,iBAAiB,aACd,sBAAsB,cACrB,mBAAmB,YACrB,gBAAgB,uBACN,WAAW,GAAG,YAAY,WAAW,CAAC,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,kBACjF,QAAQ,WAAW,CAAC,CAarB;IAGF,OAAO,CAAC,iBAAiB,CAsDvB;IAEK,QAAQ;uBACC,UAAU,KAAG,IAAI;MA4B/B;gBAEU,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,YAAY;CAwnBvD"}
1
+ {"version":3,"file":"Snap.d.ts","sourceRoot":"","sources":["../../src/Snap.tsx"],"names":[],"mappings":"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"}
@@ -57,6 +57,7 @@ export declare class RecommendationInstantiator {
57
57
  plugin(func: (cntrlr: AbstractController, ...args: any) => Promise<void>, ...args: unknown[]): void;
58
58
  on(event: string, ...func: Middleware<unknown>[]): void;
59
59
  use(attachments: Attachments): void;
60
+ cleanupStaleControllers(): void;
60
61
  }
61
62
  type DefinedProps = {
62
63
  [key: string]: any;
@@ -1 +1 @@
1
- {"version":3,"file":"RecommendationInstantiator.d.ts","sourceRoot":"","sources":["../../../src/Instantiators/RecommendationInstantiator.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RecommendationInstantiator.d.ts","sourceRoot":"","sources":["../../../src/Instantiators/RecommendationInstantiator.tsx"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import { AppMode, DomTargeter, getContext } from '@searchspring/snap-toolbox';
5
5
  import { Client } from '@searchspring/snap-client';
6
6
  import { Logger } from '@searchspring/snap-logger';
7
7
  import { Tracker } from '@searchspring/snap-tracker';
8
+ import { createRecommendationController } from '../create';
8
9
  const DEFAULT_BRANCH = 'production';
9
10
  export class RecommendationInstantiator {
10
11
  constructor(config, services, context) {
@@ -40,20 +41,13 @@ export class RecommendationInstantiator {
40
41
  this.tracker = services?.tracker || new Tracker(this.config.client.globals);
41
42
  this.logger = services?.logger || new Logger({ prefix: 'RecommendationInstantiator ', mode: this.mode });
42
43
  const profileCount = {};
44
+ // script block targeter for "grouped" and "legacy" blocks
43
45
  this.targeter = new DomTargeter([
44
46
  {
45
47
  selector: `${this.config.selector || 'script[type="searchspring/recommend"], script[type="searchspring/personalized-recommendations"]'}, script[type="searchspring/recommend"][profile="email"]`,
46
48
  autoRetarget: true,
47
49
  clickRetarget: true,
48
- inject: {
49
- action: 'before',
50
- element: (target, origElement) => {
51
- const profile = origElement.getAttribute('profile') || '';
52
- const recsContainer = document.createElement('div');
53
- recsContainer.setAttribute('searchspring-recommend', profile);
54
- return recsContainer;
55
- },
56
- },
50
+ emptyTarget: false,
57
51
  },
58
52
  {
59
53
  selector: 'script[type="searchspring/recommendations"]',
@@ -61,7 +55,9 @@ export class RecommendationInstantiator {
61
55
  clickRetarget: true,
62
56
  emptyTarget: false,
63
57
  },
64
- ], async (target, elem, originalElem) => {
58
+ ], async (target, elem, _originalElem, targeter) => {
59
+ this.targeter = this.targeter || targeter;
60
+ const scriptElement = elem;
65
61
  const elemContext = getContext([
66
62
  'shopperId',
67
63
  'shopper',
@@ -76,7 +72,7 @@ export class RecommendationInstantiator {
76
72
  'custom',
77
73
  'profiles',
78
74
  'globals',
79
- ], (originalElem || elem));
75
+ ], scriptElement);
80
76
  if (elemContext.profiles && elemContext.profiles.length) {
81
77
  // using the "grouped block" integration structure
82
78
  // type the new profile specific integration context variables
@@ -90,34 +86,48 @@ export class RecommendationInstantiator {
90
86
  cart: scriptContextGlobals?.cart && getArrayFunc(scriptContextGlobals.cart),
91
87
  products: scriptContextGlobals?.products,
92
88
  shopper: scriptContextGlobals?.shopper?.id,
93
- batchId: Math.random(),
89
+ batchId: Math.floor(Math.random() * Number.MAX_SAFE_INTEGER),
94
90
  }),
95
91
  };
96
- const targetsArr = [];
97
- // build out the targets array for each profile
92
+ // create a per-profile DomTargeter for each profile so each controller
93
+ // gets its own targeter tracking its specific element
98
94
  scriptContextProfiles.forEach((profile) => {
99
95
  if (profile.selector) {
100
- const targetObj = {
96
+ const profileTarget = {
101
97
  selector: profile.selector,
102
98
  autoRetarget: true,
103
- clickRetarget: true,
104
99
  profile,
105
100
  };
106
- targetsArr.push(targetObj);
107
- }
108
- });
109
- new DomTargeter(targetsArr, async (target, elem, originalElem) => {
110
- if (target.profile?.profile || target.profile?.tag) {
111
- const profileRequestGlobals = {
112
- ...requestGlobals,
113
- profile: target.profile?.options,
114
- tag: target.profile.tag || target.profile.profile, // have to support both tag and profile due to having profile at release, but will favor tag
115
- };
116
- const profileContext = deepmerge(this.context, defined({ globals: scriptContextGlobals, profile: target.profile }));
117
- if (elemContext.custom) {
118
- profileContext.custom = elemContext.custom;
119
- }
120
- readyTheController(this, elem, profileContext, profileCount, originalElem, profileRequestGlobals);
101
+ // track the controller for this profile so multiple matched elements share it
102
+ let profileControllerPromise;
103
+ new DomTargeter([profileTarget], async (target, targetElem, _originalElem, targeter) => {
104
+ // skip retarget if the source script element was removed from the DOM (SPA navigation)
105
+ if (!scriptElement.isConnected) {
106
+ return;
107
+ }
108
+ if (target.profile?.profile || target.profile?.tag) {
109
+ const profileRequestGlobals = {
110
+ ...requestGlobals,
111
+ profile: target.profile?.options,
112
+ tag: target.profile.tag || target.profile.profile, // have to support both tag and profile due to having profile at release, but will favor tag
113
+ };
114
+ const profileContext = deepmerge(this.context, defined({ globals: scriptContextGlobals, profile: target.profile }));
115
+ if (elemContext.custom) {
116
+ profileContext.custom = elemContext.custom;
117
+ }
118
+ if (!profileControllerPromise) {
119
+ // first element match — create the controller
120
+ profileControllerPromise = readyTheController(this, targetElem, profileContext, profileCount, scriptElement, profileRequestGlobals, targeter);
121
+ }
122
+ else {
123
+ // subsequent element matches — reuse the existing controller and just render
124
+ const controller = await profileControllerPromise;
125
+ if (controller && targetElem) {
126
+ renderController(this, controller, targetElem, scriptElement);
127
+ }
128
+ }
129
+ }
130
+ });
121
131
  }
122
132
  });
123
133
  }
@@ -137,7 +147,20 @@ export class RecommendationInstantiator {
137
147
  profile: options,
138
148
  }),
139
149
  };
140
- readyTheController(this, elem, deepmerge(this.context, elemContext), profileCount, originalElem, profileRequestGlobals);
150
+ // inject a render container before the script element
151
+ const profileAttr = scriptElement.getAttribute('profile') || '';
152
+ const recsContainer = document.createElement('div');
153
+ recsContainer.setAttribute('searchspring-recommend', profileAttr);
154
+ scriptElement.before(recsContainer);
155
+ const legacyContext = deepmerge(this.context, elemContext);
156
+ // create a per-element DomTargeter for the injected div (mirrors grouped block pattern)
157
+ new DomTargeter([{ selector: `[searchspring-recommend="${profileAttr}"]`, name: `legacy_${profile}_${profileCount[profile || ''] || 0}` }], async (_target, targetElem, _originalElem, targeter) => {
158
+ // skip retarget if the source script element was removed from the DOM (SPA navigation)
159
+ if (!scriptElement.isConnected) {
160
+ return;
161
+ }
162
+ readyTheController(this, targetElem, legacyContext, profileCount, scriptElement, profileRequestGlobals, targeter);
163
+ });
141
164
  }
142
165
  });
143
166
  }
@@ -150,26 +173,39 @@ export class RecommendationInstantiator {
150
173
  use(attachments) {
151
174
  this.uses.push(attachments);
152
175
  }
176
+ // cleanup to ensure we release controllers no longer rendering in the DOM (memory leak prevention for SPA's)
177
+ cleanupStaleControllers() {
178
+ Object.keys(this.controller).forEach((id) => {
179
+ const controller = this.controller[id];
180
+ const targeters = Object.values(controller.targeters);
181
+ const hasConnectedTarget = targeters.some((targeter) => targeter.getTargetedElems().some((elem) => elem.isConnected));
182
+ if (!hasConnectedTarget) {
183
+ controller.targeters = {};
184
+ delete this.controller[id];
185
+ if (window.searchspring?.controller) {
186
+ delete window.searchspring.controller[id];
187
+ }
188
+ }
189
+ });
190
+ }
153
191
  }
154
- async function readyTheController(instance, injectedElem, context, profileCount, elem, controllerGlobals) {
192
+ async function readyTheController(instance, targetElem, context, profileCount, scriptElem, controllerGlobals, targeter) {
155
193
  const { profile, batchId, cart, tag } = controllerGlobals;
156
194
  const batched = profile?.batched ?? controllerGlobals.batched ?? true;
157
195
  if (!tag) {
158
196
  // FEEDBACK: change message depending on script integration type (profile vs. legacy)
159
- instance.logger.warn(`'tag' is missing from <script> tag, skipping this profile`, elem);
197
+ instance.logger.warn(`'tag' is missing from <script> tag, skipping this profile`, scriptElem);
160
198
  return;
161
199
  }
162
200
  if (Array.isArray(cart)) {
163
201
  instance.tracker.cookies.cart.set(cart);
164
202
  }
165
- profileCount[tag] = profileCount[tag] + 1 || 1;
166
203
  const globals = deepmerge.all([
167
204
  instance.config.client?.globals || {},
168
205
  instance.config.config?.globals || {},
169
206
  controllerGlobals,
170
207
  ]);
171
- const controllerConfig = {
172
- id: `recommend_${tag}_${profileCount[tag] - 1}`,
208
+ const controllerConfigBase = {
173
209
  tag,
174
210
  batched: batched ?? true,
175
211
  realtime: Boolean(context.options?.realtime ?? context.profile?.options?.realtime),
@@ -178,77 +214,69 @@ async function readyTheController(instance, injectedElem, context, profileCount,
178
214
  globals,
179
215
  };
180
216
  if (profile?.branch) {
181
- controllerConfig.branch = profile?.branch;
182
- }
183
- // try to find an existing controller by similar configuration
184
- let controller = Object.keys(instance.controller)
185
- .map((id) => instance.controller[id])
186
- .filter((controller) => {
187
- return (JSON.stringify({
188
- batched: controller.config.batched,
189
- branch: controller.config.branch,
190
- globals: controller.config.globals,
191
- tag: controller.config.tag,
192
- realtime: controller.config.realtime,
193
- }) ==
194
- JSON.stringify({
195
- batched: controllerConfig.batched,
196
- branch: controllerConfig.branch,
197
- globals: controllerConfig.globals,
198
- tag: controllerConfig.tag,
199
- realtime: controllerConfig.realtime,
200
- }));
201
- })[0];
202
- if (!controller) {
203
- // no existing controller found of same configuration - creating a new controller
204
- const createRecommendationController = (await import('../create/createRecommendationController')).default;
205
- controller = createRecommendationController({
206
- url: instance.config.url,
207
- controller: controllerConfig,
208
- context,
209
- mode: instance.config.mode,
210
- }, { client: instance.client, tracker: instance.tracker });
211
- instance.uses.forEach((attachements) => controller.use(attachements));
212
- instance.plugins.forEach((plugin) => controller.plugin(plugin.func, ...plugin.args));
213
- instance.middleware.forEach((middleware) => controller.on(middleware.event, ...middleware.func));
217
+ controllerConfigBase.branch = profile?.branch;
214
218
  }
219
+ // clean up controllers whose rendered elements are no longer in the DOM (SPA navigation)
220
+ instance.cleanupStaleControllers();
221
+ profileCount[tag] = profileCount[tag] + 1 || 1;
222
+ const controllerConfig = {
223
+ id: `recommend_${tag}_${profileCount[tag] - 1}`,
224
+ ...controllerConfigBase,
225
+ };
226
+ const controller = createRecommendationController({
227
+ url: instance.config.url,
228
+ controller: controllerConfig,
229
+ context,
230
+ mode: instance.config.mode,
231
+ }, { client: instance.client, tracker: instance.tracker });
232
+ instance.uses.forEach((attachements) => controller.use(attachements));
233
+ instance.plugins.forEach((plugin) => controller.plugin(plugin.func, ...plugin.args));
234
+ instance.middleware.forEach((middleware) => controller.on(middleware.event, ...middleware.func));
235
+ // add controller to instantiator and global namespace
236
+ instance.controller[controller.config.id] = controller;
237
+ window.searchspring.controller = window.searchspring.controller || {};
238
+ window.searchspring.controller[controller.config.id] = controller;
239
+ // register targeter on the controller for element tracking
240
+ controller.addTargeter(targeter);
215
241
  // run a search on the controller if it is not currently
216
242
  if (!controller.store.loading) {
217
243
  await controller.search();
218
244
  }
219
- controller.addTargeter(instance.targeter);
220
- instance.controller[controller.config.id] = controller;
221
- window.searchspring.controller = window.searchspring.controller || {};
222
- window.searchspring.controller[controller.config.id] = controller;
223
245
  const profileVars = controller.store.profile.display.templateParameters;
224
- const component = controller.store.profile.display.template?.component;
225
246
  if (controller.store.error) {
226
247
  //something went wrong
227
248
  //err was already logged - nothing to do.
228
249
  return;
229
250
  }
230
251
  if (!controller.store.profile.display.template) {
231
- instance.logger.error(`profile '${tag}' found on the following element is missing a template!\n${elem?.outerHTML}`);
252
+ instance.logger.error(`profile '${tag}' found on the following element is missing a template!\n${scriptElem?.outerHTML}`);
232
253
  return;
233
254
  }
234
255
  if (!profileVars) {
235
- instance.logger.error(`profile '${tag}' found on the following element is missing templateParameters!\n${elem?.outerHTML}`);
256
+ instance.logger.error(`profile '${tag}' found on the following element is missing templateParameters!\n${scriptElem?.outerHTML}`);
236
257
  return;
237
258
  }
259
+ if (targetElem) {
260
+ await renderController(instance, controller, targetElem, scriptElem);
261
+ }
262
+ return controller;
263
+ }
264
+ async function renderController(instance, controller, targetElem, scriptElem) {
265
+ const tag = controller.config.tag;
266
+ const component = controller.store.profile.display.template?.component;
238
267
  if (!component) {
239
- instance.logger.error(`profile '${tag}' found on the following element is missing a component!\n${elem?.outerHTML}`);
268
+ instance.logger.error(`profile '${tag}' found on the following element is missing a component!\n${scriptElem?.outerHTML}`);
240
269
  return;
241
270
  }
242
271
  const RecommendationsComponent = instance.config.components[component] &&
243
272
  (await instance.config.components[component]());
244
273
  if (!RecommendationsComponent) {
245
- instance.logger.error(`profile '${tag}' found on the following element is expecting component mapping for '${component}' - verify instantiator config.\n${elem?.outerHTML}`);
274
+ instance.logger.error(`profile '${tag}' found on the following element is expecting component mapping for '${component}' - verify instantiator config.\n${scriptElem?.outerHTML}`);
246
275
  return;
247
276
  }
248
277
  setTimeout(() => {
249
- if (injectedElem) {
250
- render(_jsx(RecommendationsComponent, { controller: controller }), injectedElem);
251
- }
278
+ targetElem.setAttribute('ss-controller-id', controller.config.id);
279
+ render(_jsx(RecommendationsComponent, { controller: controller }), targetElem);
252
280
  });
253
281
  }
254
282
  function getArrayFunc(arrayOrFunc) {
@@ -9,7 +9,7 @@ import type { Controllers, AbstractController, SearchControllerConfig, Autocompl
9
9
  import type { TrackerConfig, TrackerGlobals } from '@searchspring/snap-tracker';
10
10
  import type { Target, OnTarget } from '@searchspring/snap-toolbox';
11
11
  import type { UrlTranslatorConfig } from '@searchspring/snap-url-manager';
12
- import { RecommendationInstantiator, RecommendationInstantiatorConfig } from './Instantiators/RecommendationInstantiator';
12
+ import type { RecommendationInstantiator, RecommendationInstantiatorConfig } from './Instantiators/RecommendationInstantiator';
13
13
  import type { SnapControllerServices, InitialUrlConfig } from './types';
14
14
  export declare const BRANCH_COOKIE = "ssBranch";
15
15
  export declare const BRANCH_PARAM = "searchspring-preview";
@@ -1 +1 @@
1
- {"version":3,"file":"Snap.d.ts","sourceRoot":"","sources":["../../src/Snap.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Snap.d.ts","sourceRoot":"","sources":["../../src/Snap.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@searchspring/snap-preact",
3
- "version": "0.76.1",
3
+ "version": "0.77.0",
4
4
  "description": "Snap Preact",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -20,17 +20,17 @@
20
20
  "test:watch": "jest --watch"
21
21
  },
22
22
  "dependencies": {
23
- "@searchspring/snap-client": "0.76.1",
24
- "@searchspring/snap-controller": "0.76.1",
25
- "@searchspring/snap-event-manager": "0.76.1",
26
- "@searchspring/snap-logger": "0.76.1",
27
- "@searchspring/snap-platforms": "0.76.1",
28
- "@searchspring/snap-preact-components": "0.76.1",
29
- "@searchspring/snap-profiler": "0.76.1",
30
- "@searchspring/snap-store-mobx": "0.76.1",
31
- "@searchspring/snap-toolbox": "0.76.1",
32
- "@searchspring/snap-tracker": "0.76.1",
33
- "@searchspring/snap-url-manager": "0.76.1",
23
+ "@searchspring/snap-client": "0.77.0",
24
+ "@searchspring/snap-controller": "0.77.0",
25
+ "@searchspring/snap-event-manager": "0.77.0",
26
+ "@searchspring/snap-logger": "0.77.0",
27
+ "@searchspring/snap-platforms": "0.77.0",
28
+ "@searchspring/snap-preact-components": "0.77.0",
29
+ "@searchspring/snap-profiler": "0.77.0",
30
+ "@searchspring/snap-store-mobx": "0.77.0",
31
+ "@searchspring/snap-toolbox": "0.77.0",
32
+ "@searchspring/snap-tracker": "0.77.0",
33
+ "@searchspring/snap-url-manager": "0.77.0",
34
34
  "deepmerge": "4.3.1",
35
35
  "intersection-observer": "0.12.0",
36
36
  "is-plain-object": "5.0.0"
@@ -43,5 +43,5 @@
43
43
  "files": [
44
44
  "dist/**/*"
45
45
  ],
46
- "gitHead": "c834b949788f37cd5265f227e7416280587f6989"
46
+ "gitHead": "d7a25a5ade47e4561f49af70f6f929b7331cd15e"
47
47
  }