@searchspring/snap-preact 0.20.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +293 -0
  3. package/dist/cjs/Instantiators/RecommendationInstantiator.d.ts +49 -0
  4. package/dist/cjs/Instantiators/RecommendationInstantiator.d.ts.map +1 -0
  5. package/dist/cjs/Instantiators/RecommendationInstantiator.js +226 -0
  6. package/dist/cjs/Snap.d.ts +93 -0
  7. package/dist/cjs/Snap.d.ts.map +1 -0
  8. package/dist/cjs/Snap.js +549 -0
  9. package/dist/cjs/components/BranchOverride.d.ts +7 -0
  10. package/dist/cjs/components/BranchOverride.d.ts.map +1 -0
  11. package/dist/cjs/components/BranchOverride.js +237 -0
  12. package/dist/cjs/create/createAutocompleteController.d.ts +5 -0
  13. package/dist/cjs/create/createAutocompleteController.d.ts.map +1 -0
  14. package/dist/cjs/create/createAutocompleteController.js +25 -0
  15. package/dist/cjs/create/createFinderController.d.ts +5 -0
  16. package/dist/cjs/create/createFinderController.d.ts.map +1 -0
  17. package/dist/cjs/create/createFinderController.js +25 -0
  18. package/dist/cjs/create/createRecommendationController.d.ts +5 -0
  19. package/dist/cjs/create/createRecommendationController.d.ts.map +1 -0
  20. package/dist/cjs/create/createRecommendationController.js +25 -0
  21. package/dist/cjs/create/createSearchController.d.ts +5 -0
  22. package/dist/cjs/create/createSearchController.d.ts.map +1 -0
  23. package/dist/cjs/create/createSearchController.js +25 -0
  24. package/dist/cjs/create/index.d.ts +5 -0
  25. package/dist/cjs/create/index.d.ts.map +1 -0
  26. package/dist/cjs/create/index.js +14 -0
  27. package/dist/cjs/index.d.ts +5 -0
  28. package/dist/cjs/index.d.ts.map +1 -0
  29. package/dist/cjs/index.js +18 -0
  30. package/dist/cjs/polyfills/polyfills.d.ts +2 -0
  31. package/dist/cjs/polyfills/polyfills.d.ts.map +1 -0
  32. package/dist/cjs/polyfills/polyfills.js +31 -0
  33. package/dist/cjs/types.d.ts +54 -0
  34. package/dist/cjs/types.d.ts.map +1 -0
  35. package/dist/cjs/types.js +2 -0
  36. package/dist/esm/Instantiators/RecommendationInstantiator.d.ts +49 -0
  37. package/dist/esm/Instantiators/RecommendationInstantiator.d.ts.map +1 -0
  38. package/dist/esm/Instantiators/RecommendationInstantiator.js +127 -0
  39. package/dist/esm/Snap.d.ts +93 -0
  40. package/dist/esm/Snap.d.ts.map +1 -0
  41. package/dist/esm/Snap.js +396 -0
  42. package/dist/esm/components/BranchOverride.d.ts +7 -0
  43. package/dist/esm/components/BranchOverride.d.ts.map +1 -0
  44. package/dist/esm/components/BranchOverride.js +172 -0
  45. package/dist/esm/create/createAutocompleteController.d.ts +5 -0
  46. package/dist/esm/create/createAutocompleteController.d.ts.map +1 -0
  47. package/dist/esm/create/createAutocompleteController.js +23 -0
  48. package/dist/esm/create/createFinderController.d.ts +5 -0
  49. package/dist/esm/create/createFinderController.d.ts.map +1 -0
  50. package/dist/esm/create/createFinderController.js +23 -0
  51. package/dist/esm/create/createRecommendationController.d.ts +5 -0
  52. package/dist/esm/create/createRecommendationController.d.ts.map +1 -0
  53. package/dist/esm/create/createRecommendationController.js +23 -0
  54. package/dist/esm/create/createSearchController.d.ts +5 -0
  55. package/dist/esm/create/createSearchController.d.ts.map +1 -0
  56. package/dist/esm/create/createSearchController.js +23 -0
  57. package/dist/esm/create/index.d.ts +5 -0
  58. package/dist/esm/create/index.d.ts.map +1 -0
  59. package/dist/esm/create/index.js +4 -0
  60. package/dist/esm/index.d.ts +5 -0
  61. package/dist/esm/index.d.ts.map +1 -0
  62. package/dist/esm/index.js +3 -0
  63. package/dist/esm/polyfills/polyfills.d.ts +2 -0
  64. package/dist/esm/polyfills/polyfills.d.ts.map +1 -0
  65. package/dist/esm/polyfills/polyfills.js +9 -0
  66. package/dist/esm/types.d.ts +54 -0
  67. package/dist/esm/types.d.ts.map +1 -0
  68. package/dist/esm/types.js +1 -0
  69. package/package.json +43 -0
