@coveo/quantic 3.37.9 → 3.37.10

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.
@@ -4,6 +4,7 @@ import {
4
4
  initializeWithHeadless,
5
5
  getHeadlessBundle,
6
6
  } from 'c/quanticHeadlessLoader';
7
+ import {unwrapLockerProxiedObject} from 'c/quanticUtils';
7
8
  import {LightningElement, api} from 'lwc';
8
9
 
9
10
  /** @typedef {import("coveo").Result} Result */
@@ -28,7 +29,13 @@ export default class QuanticResultHighlightedTextField extends LightningElement
28
29
  * @api
29
30
  * @type {Result}
30
31
  */
31
- @api result;
32
+ @api
33
+ get result() {
34
+ return this._result;
35
+ }
36
+ set result(result) {
37
+ this._result = unwrapLockerProxiedObject(result);
38
+ }
32
39
  /**
33
40
  * (Optional) The label to display.
34
41
  * @api
@@ -49,6 +56,8 @@ export default class QuanticResultHighlightedTextField extends LightningElement
49
56
  isInitialized = false;
50
57
  /** @type {boolean} */
51
58
  validated = false;
59
+ /** @type {Result} */
60
+ _result;
52
61
 
53
62
  connectedCallback() {
54
63
  this.validateProps();
@@ -4,7 +4,7 @@ import {
4
4
  getHeadlessBundle,
5
5
  getHeadlessEnginePromise,
6
6
  } from 'c/quanticHeadlessLoader';
7
- import {ResultUtils} from 'c/quanticUtils';
7
+ import {ResultUtils, unwrapLockerProxiedObject} from 'c/quanticUtils';
8
8
  import {NavigationMixin} from 'lightning/navigation';
9
9
  import {LightningElement, api} from 'lwc';
10
10
 
@@ -38,7 +38,13 @@ export default class QuanticResultLink extends NavigationMixin(
38
38
  * @api
39
39
  * @type {Result}
40
40
  */
41
- @api result;
41
+ @api
42
+ get result() {
43
+ return this._result;
44
+ }
45
+ set result(result) {
46
+ this._result = unwrapLockerProxiedObject(result);
47
+ }
42
48
  /**
43
49
  * Where to display the linked URL, as the name for a browsing context (a tab, window, or <iframe>).
44
50
  * The following keywords have special meanings for where to load the URL:
@@ -75,6 +81,8 @@ export default class QuanticResultLink extends NavigationMixin(
75
81
  engine;
76
82
  /** @type {AnyHeadless} */
77
83
  headless;
84
+ /** @type {Result} */
85
+ _result;
78
86
  /** @type {string} */
79
87
  salesforceRecordUrl;
80
88
 
@@ -113,8 +121,7 @@ export default class QuanticResultLink extends NavigationMixin(
113
121
  this.engine = engine;
114
122
  ResultUtils.bindClickEventsOnResult(
115
123
  this.engine,
116
- // Destructuring transforms the Proxy object created by Salesforce to a normal object so no unexpected behaviour will occur with the Headless library.
117
- {...this.result, raw: {...this.result.raw}},
124
+ this.result,
118
125
  this.template,
119
126
  this.headless.buildInteractiveResult
120
127
  );
@@ -8,7 +8,11 @@ import {
8
8
  HeadlessBundleNames,
9
9
  isHeadlessBundle,
10
10
  } from 'c/quanticHeadlessLoader';
11
- import {I18nUtils, getLastFocusableElement} from 'c/quanticUtils';
11
+ import {
12
+ I18nUtils,
13
+ getLastFocusableElement,
14
+ unwrapLockerProxiedObject,
15
+ } from 'c/quanticUtils';
12
16
  import {LightningElement, api, track} from 'lwc';
13
17
 
14
18
  /** @typedef {import("coveo").Result} Result */
@@ -42,7 +46,13 @@ export default class QuanticResultQuickview extends LightningElement {
42
46
  * @api
43
47
  * @type {ResultWithFolding}
44
48
  */
45
- @api result;
49
+ @api
50
+ get result() {
51
+ return this._result;
52
+ }
53
+ set result(result) {
54
+ this._result = unwrapLockerProxiedObject(result);
55
+ }
46
56
  /**
47
57
  * The maximum preview size to retrieve, in bytes. By default, the full preview is retrieved.
48
58
  * @api
@@ -84,6 +94,8 @@ export default class QuanticResultQuickview extends LightningElement {
84
94
 
85
95
  /** @type {Quickview} */
86
96
  quickview;
97
+ /** @type {ResultWithFolding} */
98
+ _result;
87
99
  /** @type {boolean} */
88
100
  isQuickviewOpen = false;
89
101
  /** @type {Function} */
@@ -2,6 +2,7 @@ import {
2
2
  I18nUtils,
3
3
  buildTemplateTextFromResult,
4
4
  copyToClipboard,
5
+ unwrapLockerProxiedObject,
5
6
  } from 'c/quanticUtils';
6
7
 
7
8
  describe('c/quanticUtils', () => {
@@ -200,4 +201,33 @@ describe('c/quanticUtils', () => {
200
201
  );
201
202
  });
202
203
  });
204
+
205
+ describe('unwrapLockerObject', () => {
206
+ it('should deeply clone complex objects while preserving primitive values', () => {
207
+ const original = {
208
+ title: 'Example',
209
+ raw: {
210
+ foo: 'bar',
211
+ tags: ['a', {value: 'b'}],
212
+ },
213
+ score: 42,
214
+ };
215
+
216
+ const unwrapped = unwrapLockerProxiedObject(original);
217
+
218
+ expect(unwrapped).toEqual(original);
219
+ expect(unwrapped).not.toBe(original);
220
+ expect(unwrapped.raw).not.toBe(original.raw);
221
+ expect(unwrapped.raw.tags).not.toBe(original.raw.tags);
222
+ expect(unwrapped.raw.tags[1]).not.toBe(original.raw.tags[1]);
223
+ });
224
+
225
+ it('should return primitive values as-is', () => {
226
+ expect(unwrapLockerProxiedObject(undefined)).toBeUndefined();
227
+ expect(unwrapLockerProxiedObject(null)).toBeNull();
228
+ expect(unwrapLockerProxiedObject('value')).toBe('value');
229
+ expect(unwrapLockerProxiedObject(0)).toBe(0);
230
+ expect(unwrapLockerProxiedObject(false)).toBe(false);
231
+ });
232
+ });
203
233
  });
@@ -259,6 +259,30 @@ export function parseXML(string) {
259
259
  return new window.DOMParser().parseFromString(string, 'text/xml');
260
260
  }
261
261
 
262
+ /**
263
+ * Recursively clones objects to break Locker proxy chains.
264
+ * @param {any} value
265
+ * @returns {any}
266
+ */
267
+ export function unwrapLockerProxiedObject(value) {
268
+ if (value === null || typeof value !== 'object') {
269
+ return value;
270
+ }
271
+
272
+ if (Array.isArray(value)) {
273
+ return value.map((item) => unwrapLockerProxiedObject(item));
274
+ }
275
+
276
+ const unwrappedValue = {};
277
+ for (const key in value) {
278
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
279
+ unwrappedValue[key] = unwrapLockerProxiedObject(value[key]);
280
+ }
281
+ }
282
+
283
+ return unwrappedValue;
284
+ }
285
+
262
286
  /**
263
287
  * Utility class for managing a simple in-memory store.
264
288
  * Supports registering and retrieving facet and sort option data.