@@ -0,0 +1,127 @@
1
+ import { jsx as _jsx } from "preact/jsx-runtime";
2
+ import { render } from 'preact';
3
+ import { DomTargeter, getContext } from '@searchspring/snap-toolbox';
4
+ export class RecommendationInstantiator {
5
+ constructor(config, { client, logger, tracker }) {
6
+ this.controllers = {};
7
+ this.uses = [];
8
+ this.plugins = [];
9
+ this.middleware = [];
10
+ this.config = config;
11
+ if (!this.config) {
12
+ throw new Error(`Recommendation Instantiator config is required`);
13
+ }
14
+ if (!this.config.config?.branch) {
15
+ throw new Error(`Recommendation Instantiator config must contain 'branch' property`);
16
+ }
17
+ if (!this.config.components || typeof this.config.components != 'object') {
18
+ throw new Error(`Recommendation Instantiator config must contain 'components' mapping property`);
19
+ }
20
+ this.client = client;
21
+ this.tracker = tracker;
22
+ this.logger = logger;
23
+ const profileCount = {};
24
+ this.targeter = new DomTargeter([
25
+ {
26
+ selector: `script[type="searchspring/recommend"], script[type="searchspring/personalized-recommendations"]${this.config.selector ? ` , ${this.config.selector}` : ''}`,
27
+ inject: {
28
+ action: 'before',
29
+ element: (target, origElement) => {
30
+ const profile = origElement.getAttribute('profile');
31
+ if (profile) {
32
+ const recsContainer = document.createElement('div');
33
+ recsContainer.setAttribute('searchspring-recommend', profile);
34
+ return recsContainer;
35
+ }
36
+ else {
37
+ this.logger.warn(`'profile' attribute is missing from <script> tag, skipping this profile`, origElement);
38
+ }
39
+ },
40
+ },
41
+ },
42
+ ], async (target, injectedElem, elem) => {
43
+ const globals = {};
44
+ const { shopper, shopperId, product, seed, options } = getContext(['shopperId', 'shopper', 'product', 'seed', 'options'], elem);
45
+ /*
46
+ type instantiatorContext = {
47
+ shopper?: string;
48
+ shopperId?: string;
49
+ product?: string;
50
+ seed?: string;
51
+ options?: {
52
+ siteId?: string;
53
+ branch?: string;
54
+ batched?: boolean;
55
+ realtime?: boolean;
56
+ categories?: any;
57
+ }
58
+ }
59
+ */
60
+ if (shopper || shopperId) {
61
+ globals.shopper = shopper || shopperId;
62
+ }
63
+ if (product || seed) {
64
+ globals.product = product || seed;
65
+ }
66
+ if (options?.branch) {
67
+ globals.branch = options.branch;
68
+ }
69
+ if (options?.siteId) {
70
+ globals.siteId = options.siteId;
71
+ }
72
+ if (options?.categories) {
73
+ globals.categories = options.categories;
74
+ }
75
+ const tag = injectedElem.getAttribute('searchspring-recommend');
76
+ profileCount[tag] = profileCount[tag] + 1 || 1;
77
+ const controllerConfig = {
78
+ id: `recommend_${tag + (profileCount[tag] - 1)}`,
79
+ tag,
80
+ batched: options?.batched ?? true,
81
+ realtime: Boolean(options?.realtime),
82
+ globals,
83
+ ...this.config.config,
84
+ };
85
+ const createRecommendationController = (await import('../create/createRecommendationController')).default;
86
+ const client = this.config.services?.client || this.client;
87
+ const tracker = this.config.services?.tracker || this.tracker;
88
+ const recs = createRecommendationController({
89
+ url: this.config.url || {},
90
+ controller: controllerConfig,
91
+ }, { client, tracker });
92
+ this.uses.forEach((attachements) => recs.use(attachements));
93
+ this.plugins.forEach((plugin) => recs.plugin(plugin));
94
+ this.middleware.forEach((middleware) => recs.on(middleware.event, ...middleware.func));
95
+ await recs.search();
96
+ recs.addTargeter(this.targeter);
97
+ this.controllers[recs.config.id] = recs;
98
+ const profileVars = recs.store.profile.display.templateParameters;
99
+ const component = recs.store.profile.display.template?.component;
100
+ if (!profileVars) {
101
+ recs.log.error(`profile failed to load!`);
102
+ return;
103
+ }
104
+ if (!component) {
105
+ recs.log.error(`template does not support components!`);
106
+ return;
107
+ }
108
+ const RecommendationsComponent = this.config.components && (await this.config.components[component]());
109
+ if (!RecommendationsComponent) {
110
+ recs.log.error(`component '${profileVars.component}' not found!`);
111
+ return;
112
+ }
113
+ setTimeout(() => {
114
+ render(_jsx(RecommendationsComponent, { controller: recs }, void 0), injectedElem);
115
+ });
116
+ });
117
+ }
118
+ plugin(func) {
119
+ this.plugins.push(func);
120
+ }
121
+ on(event, ...func) {
122
+ this.middleware.push({ event, func });
123
+ }
124
+ use(attachments) {
125
+ this.uses.push(attachments);
126
+ }
127
+ }
@@ -0,0 +1,93 @@
1
+ import { Client } from '@searchspring/snap-client';
2
+ import { Logger } from '@searchspring/snap-logger';
3
+ import { Tracker } from '@searchspring/snap-tracker';
4
+ import type { ClientConfig, ClientGlobals } from '@searchspring/snap-client';
5
+ import type { AbstractController, SearchController, AutocompleteController, FinderController, RecommendationController, SearchControllerConfig, AutocompleteControllerConfig, FinderControllerConfig, RecommendationControllerConfig, ControllerConfigs } from '@searchspring/snap-controller';
6
+ import type { Product } from '@searchspring/snap-tracker';
7
+ import type { Target, OnTarget } from '@searchspring/snap-toolbox';
8
+ import type { UrlTranslatorConfig } from '@searchspring/snap-url-manager';
9
+ import { RecommendationInstantiator, RecommendationInstantiatorConfig } from './Instantiators/RecommendationInstantiator';
10
+ import type { SnapControllerServices, RootComponent } from './types';
11
+ declare type ExtendedTarget = Target & {
12
+ name?: string;
13
+ controller?: AbstractController;
14
+ component?: () => Promise<RootComponent> | RootComponent;
15
+ skeleton?: () => Promise<any>;
16
+ props?: unknown;
17
+ onTarget?: OnTarget;
18
+ prefetch?: boolean;
19
+ };
20
+ declare type ContextVariables = {
21
+ shopper?: {
22
+ id: string;
23
+ cart?: Product[];
24
+ [variable: string]: any;
25
+ };
26
+ [variable: string]: any;
27
+ };
28
+ export declare type SnapConfig = {
29
+ context?: ContextVariables;
30
+ url?: UrlTranslatorConfig;
31
+ client: {
32
+ globals: ClientGlobals;
33
+ config?: ClientConfig;
34
+ };
35
+ instantiators?: {
36
+ recommendation?: RecommendationInstantiatorConfig;
37
+ };
38
+ controllers?: {
39
+ search?: {
40
+ config: SearchControllerConfig;
41
+ targeters?: ExtendedTarget[];
42
+ services?: SnapControllerServices;
43
+ url?: UrlTranslatorConfig;
44
+ }[];
45
+ autocomplete?: {
46
+ config: AutocompleteControllerConfig;
47
+ targeters: ExtendedTarget[];
48
+ services?: SnapControllerServices;
49
+ url?: UrlTranslatorConfig;
50
+ }[];
51
+ finder?: {
52
+ config: FinderControllerConfig;
53
+ targeters?: ExtendedTarget[];
54
+ services?: SnapControllerServices;
55
+ url?: UrlTranslatorConfig;
56
+ }[];
57
+ recommendation?: {
58
+ config: RecommendationControllerConfig;
59
+ targeters?: ExtendedTarget[];
60
+ services?: SnapControllerServices;
61
+ url?: UrlTranslatorConfig;
62
+ }[];
63
+ };
64
+ };
65
+ declare type ControllerTypes = SearchController | AutocompleteController | FinderController | RecommendationController;
66
+ declare enum DynamicImportNames {
67
+ SEARCH = "searchController",
68
+ AUTOCOMPLETE = "autocompleteController",
69
+ FINDER = "finderController",
70
+ RECOMMENDATION = "recommendationController"
71
+ }
72
+ export declare class Snap {
73
+ config: SnapConfig;
74
+ logger: Logger;
75
+ client: Client;
76
+ tracker: Tracker;
77
+ _controllerPromises: {
78
+ [controllerConfigId: string]: Promise<ControllerTypes>;
79
+ };
80
+ controllers: {
81
+ [controllerConfigId: string]: ControllerTypes;
82
+ };
83
+ _instantiatorPromises: {
84
+ [instantiatorId: string]: Promise<RecommendationInstantiator>;
85
+ };
86
+ getInstantiator: (id: string) => Promise<RecommendationInstantiator>;
87
+ getController: (id: string) => Promise<ControllerTypes>;
88
+ getControllers: (...controllerIds: string[]) => Promise<ControllerTypes[]>;
89
+ createController: (type: DynamicImportNames, config: ControllerConfigs, services: SnapControllerServices, urlConfig: UrlTranslatorConfig, resolve: (value?: ControllerTypes | PromiseLike<ControllerTypes>) => void) => Promise<ControllerTypes>;
90
+ constructor(config: SnapConfig);
91
+ }
92
+ export {};
93
+ //# sourceMappingURL=Snap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Snap.d.ts","sourceRoot":"","sources":["../../src/Snap.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,396 @@
1
+ import { jsx as _jsx } from "preact/jsx-runtime";
2
+ import deepmerge from 'deepmerge';
3
+ import { render } from 'preact';
4
+ import { Client } from '@searchspring/snap-client';
5
+ import { Logger, LogMode } from '@searchspring/snap-logger';
6
+ import { Tracker } from '@searchspring/snap-tracker';
7
+ import { version, DomTargeter, url, cookies, featureFlags } from '@searchspring/snap-toolbox';
8
+ import { default as createSearchController } from './create/createSearchController';
9
+ const BRANCH_COOKIE = 'ssBranch';
10
+ const SS_DEV_COOKIE = 'ssDev';
11
+ var DynamicImportNames;
12
+ (function (DynamicImportNames) {
13
+ DynamicImportNames["SEARCH"] = "searchController";
14
+ DynamicImportNames["AUTOCOMPLETE"] = "autocompleteController";
15
+ DynamicImportNames["FINDER"] = "finderController";
16
+ DynamicImportNames["RECOMMENDATION"] = "recommendationController";
17
+ })(DynamicImportNames || (DynamicImportNames = {}));
18
+ export class Snap {
19
+ constructor(config) {
20
+ this.getInstantiator = (id) => {
21
+ return this._instantiatorPromises[id] || Promise.reject(`getInstantiator could not find instantiator with id: ${id}`);
22
+ };
23
+ this.getController = (id) => {
24
+ return this._controllerPromises[id] || Promise.reject(`getController could not find controller with id: ${id}`);
25
+ };
26
+ this.getControllers = (...controllerIds) => {
27
+ const getControllerPromises = [];
28
+ controllerIds.forEach((id) => getControllerPromises.push(this.getController(id)));
29
+ return Promise.all(getControllerPromises);
30
+ };
31
+ this.createController = (type, config, services, urlConfig, resolve) => {
32
+ let importPromise;
33
+ switch (type) {
34
+ case DynamicImportNames.SEARCH:
35
+ importPromise = import('./create/createSearchController');
36
+ break;
37
+ case DynamicImportNames.AUTOCOMPLETE:
38
+ importPromise = import('./create/createAutocompleteController');
39
+ break;
40
+ case DynamicImportNames.FINDER:
41
+ importPromise = import('./create/createFinderController');
42
+ break;
43
+ case DynamicImportNames.RECOMMENDATION:
44
+ importPromise = import('./create/createRecommendationController');
45
+ break;
46
+ }
47
+ return importPromise.then((_) => {
48
+ if (!this.controllers[config.id]) {
49
+ this.controllers[config.id] = _.default({
50
+ url: deepmerge(this.config.url || {}, urlConfig || {}),
51
+ controller: config,
52
+ }, { client: services?.client || this.client, tracker: services?.tracker || this.tracker });
53
+ resolve(this.controllers[config.id]);
54
+ }
55
+ return this.controllers[config.id];
56
+ });
57
+ };
58
+ this.config = config;
59
+ this.logger = new Logger('Snap Preact ');
60
+ if (!this.config?.client?.globals?.siteId) {
61
+ throw new Error(`Snap: config provided must contain a valid config.client.globals.siteId value`);
62
+ }
63
+ this.client = new Client(this.config.client.globals, this.config.client.config);
64
+ this.tracker = new Tracker(this.config.client.globals);
65
+ this._controllerPromises = {};
66
+ this._instantiatorPromises = {};
67
+ this.controllers = {};
68
+ // TODO environment switch using URL?
69
+ this.logger.setMode(process.env.NODE_ENV);
70
+ // log version
71
+ this.logger.imageText({
72
+ url: 'https://snapui.searchspring.io/favicon.svg',
73
+ text: `[${version}]`,
74
+ style: `color: ${this.logger.colors.indigo}; font-weight: bold;`,
75
+ });
76
+ try {
77
+ const urlParams = url(window.location.href);
78
+ const branchParam = urlParams.params?.query?.branch || cookies.get(BRANCH_COOKIE);
79
+ if (branchParam && !document.querySelector(`script[${BRANCH_COOKIE}]`)) {
80
+ // set a cookie or localstorage with branch
81
+ if (featureFlags.cookies) {
82
+ cookies.set(BRANCH_COOKIE, branchParam, 'Lax', 3600000); // 1 hour
83
+ cookies.set(SS_DEV_COOKIE, '1', 'Lax', 0);
84
+ }
85
+ else {
86
+ this.logger.warn('Cookies are not supported/enabled by this browser, branch overrides will not persist!');
87
+ }
88
+ this.logger.setMode(LogMode.DEVELOPMENT);
89
+ this.logger.warn(`...loading build... '${branchParam}'`);
90
+ // append script with new branch in path
91
+ const script = document.createElement('script');
92
+ const src = `https://snapui.searchspring.io/${this.config.client.globals.siteId}/${branchParam}/bundle.js`;
93
+ script.src = src;
94
+ script.setAttribute(BRANCH_COOKIE, '');
95
+ document.head.appendChild(script);
96
+ new DomTargeter([
97
+ {
98
+ selector: 'body',
99
+ inject: {
100
+ action: 'append',
101
+ element: () => {
102
+ const branchContainer = document.createElement('div');
103
+ branchContainer.className = 'ss__branch--target';
104
+ return branchContainer;
105
+ },
106
+ },
107
+ },
108
+ ], async (target, elem) => {
109
+ const BranchOverride = (await import('./components/BranchOverride')).BranchOverride;
110
+ render(_jsx(BranchOverride, { branch: branchParam, cookieName: BRANCH_COOKIE, bundleUrl: src }, void 0), elem);
111
+ });
112
+ // prevent further instantiation of config
113
+ return;
114
+ }
115
+ }
116
+ catch (e) { }
117
+ if (window.searchspring) {
118
+ if (this.config.context)
119
+ window.searchspring.context = this.config.context;
120
+ if (this.client)
121
+ window.searchspring.client = this.client;
122
+ }
123
+ // autotrack shopper id from the context
124
+ if (this.config.context?.shopper?.id) {
125
+ this.tracker.track.shopper.login({
126
+ id: this.config.context.shopper.id,
127
+ });
128
+ }
129
+ // auto populate cart cookie from the context
130
+ if (this.config.context?.shopper?.cart) {
131
+ const cart = this.config.context.shopper.cart;
132
+ if (Array.isArray(cart)) {
133
+ const cartItems = cart.filter((item) => item?.sku || item?.childSku).map((item) => (item?.sku || item?.childSku).trim());
134
+ this.tracker.cookies.cart.set(cartItems);
135
+ }
136
+ }
137
+ Object.keys(this.config?.controllers || {}).forEach((type) => {
138
+ switch (type) {
139
+ case 'search': {
140
+ this.config.controllers[type].forEach((controller, index) => {
141
+ try {
142
+ const cntrlr = createSearchController({
143
+ url: deepmerge(this.config.url || {}, controller.url || {}),
144
+ controller: controller.config,
145
+ }, { client: controller.services?.client || this.client, tracker: controller.services?.tracker || this.tracker });
146
+ this.controllers[cntrlr.config.id] = cntrlr;
147
+ this._controllerPromises[cntrlr.config.id] = new Promise((resolve) => resolve(cntrlr));
148
+ let searched = false;
149
+ const runSearch = () => {
150
+ if (!searched) {
151
+ searched = true;
152
+ this.controllers[controller.config.id].search();
153
+ }
154
+ };
155
+ const targetFunction = async (target, elem, originalElem) => {
156
+ runSearch();
157
+ const onTarget = target.onTarget;
158
+ onTarget && onTarget(target, elem, originalElem);
159
+ try {
160
+ const Component = await target.component();
161
+ setTimeout(() => {
162
+ render(_jsx(Component, { controller: this.controllers[controller.config.id], ...target.props }, void 0), elem);
163
+ });
164
+ }
165
+ catch (err) {
166
+ this.logger.error(`Uncaught Error - Invalid value passed as the component.
167
+ This usually happens when you pass a JSX Element, and not a function that returns the component, in the snap config.
168
+
169
+ instead of -
170
+
171
+ targeters: [
172
+ {
173
+ selector: '#searchspring-content',
174
+ hideTarget: true,
175
+ component: <Content/>,
176
+ },
177
+ ]
178
+
179
+ or -
180
+
181
+ targeters: [
182
+ {
183
+ selector: '#searchspring-content',
184
+ hideTarget: true,
185
+ component: Content,
186
+ },
187
+ ]
188
+
189
+ please try -
190
+
191
+ targeters: [
192
+ {
193
+ selector: '#searchspring-content',
194
+ hideTarget: true,
195
+ component: () => Content
196
+ },
197
+ ]
198
+
199
+
200
+ The error above happened in the following targeter in the Snap Config`, target);
201
+ }
202
+ };
203
+ controller?.targeters?.forEach(async (target, target_index) => {
204
+ if (!target.selector) {
205
+ throw new Error(`Targets at index ${target_index} missing selector value (string).`);
206
+ }
207
+ if (!target.component) {
208
+ throw new Error(`Targets at index ${target_index} missing component value (Component).`);
209
+ }
210
+ if (target.prefetch) {
211
+ runSearch();
212
+ }
213
+ cntrlr.createTargeter({ controller: cntrlr, ...target }, async (target, elem, originalElem) => {
214
+ if (target.skeleton) {
215
+ const Skeleton = await target.skeleton();
216
+ setTimeout(() => {
217
+ render(_jsx(Skeleton, {}, void 0), elem);
218
+ });
219
+ }
220
+ targetFunction(target, elem, originalElem);
221
+ });
222
+ });
223
+ }
224
+ catch (err) {
225
+ this.logger.error(`Failed to instantiate ${type} controller at index ${index}.`, err);
226
+ }
227
+ });
228
+ break;
229
+ }
230
+ case 'autocomplete': {
231
+ this.config.controllers[type].forEach((controller, index) => {
232
+ this._controllerPromises[controller.config.id] = new Promise((resolve) => {
233
+ try {
234
+ let bound = false;
235
+ const runBind = () => {
236
+ if (!bound) {
237
+ bound = true;
238
+ setTimeout(() => {
239
+ this.controllers[controller.config.id].bind();
240
+ });
241
+ }
242
+ };
243
+ const targetFunction = async (target, elem, originalElem) => {
244
+ const onTarget = target.onTarget;
245
+ onTarget && onTarget(target, elem, originalElem);
246
+ const Component = (await target.component());
247
+ setTimeout(() => {
248
+ render(_jsx(Component, { controller: this.controllers[controller.config.id], input: originalElem, ...target.props }, void 0), elem);
249
+ });
250
+ };
251
+ if (!controller?.targeters || controller?.targeters.length === 0) {
252
+ this.createController(DynamicImportNames.AUTOCOMPLETE, controller.config, controller.services, controller.url, resolve);
253
+ }
254
+ controller?.targeters?.forEach(async (target, target_index) => {
255
+ if (!target.selector) {
256
+ throw new Error(`Targets at index ${target_index} missing selector value (string).`);
257
+ }
258
+ if (!target.component) {
259
+ throw new Error(`Targets at index ${target_index} missing component value (Component).`);
260
+ }
261
+ const targeter = new DomTargeter([
262
+ {
263
+ inject: {
264
+ action: 'after',
265
+ element: () => {
266
+ const acContainer = document.createElement('div');
267
+ acContainer.className = 'ss__autocomplete--target';
268
+ acContainer.addEventListener('click', (e) => {
269
+ e.stopPropagation();
270
+ });
271
+ return acContainer;
272
+ },
273
+ },
274
+ ...target,
275
+ },
276
+ ], async (target, elem, originalElem) => {
277
+ const cntrlr = await this.createController(DynamicImportNames.AUTOCOMPLETE, controller.config, controller.services, controller.url, resolve);
278
+ runBind();
279
+ targetFunction({ controller: cntrlr, ...target }, elem, originalElem);
280
+ cntrlr.addTargeter(targeter);
281
+ });
282
+ });
283
+ }
284
+ catch (err) {
285
+ this.logger.error(`Failed to instantiate ${type} controller at index ${index}.`, err);
286
+ }
287
+ });
288
+ });
289
+ break;
290
+ }
291
+ case 'finder': {
292
+ this.config.controllers[type].forEach((controller, index) => {
293
+ this._controllerPromises[controller.config.id] = new Promise((resolve) => {
294
+ try {
295
+ let searched = false;
296
+ const runSearch = () => {
297
+ if (!searched) {
298
+ this.controllers[controller.config.id].search();
299
+ searched = true;
300
+ }
301
+ };
302
+ const targetFunction = async (target, elem, originalElem) => {
303
+ const onTarget = target.onTarget;
304
+ onTarget && onTarget(target, elem, originalElem);
305
+ const Component = await target.component();
306
+ setTimeout(() => {
307
+ render(_jsx(Component, { controller: this.controllers[controller.config.id], ...target.props }, void 0), elem);
308
+ });
309
+ };
310
+ if (!controller?.targeters || controller?.targeters.length === 0) {
311
+ this.createController(DynamicImportNames.FINDER, controller.config, controller.services, controller.url, resolve);
312
+ }
313
+ controller?.targeters?.forEach(async (target, target_index) => {
314
+ if (!target.selector) {
315
+ throw new Error(`Targets at index ${target_index} missing selector value (string).`);
316
+ }
317
+ if (!target.component) {
318
+ throw new Error(`Targets at index ${target_index} missing component value (Component).`);
319
+ }
320
+ const targeter = new DomTargeter([{ ...target }], async (target, elem, originalElem) => {
321
+ const cntrlr = await this.createController(DynamicImportNames.FINDER, controller.config, controller.services, controller.url, resolve);
322
+ runSearch();
323
+ targetFunction({ controller: cntrlr, ...target }, elem, originalElem);
324
+ cntrlr.addTargeter(targeter);
325
+ });
326
+ });
327
+ }
328
+ catch (err) {
329
+ this.logger.error(`Failed to instantiate ${type} controller at index ${index}.`, err);
330
+ }
331
+ });
332
+ });
333
+ break;
334
+ }
335
+ case 'recommendation': {
336
+ this.config.controllers[type].forEach((controller, index) => {
337
+ this._controllerPromises[controller.config.id] = new Promise((resolve) => {
338
+ try {
339
+ let searched = false;
340
+ const runSearch = () => {
341
+ if (!searched) {
342
+ this.controllers[controller.config.id].search();
343
+ searched = true;
344
+ }
345
+ };
346
+ const targetFunction = async (target, elem, originalElem) => {
347
+ const onTarget = target.onTarget;
348
+ onTarget && onTarget(target, elem, originalElem);
349
+ const Component = await target.component();
350
+ setTimeout(() => {
351
+ render(_jsx(Component, { controller: this.controllers[controller.config.id], ...target.props }, void 0), elem);
352
+ });
353
+ };
354
+ if (!controller?.targeters || controller?.targeters.length === 0) {
355
+ this.createController(DynamicImportNames.RECOMMENDATION, controller.config, controller.services, controller.url, resolve);
356
+ }
357
+ controller?.targeters?.forEach(async (target, target_index) => {
358
+ if (!target.selector) {
359
+ throw new Error(`Targets at index ${target_index} missing selector value (string).`);
360
+ }
361
+ if (!target.component) {
362
+ throw new Error(`Targets at index ${target_index} missing component value (Component).`);
363
+ }
364
+ const targeter = new DomTargeter([{ ...target }], async (target, elem, originalElem) => {
365
+ const cntrlr = await this.createController(DynamicImportNames.RECOMMENDATION, controller.config, controller.services, controller.url, resolve);
366
+ runSearch();
367
+ targetFunction({ controller: cntrlr, ...target }, elem, originalElem);
368
+ cntrlr.addTargeter(targeter);
369
+ });
370
+ });
371
+ }
372
+ catch (err) {
373
+ this.logger.error(`Failed to instantiate ${type} controller at index ${index}.`, err);
374
+ }
375
+ });
376
+ });
377
+ break;
378
+ }
379
+ }
380
+ });
381
+ if (config?.instantiators?.recommendation) {
382
+ try {
383
+ this._instantiatorPromises.recommendations = import('./Instantiators/RecommendationInstantiator').then(({ RecommendationInstantiator }) => {
384
+ return new RecommendationInstantiator(config.instantiators.recommendation, {
385
+ client: config.instantiators.recommendation?.services?.client || this.client,
386
+ tracker: config.instantiators.recommendation?.services?.tracker || this.tracker,
387
+ logger: config.instantiators.recommendation?.services?.logger || this.logger,
388
+ });
389
+ });
390
+ }
391
+ catch (err) {
392
+ this.logger.error(`Failed to create Recommendations Instantiator.`, err);
393
+ }
394
+ }
395
+ }
396
+ }
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ export declare const BranchOverride: (props: {
3
+ branch: string;
4
+ cookieName: string;
5
+ bundleUrl: string;
6
+ }) => JSX.Element;
7
+ //# sourceMappingURL=BranchOverride.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BranchOverride.d.ts","sourceRoot":"","sources":["../../../src/components/BranchOverride.tsx"],"names":[],"mappings":";AA8IA,eAAO,MAAM,cAAc,UAAW;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KAAG,WA+FjG,CAAC"}