react-instantsearch 7.37.0 → 7.39.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.
@@ -1,4 +1,4 @@
1
- /*! React InstantSearch 7.37.0 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch */
1
+ /*! React InstantSearch 7.39.0 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
4
4
  typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
@@ -24,7 +24,7 @@
24
24
 
25
25
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
26
26
 
27
- var version$2 = '7.37.0';
27
+ var version$2 = '7.39.0';
28
28
 
29
29
  function _define_property(obj, key, value) {
30
30
  if (key in obj) {
@@ -571,10 +571,10 @@
571
571
  return objectHasKeys_1;
572
572
  }
573
573
 
574
- var omit;
574
+ var omit$1;
575
575
  var hasRequiredOmit;
576
576
  function requireOmit() {
577
- if (hasRequiredOmit) return omit;
577
+ if (hasRequiredOmit) return omit$1;
578
578
  hasRequiredOmit = 1;
579
579
  // https://github.com/babel/babel/blob/3aaafae053fa75febb3aa45d45b6f00646e30ba4/packages/babel-helpers/src/helpers.js#L604-L620
580
580
  function _objectWithoutPropertiesLoose(source, excluded) {
@@ -591,8 +591,8 @@
591
591
  }
592
592
  return target;
593
593
  }
594
- omit = _objectWithoutPropertiesLoose;
595
- return omit;
594
+ omit$1 = _objectWithoutPropertiesLoose;
595
+ return omit$1;
596
596
  }
597
597
 
598
598
  var RecommendParameters_1;
@@ -3919,7 +3919,7 @@
3919
3919
  function requireVersion() {
3920
3920
  if (hasRequiredVersion) return version$1;
3921
3921
  hasRequiredVersion = 1;
3922
- version$1 = '3.29.1';
3922
+ version$1 = '3.29.2';
3923
3923
  return version$1;
3924
3924
  }
3925
3925
 
@@ -6890,10 +6890,11 @@
6890
6890
 
6891
6891
  var hasAlphanumeric = new RegExp(/\w/i);
6892
6892
  function getHighlightFromSiblings(parts, i) {
6893
+ var _ref, _ref1;
6893
6894
  var _parts_, _parts_1;
6894
6895
  var current = parts[i];
6895
- var isNextHighlighted = ((_parts_ = parts[i + 1]) === null || _parts_ === void 0 ? void 0 : _parts_.isHighlighted) || true;
6896
- var isPreviousHighlighted = ((_parts_1 = parts[i - 1]) === null || _parts_1 === void 0 ? void 0 : _parts_1.isHighlighted) || true;
6896
+ var isNextHighlighted = (_ref = (_parts_ = parts[i + 1]) === null || _parts_ === void 0 ? void 0 : _parts_.isHighlighted) !== null && _ref !== void 0 ? _ref : true;
6897
+ var isPreviousHighlighted = (_ref1 = (_parts_1 = parts[i - 1]) === null || _parts_1 === void 0 ? void 0 : _parts_1.isHighlighted) !== null && _ref1 !== void 0 ? _ref1 : true;
6897
6898
  if (!hasAlphanumeric.test(unescape$1(current.value)) && isPreviousHighlighted === isNextHighlighted) {
6898
6899
  return isPreviousHighlighted;
6899
6900
  }
@@ -7258,19 +7259,23 @@
7258
7259
  * This is used to log issues in development environment only.
7259
7260
  */ var warn = noop;
7260
7261
 
7261
- function range(param) {
7262
- var _param_start = param.start, start = _param_start === void 0 ? 0 : _param_start, end = param.end, _param_step = param.step, step = _param_step === void 0 ? 1 : _param_step;
7263
- // We can't divide by 0 so we re-assign the step to 1 if it happens.
7264
- var limitStep = step === 0 ? 1 : step;
7265
- // In some cases the array to create has a decimal length.
7266
- // We therefore need to round the value.
7267
- // Example:
7268
- // { start: 1, end: 5000, step: 500 }
7269
- // => Array length = (5000 - 1) / 500 = 9.998
7270
- var arrayLength = Math.round((end - start) / limitStep);
7271
- return _to_consumable_array(Array(arrayLength)).map(function(_, current) {
7272
- return start + current * limitStep;
7273
- });
7262
+ /**
7263
+ * Creates a new object with the same keys as the original object, but without the excluded keys.
7264
+ * @param source original object
7265
+ * @param excluded keys to remove from the original object
7266
+ * @returns the new object
7267
+ */ function omit(source, excluded) {
7268
+ if (source === null || source === undefined) {
7269
+ return source;
7270
+ }
7271
+ return Object.keys(source).reduce(function(target, key) {
7272
+ if (excluded.indexOf(key) >= 0) {
7273
+ return target;
7274
+ }
7275
+ var validKey = key;
7276
+ target[validKey] = source[validKey];
7277
+ return target;
7278
+ }, {});
7274
7279
  }
7275
7280
 
7276
7281
  function createInitArgs(instantSearchInstance, parent, uiState) {
@@ -7318,6 +7323,132 @@
7318
7323
  instantSearchInstance.renderState = _object_spread_props(_object_spread({}, instantSearchInstance.renderState), _define_property({}, parentIndexName, _object_spread({}, instantSearchInstance.renderState[parentIndexName], renderState)));
7319
7324
  }
7320
7325
 
7326
+ function serializeParamValue(value) {
7327
+ if (value === undefined || value === null) {
7328
+ return null;
7329
+ }
7330
+ var t = typeof value === "undefined" ? "undefined" : _type_of(value);
7331
+ if (t === 'string' || t === 'number' || t === 'boolean') {
7332
+ return {
7333
+ value: String(value),
7334
+ type: t
7335
+ };
7336
+ }
7337
+ if (Array.isArray(value) || t === 'object') {
7338
+ var type = Array.isArray(value) ? 'array' : 'object';
7339
+ try {
7340
+ return {
7341
+ value: JSON.stringify(value),
7342
+ type: type
7343
+ };
7344
+ } catch (unused) {
7345
+ return {
7346
+ type: type
7347
+ };
7348
+ }
7349
+ }
7350
+ if (t === 'function') {
7351
+ return {
7352
+ value: value.name,
7353
+ type: 'function'
7354
+ };
7355
+ }
7356
+ // symbols, DOM elements: name only
7357
+ return null;
7358
+ }
7359
+ /**
7360
+ * Turns a `widgetParams`-style record into the serialized `WidgetTreeParam[]`
7361
+ * shape used throughout the usage events. Shared between the widget tree and
7362
+ * the root `ais.instantSearch` node so every node reports params identically.
7363
+ */ function serializeWidgetParams(widgetParams) {
7364
+ var params = [];
7365
+ Object.keys(widgetParams).forEach(function(key) {
7366
+ var raw = widgetParams[key];
7367
+ if (raw === undefined) {
7368
+ return;
7369
+ }
7370
+ var serialized = serializeParamValue(raw);
7371
+ if (serialized) {
7372
+ params.push(_object_spread({
7373
+ name: key
7374
+ }, serialized));
7375
+ } else {
7376
+ params.push({
7377
+ name: key
7378
+ });
7379
+ }
7380
+ });
7381
+ return params;
7382
+ }
7383
+ function buildWidgetTree(widgets, instantSearchInstance) {
7384
+ var parent = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : instantSearchInstance.mainIndex;
7385
+ var initOptions = createInitArgs(instantSearchInstance, parent, instantSearchInstance._initialUiState);
7386
+ return widgets.map(function(widget) {
7387
+ var widgetParams = {};
7388
+ if (widget.getWidgetRenderState) {
7389
+ var renderState = widget.getWidgetRenderState(initOptions);
7390
+ if (renderState && renderState.widgetParams) {
7391
+ widgetParams = renderState.widgetParams;
7392
+ }
7393
+ }
7394
+ var params = serializeWidgetParams(widgetParams);
7395
+ var children = isIndexWidget(widget) ? buildWidgetTree(widget.getWidgets(), instantSearchInstance, widget) : [];
7396
+ return {
7397
+ type: widget.$$widgetType || widget.$$type || 'unknown',
7398
+ params: params,
7399
+ children: children
7400
+ };
7401
+ });
7402
+ }
7403
+
7404
+ function extractWidgetPayload(widgets, instantSearchInstance, payload) {
7405
+ var parent = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : instantSearchInstance.mainIndex;
7406
+ var initOptions = createInitArgs(instantSearchInstance, parent, instantSearchInstance._initialUiState);
7407
+ widgets.forEach(function(widget) {
7408
+ var widgetParams = {};
7409
+ if (widget.getWidgetRenderState) {
7410
+ var renderState = widget.getWidgetRenderState(initOptions);
7411
+ if (renderState && renderState.widgetParams) {
7412
+ // casting, as we just earlier checked widgetParams exists, and thus an object
7413
+ widgetParams = renderState.widgetParams;
7414
+ }
7415
+ }
7416
+ // since we destructure in all widgets, the parameters with defaults are set to "undefined"
7417
+ var params = Object.keys(widgetParams).filter(function(key) {
7418
+ return widgetParams[key] !== undefined;
7419
+ });
7420
+ payload.widgets.push({
7421
+ type: widget.$$type,
7422
+ widgetType: widget.$$widgetType,
7423
+ params: params
7424
+ });
7425
+ if (isIndexWidget(widget)) {
7426
+ extractWidgetPayload(widget.getWidgets(), instantSearchInstance, payload, widget);
7427
+ }
7428
+ });
7429
+ }
7430
+
7431
+ var now = typeof performance !== 'undefined' ? function() {
7432
+ return performance.now();
7433
+ } : function() {
7434
+ return Date.now();
7435
+ };
7436
+
7437
+ function range(param) {
7438
+ var _param_start = param.start, start = _param_start === void 0 ? 0 : _param_start, end = param.end, _param_step = param.step, step = _param_step === void 0 ? 1 : _param_step;
7439
+ // We can't divide by 0 so we re-assign the step to 1 if it happens.
7440
+ var limitStep = step === 0 ? 1 : step;
7441
+ // In some cases the array to create has a decimal length.
7442
+ // We therefore need to round the value.
7443
+ // Example:
7444
+ // { start: 1, end: 5000, step: 500 }
7445
+ // => Array length = (5000 - 1) / 500 = 9.998
7446
+ var arrayLength = Math.round((end - start) / limitStep);
7447
+ return _to_consumable_array(Array(arrayLength)).map(function(_, current) {
7448
+ return start + current * limitStep;
7449
+ });
7450
+ }
7451
+
7321
7452
  function resolveSearchParameters(current) {
7322
7453
  var parent = current.getParent();
7323
7454
  var states = [
@@ -9029,6 +9160,8 @@
9029
9160
  });
9030
9161
  }
9031
9162
 
9163
+ var version = '4.105.0';
9164
+
9032
9165
  var ANONYMOUS_TOKEN_COOKIE_KEY = '_ALGOLIA';
9033
9166
  function getCookie(name) {
9034
9167
  if ((typeof document === "undefined" ? "undefined" : _type_of(document)) !== 'object' || typeof document.cookie !== 'string') {
@@ -9051,8 +9184,61 @@
9051
9184
  return getCookie(ANONYMOUS_TOKEN_COOKIE_KEY);
9052
9185
  }
9053
9186
 
9187
+ var USAGE_SESSION_KEY = 'ais.usage.sessionId';
9188
+ // Cache the id for the lifetime of the runtime so repeated calls don't hit
9189
+ // `sessionStorage` again, and so we always return the same id even when
9190
+ // storage is unavailable (SSR, privacy mode) and we fall back to a fresh UUID.
9191
+ var usageSessionId = null;
9192
+ function getUsageSessionId() {
9193
+ if (usageSessionId) {
9194
+ return usageSessionId;
9195
+ }
9196
+ try {
9197
+ var existing = sessionStorage.getItem(USAGE_SESSION_KEY);
9198
+ if (existing) {
9199
+ usageSessionId = existing;
9200
+ return usageSessionId;
9201
+ }
9202
+ usageSessionId = createUUID();
9203
+ sessionStorage.setItem(USAGE_SESSION_KEY, usageSessionId);
9204
+ return usageSessionId;
9205
+ } catch (unused) {
9206
+ // sessionStorage unavailable (SSR, privacy mode, etc.)
9207
+ usageSessionId = createUUID();
9208
+ return usageSessionId;
9209
+ }
9210
+ }
9211
+ /** @deprecated use bindEvent instead */ function writeDataAttributes(param) {
9212
+ var method = param.method, payload = param.payload;
9213
+ if ((typeof payload === "undefined" ? "undefined" : _type_of(payload)) !== 'object') {
9214
+ throw new Error("The insights helper expects the payload to be an object.");
9215
+ }
9216
+ var serializedPayload;
9217
+ try {
9218
+ serializedPayload = serializePayload(payload);
9219
+ } catch (error) {
9220
+ throw new Error("Could not JSON serialize the payload object.");
9221
+ }
9222
+ return 'data-insights-method="'.concat(method, '" data-insights-payload="').concat(serializedPayload, '"');
9223
+ }
9224
+ /**
9225
+ * @deprecated This function will be still supported in 4.x releases, but not further. It is replaced by the `insights` middleware. For more information, visit https://www.algolia.com/doc/guides/getting-insights-and-analytics/search-analytics/click-through-and-conversions/how-to/send-click-and-conversion-events-with-instantsearch/js/
9226
+ */ function insights(method, payload) {
9227
+ return writeDataAttributes({
9228
+ method: method,
9229
+ payload: payload
9230
+ });
9231
+ }
9232
+
9054
9233
  var ALGOLIA_INSIGHTS_VERSION = '2.17.2';
9055
9234
  var ALGOLIA_INSIGHTS_SRC = "https://cdn.jsdelivr.net/npm/search-insights@".concat(ALGOLIA_INSIGHTS_VERSION, "/dist/search-insights.min.js");
9235
+ // InstantSearch options that must never be sent in usage events because
9236
+ // they carry credentials or end-user data. Everything else is reported as-is.
9237
+ var SENSITIVE_OPTIONS = [
9238
+ 'searchClient',
9239
+ 'insightsClient',
9240
+ 'initialUiState'
9241
+ ];
9056
9242
  function createInsightsMiddleware() {
9057
9243
  var props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
9058
9244
  var _insightsClient = props.insightsClient, insightsInitParams = props.insightsInitParams, onEvent = props.onEvent, _props_$$internal = props.$$internal, $$internal = _props_$$internal === void 0 ? false : _props_$$internal, _props_$$automatic = props.$$automatic, $$automatic = _props_$$automatic === void 0 ? false : _props_$$automatic;
@@ -9142,6 +9328,7 @@
9142
9328
  }
9143
9329
  var initialParameters;
9144
9330
  var helper;
9331
+ var removeStartEventListener = null;
9145
9332
  return {
9146
9333
  $$type: 'ais.insights',
9147
9334
  $$internal: $$internal,
@@ -9316,8 +9503,65 @@
9316
9503
  insightsClientWithLocalCredentials(event.insightsMethod, event.payload);
9317
9504
  } else ;
9318
9505
  };
9506
+ // usage tracking (browser-only)
9507
+ safelyRunOnBrowser(function() {
9508
+ var usageSessionId = getUsageSessionId();
9509
+ function sendUsageEvent(event) {
9510
+ var _helper_state;
9511
+ var userToken = (_helper_state = helper.state) === null || _helper_state === void 0 ? void 0 : _helper_state.userToken;
9512
+ insightsClientWithLocalCredentials('sendEvents', [
9513
+ _object_spread({
9514
+ eventType: 'instantsearch',
9515
+ timestamp: Date.now(),
9516
+ sessionID: usageSessionId,
9517
+ userToken: userToken ? String(userToken) : undefined
9518
+ }, event)
9519
+ ]);
9520
+ }
9521
+ // Send the start event on the first `render`, by which point every
9522
+ // flavor has registered its widgets. `bootstrapMs` then measures the
9523
+ // time between the constructor running and that point, so for flavors
9524
+ // that register widgets right at start (e.g. React) it captures the
9525
+ // cost of adding them.
9526
+ var sendStartEvent = function sendStartEvent() {
9527
+ try {
9528
+ var bootstrapMs = Math.round(now() - instantSearchInstance._createdAt);
9529
+ sendUsageEvent({
9530
+ eventName: '__start__',
9531
+ algoliaAgent: getAlgoliaAgent(instantSearchInstance.client),
9532
+ version: version,
9533
+ applicationId: appId,
9534
+ performance: {
9535
+ bootstrapMs: bootstrapMs
9536
+ },
9537
+ widgets: [
9538
+ {
9539
+ type: 'ais.instantSearch',
9540
+ // The options the instance was created with, serialized the
9541
+ // same way every widget's params are. Derived dynamically from
9542
+ // `_initialOptions` so new options are reported automatically,
9543
+ // minus the keys that carry credentials or user data. Functions
9544
+ // (`onStateChange`, `searchFunction`) report their `fn.name`
9545
+ // when present, tagged `type: 'function'`.
9546
+ params: instantSearchInstance._initialOptions ? serializeWidgetParams(omit(instantSearchInstance._initialOptions, _to_consumable_array(SENSITIVE_OPTIONS))) : [],
9547
+ children: buildWidgetTree(instantSearchInstance.mainIndex.getWidgets(), instantSearchInstance)
9548
+ }
9549
+ ]
9550
+ });
9551
+ } catch (unused) {
9552
+ // usage tracking must never crash the host app
9553
+ }
9554
+ };
9555
+ instantSearchInstance.once('render', sendStartEvent);
9556
+ removeStartEventListener = function removeStartEventListener() {
9557
+ return instantSearchInstance.removeListener('render', sendStartEvent);
9558
+ };
9559
+ });
9319
9560
  },
9320
9561
  unsubscribe: function unsubscribe() {
9562
+ if (removeStartEventListener) {
9563
+ removeStartEventListener();
9564
+ }
9321
9565
  insightsClient('onUserTokenChange', undefined);
9322
9566
  instantSearchInstance.sendEventToInsights = noop;
9323
9567
  if (helper && initialParameters) {
@@ -9365,31 +9609,6 @@
9365
9609
  return typeof userToken === 'number' ? userToken.toString() : userToken;
9366
9610
  }
9367
9611
 
9368
- function extractWidgetPayload(widgets, instantSearchInstance, payload) {
9369
- var initOptions = createInitArgs(instantSearchInstance, instantSearchInstance.mainIndex, instantSearchInstance._initialUiState);
9370
- widgets.forEach(function(widget) {
9371
- var widgetParams = {};
9372
- if (widget.getWidgetRenderState) {
9373
- var renderState = widget.getWidgetRenderState(initOptions);
9374
- if (renderState && renderState.widgetParams) {
9375
- // casting, as we just earlier checked widgetParams exists, and thus an object
9376
- widgetParams = renderState.widgetParams;
9377
- }
9378
- }
9379
- // since we destructure in all widgets, the parameters with defaults are set to "undefined"
9380
- var params = Object.keys(widgetParams).filter(function(key) {
9381
- return widgetParams[key] !== undefined;
9382
- });
9383
- payload.widgets.push({
9384
- type: widget.$$type,
9385
- widgetType: widget.$$widgetType,
9386
- params: params
9387
- });
9388
- if (isIndexWidget(widget)) {
9389
- extractWidgetPayload(widget.getWidgets(), instantSearchInstance, payload);
9390
- }
9391
- });
9392
- }
9393
9612
  function isMetadataEnabled() {
9394
9613
  return safelyRunOnBrowser(function(param) {
9395
9614
  var window = param.window;
@@ -10738,28 +10957,6 @@
10738
10957
  return reverseHighlightedValue.replace(new RegExp(TAG_REPLACEMENT.highlightPreTag, 'g'), "<".concat(highlightedTagName, ' class="').concat(className, '">')).replace(new RegExp(TAG_REPLACEMENT.highlightPostTag, 'g'), "</".concat(highlightedTagName, ">"));
10739
10958
  }
10740
10959
 
10741
- /** @deprecated use bindEvent instead */ function writeDataAttributes(param) {
10742
- var method = param.method, payload = param.payload;
10743
- if ((typeof payload === "undefined" ? "undefined" : _type_of(payload)) !== 'object') {
10744
- throw new Error("The insights helper expects the payload to be an object.");
10745
- }
10746
- var serializedPayload;
10747
- try {
10748
- serializedPayload = serializePayload(payload);
10749
- } catch (error) {
10750
- throw new Error("Could not JSON serialize the payload object.");
10751
- }
10752
- return 'data-insights-method="'.concat(method, '" data-insights-payload="').concat(serializedPayload, '"');
10753
- }
10754
- /**
10755
- * @deprecated This function will be still supported in 4.x releases, but not further. It is replaced by the `insights` middleware. For more information, visit https://www.algolia.com/doc/guides/getting-insights-and-analytics/search-analytics/click-through-and-conversions/how-to/send-click-and-conversion-events-with-instantsearch/js/
10756
- */ function insights(method, payload) {
10757
- return writeDataAttributes({
10758
- method: method,
10759
- payload: payload
10760
- });
10761
- }
10762
-
10763
10960
  function hoganHelpers(param) {
10764
10961
  var numberLocale = param.numberLocale;
10765
10962
  return {
@@ -10821,8 +11018,6 @@
10821
11018
  };
10822
11019
  }
10823
11020
 
10824
- var version = '4.103.0';
10825
-
10826
11021
  var withUsage$r = createDocumentationMessageGenerator({
10827
11022
  name: 'instantsearch'
10828
11023
  });
@@ -10842,7 +11037,14 @@
10842
11037
  function InstantSearch(options) {
10843
11038
  _class_call_check(this, InstantSearch);
10844
11039
  var _this;
10845
- _this = _call_super(this, InstantSearch), _define_property(_this, "client", void 0), _define_property(_this, "indexName", void 0), _define_property(_this, "compositionID", void 0), _define_property(_this, "insightsClient", void 0), _define_property(_this, "onStateChange", null), _define_property(_this, "future", void 0), _define_property(_this, "helper", void 0), _define_property(_this, "mainHelper", void 0), _define_property(_this, "mainIndex", void 0), _define_property(_this, "started", void 0), _define_property(_this, "templatesConfig", void 0), _define_property(_this, "renderState", {}), _define_property(_this, "_stalledSearchDelay", void 0), _define_property(_this, "_searchStalledTimer", void 0), _define_property(_this, "_initialUiState", void 0), _define_property(_this, "_initialResults", void 0), _define_property(_this, "_manuallyResetScheduleSearch", false), _define_property(_this, "_resetScheduleSearch", void 0), _define_property(_this, "_createURL", void 0), _define_property(_this, "_searchFunction", void 0), _define_property(_this, "_mainHelperSearch", void 0), _define_property(_this, "_hasSearchWidget", false), _define_property(_this, "_hasRecommendWidget", false), _define_property(_this, "_insights", void 0), _define_property(_this, "middleware", []), _define_property(_this, "sendEventToInsights", void 0), /**
11040
+ _this = _call_super(this, InstantSearch), _define_property(_this, "client", void 0), _define_property(_this, "indexName", void 0), _define_property(_this, "compositionID", void 0), _define_property(_this, "insightsClient", void 0), _define_property(_this, "onStateChange", null), _define_property(_this, "future", void 0), _define_property(_this, "helper", void 0), _define_property(_this, "mainHelper", void 0), _define_property(_this, "mainIndex", void 0), _define_property(_this, "started", void 0), _define_property(_this, "templatesConfig", void 0), _define_property(_this, "renderState", {}), _define_property(_this, "_stalledSearchDelay", void 0), _define_property(_this, "_searchStalledTimer", void 0), _define_property(_this, "_initialUiState", void 0), _define_property(_this, "_initialResults", void 0), _define_property(_this, "_manuallyResetScheduleSearch", false), _define_property(_this, "_resetScheduleSearch", void 0), _define_property(_this, "_createURL", void 0), _define_property(_this, "_searchFunction", void 0), _define_property(_this, "_mainHelperSearch", void 0), _define_property(_this, "_hasSearchWidget", false), _define_property(_this, "_hasRecommendWidget", false), _define_property(_this, "_insights", void 0), /**
11041
+ * The options the instance was created with, kept verbatim so consumers
11042
+ * (e.g. usage events) can introspect the configuration without the class
11043
+ * having to enumerate every option by hand. Typed without the class generics
11044
+ * on purpose: referencing `TUiState`/`TRouteState` here (they sit in
11045
+ * contravariant positions inside `InstantSearchOptions`) would break the
11046
+ * assignability of `InstantSearch<SpecificUiState>` to `InstantSearch`.
11047
+ */ _define_property(_this, "_initialOptions", void 0), _define_property(_this, "middleware", []), _define_property(_this, "sendEventToInsights", void 0), _define_property(_this, "_createdAt", now()), /**
10846
11048
  * The status of the search. Can be "idle", "loading", "stalled", or "error".
10847
11049
  */ _define_property(_this, "status", 'idle'), /**
10848
11050
  * The last returned error from the Search API.
@@ -10890,6 +11092,7 @@
10890
11092
  if (insightsClient && typeof insightsClient !== 'function') {
10891
11093
  throw new Error(withUsage$r('The `insightsClient` option should be a function.'));
10892
11094
  }
11095
+ _this._initialOptions = options;
10893
11096
  _this.client = searchClient;
10894
11097
  _this.future = future;
10895
11098
  _this.insightsClient = insightsClient;
@@ -11262,6 +11465,9 @@
11262
11465
  var instance = param.instance;
11263
11466
  instance.unsubscribe();
11264
11467
  });
11468
+ // Cleared after unsubscribe so in-flight readers (e.g. the insights
11469
+ // start-event listener) have detached before the reference goes away.
11470
+ this._initialOptions = null;
11265
11471
  }
11266
11472
  },
11267
11473
  {
@@ -13884,12 +14090,10 @@
13884
14090
  var _chatInstance;
13885
14091
  var input = '';
13886
14092
  var open = false;
13887
- var isClearing = false;
13888
14093
  var sendEvent;
13889
14094
  var setInput;
13890
14095
  var setOpen;
13891
14096
  var focusInput;
13892
- var setIsClearing;
13893
14097
  var setFeedbackState;
13894
14098
  var hasValidatedEntryPoints = false;
13895
14099
  var agentId = 'agentId' in options ? options.agentId : undefined;
@@ -13919,21 +14123,17 @@
13919
14123
  _chatInstance.messages = messagesParam;
13920
14124
  };
13921
14125
  var clearMessages = function clearMessages() {
13922
- if (!_chatInstance.messages || _chatInstance.messages.length === 0) {
13923
- return;
13924
- }
13925
14126
  var status = _chatInstance.status;
13926
14127
  if (status === 'submitted' || status === 'streaming') {
13927
14128
  _chatInstance.stop();
13928
14129
  }
13929
- setIsClearing(true);
13930
- };
13931
- var onClearTransitionEnd = function onClearTransitionEnd() {
14130
+ // Reset the non-reactive state first: `setMessages` and `clearError` emit
14131
+ // ChatState callbacks that synchronously re-render, so they must run last
14132
+ // for that render to see the cleared feedback and rotated conversation id.
14133
+ feedbackState = {};
14134
+ _chatInstance.resetConversationId();
13932
14135
  setMessages([]);
13933
14136
  _chatInstance.clearError();
13934
- _chatInstance.resetConversationId();
13935
- feedbackState = {};
13936
- setIsClearing(false);
13937
14137
  };
13938
14138
  var validateEntryPoints = function validateEntryPoints(instantSearchInstance) {
13939
14139
  if (disableTriggerValidation || hasValidatedEntryPoints) {
@@ -13999,22 +14199,37 @@
13999
14199
  }));
14000
14200
  }
14001
14201
  if ('agentId' in options && options.agentId) {
14202
+ var _options_requestOptions, _options_requestOptions1;
14002
14203
  if (!appId || !apiKey) {
14003
14204
  throw new Error(withUsage$o('Could not extract Algolia credentials from the search client.'));
14004
14205
  }
14005
- var baseApi = "https://".concat(appId, ".algolia.net/agent-studio/1/agents/").concat(agentId, "/completions?compatibilityMode=ai-sdk-5");
14206
+ var createApi = function createApi() {
14207
+ var bypassCache = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
14208
+ var _options_requestOptions;
14209
+ var api = new URL("https://".concat(appId, ".algolia.net/agent-studio/1/agents/").concat(agentId, "/completions"));
14210
+ var queryParameters = _object_spread(_object_spread_props(_object_spread({}, (_options_requestOptions = options.requestOptions) === null || _options_requestOptions === void 0 ? void 0 : _options_requestOptions.queryParameters), {
14211
+ compatibilityMode: 'ai-sdk-5'
14212
+ }), bypassCache ? {
14213
+ cache: false
14214
+ } : {});
14215
+ api.search = new URLSearchParams(queryParameters).toString();
14216
+ return api.toString();
14217
+ };
14218
+ var baseApi = createApi();
14006
14219
  transport = new DefaultChatTransport({
14007
14220
  api: baseApi,
14008
- headers: {
14221
+ headers: _object_spread_props(_object_spread({}, _instanceof((_options_requestOptions = options.requestOptions) === null || _options_requestOptions === void 0 ? void 0 : _options_requestOptions.headers, Headers) ? Object.fromEntries(options.requestOptions.headers.entries()) : (_options_requestOptions1 = options.requestOptions) === null || _options_requestOptions1 === void 0 ? void 0 : _options_requestOptions1.headers), {
14222
+ // Preserve the required Algolia identity headers and chat agent
14223
+ // marker, even when requestOptions.headers contains the same keys.
14009
14224
  'x-algolia-application-id': appId,
14010
14225
  'x-algolia-api-key': apiKey,
14011
14226
  'x-algolia-agent': "".concat(getAlgoliaAgent(client), "; chat")
14012
- },
14227
+ }),
14013
14228
  prepareSendMessagesRequest: function prepareSendMessagesRequest(param) {
14014
14229
  var id = param.id, messages = param.messages, trigger = param.trigger, messageId = param.messageId;
14015
14230
  return {
14016
14231
  // Bypass cache when regenerating to ensure fresh responses
14017
- api: trigger === 'regenerate-message' ? "".concat(baseApi, "&cache=false") : baseApi,
14232
+ api: trigger === 'regenerate-message' ? createApi(true) : baseApi,
14018
14233
  body: {
14019
14234
  id: id,
14020
14235
  messageId: messageId,
@@ -14099,10 +14314,6 @@
14099
14314
  input = i;
14100
14315
  render();
14101
14316
  };
14102
- setIsClearing = function setIsClearing(value) {
14103
- isClearing = value;
14104
- render();
14105
- };
14106
14317
  setFeedbackState = function setFeedbackState(messageId, state) {
14107
14318
  feedbackState = _object_spread_props(_object_spread({}, feedbackState), _define_property({}, messageId, state));
14108
14319
  render();
@@ -14221,9 +14432,7 @@
14221
14432
  focusInput: focusInput,
14222
14433
  setMessages: setMessages,
14223
14434
  suggestions: getSuggestionsFromMessages(_chatInstance.messages),
14224
- isClearing: isClearing,
14225
14435
  clearMessages: clearMessages,
14226
- onClearTransitionEnd: onClearTransitionEnd,
14227
14436
  tools: toolsWithAddToolResult,
14228
14437
  sendChatMessageFeedback: _sendChatMessageFeedback,
14229
14438
  feedbackState: feedbackState,
@@ -20448,9 +20657,8 @@
20448
20657
  Fragment: Fragment
20449
20658
  });
20450
20659
  // Skip re-rendering (and re-compiling the markdown of) completed messages on
20451
- // every streaming delta. Falls back to the plain component when the host
20452
- // renderer doesn't provide a `memo` HOC.
20453
- var MemoizedDefaultMessage = memo ? memo(DefaultMessageComponent, areMessagePropsEqual) : DefaultMessageComponent;
20660
+ // every streaming delta.
20661
+ var MemoizedDefaultMessage = memo(DefaultMessageComponent, areMessagePropsEqual);
20454
20662
  var DefaultLoaderComponent = createChatMessageLoaderComponent({
20455
20663
  createElement: createElement
20456
20664
  });
@@ -20827,8 +21035,11 @@
20827
21035
  };
20828
21036
  }
20829
21037
 
21038
+ function prefersReducedMotion() {
21039
+ return typeof window !== 'undefined' && typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
21040
+ }
20830
21041
  function createChatComponent(param) {
20831
- var createElement = param.createElement, Fragment = param.Fragment, memo = param.memo;
21042
+ var createElement = param.createElement, Fragment = param.Fragment, memo = param.memo, useState = param.useState;
20832
21043
  var ChatHeader = createChatHeaderComponent({
20833
21044
  createElement: createElement,
20834
21045
  Fragment: Fragment
@@ -20869,11 +21080,38 @@
20869
21080
  "stop",
20870
21081
  "error"
20871
21082
  ]);
21083
+ var _useState = _sliced_to_array(useState(false), 2), isClearing = _useState[0], setIsClearing = _useState[1];
21084
+ var commitClear = headerProps.onClear || messagesProps.onNewConversation;
21085
+ var startClear = function startClear() {
21086
+ if (!commitClear) {
21087
+ return;
21088
+ }
21089
+ // Reduced motion disables the transition, so `transitionend` never fires;
21090
+ // commit immediately instead of waiting for it.
21091
+ if (prefersReducedMotion()) {
21092
+ commitClear();
21093
+ return;
21094
+ }
21095
+ // Stop streaming now so the assistant stops immediately, not after the fade.
21096
+ if (messagesProps.status === 'submitted' || messagesProps.status === 'streaming') {
21097
+ stop();
21098
+ }
21099
+ setIsClearing(true);
21100
+ };
21101
+ var finishClear = function finishClear() {
21102
+ commitClear === null || commitClear === void 0 ? void 0 : commitClear();
21103
+ setIsClearing(false);
21104
+ };
20872
21105
  var headerComponent = createElement(HeaderComponent || ChatHeader, _object_spread_props(_object_spread({}, headerProps), {
21106
+ onClear: commitClear ? startClear : headerProps.onClear,
21107
+ canClear: headerProps.canClear && !isClearing,
20873
21108
  classNames: classNames.header,
20874
21109
  maximized: maximized
20875
21110
  }));
20876
21111
  var messagesComponent = /*#__PURE__*/ createElement(ChatMessages, _object_spread_props(_object_spread({}, messagesProps), {
21112
+ isClearing: isClearing,
21113
+ onClearTransitionEnd: finishClear,
21114
+ onNewConversation: commitClear ? startClear : messagesProps.onNewConversation,
20877
21115
  error: error,
20878
21116
  classNames: classNames.messages,
20879
21117
  messageClassNames: classNames.message,
@@ -20898,9 +21136,9 @@
20898
21136
  messages: messagesProps.messages,
20899
21137
  status: messagesProps.status,
20900
21138
  tools: messagesProps.tools,
20901
- isClearing: messagesProps.isClearing,
20902
- clearMessages: headerProps.onClear,
20903
- onClearTransitionEnd: messagesProps.onClearTransitionEnd,
21139
+ isClearing: isClearing,
21140
+ clearMessages: commitClear ? startClear : headerProps.onClear,
21141
+ onClearTransitionEnd: finishClear,
20904
21142
  suggestions: suggestionsProps.suggestions,
20905
21143
  sendMessage: sendMessage,
20906
21144
  regenerate: regenerate,
@@ -23395,7 +23633,8 @@
23395
23633
  var ChatUiComponent = createChatComponent({
23396
23634
  createElement: React.createElement,
23397
23635
  Fragment: React.Fragment,
23398
- memo: React.memo
23636
+ memo: React.memo,
23637
+ useState: React.useState
23399
23638
  });
23400
23639
  function createDefaultTools(itemComponent, getSearchPageURL) {
23401
23640
  var _obj;
@@ -23460,7 +23699,7 @@
23460
23699
  tools: tools,
23461
23700
  disableTriggerValidation: effectiveDisableTriggerValidation
23462
23701
  }));
23463
- var messages = chatState.messages, sendMessage = chatState.sendMessage, status = chatState.status, regenerate = chatState.regenerate, stop = chatState.stop, error = chatState.error, input = chatState.input, setInput = chatState.setInput, open = chatState.open, setOpen = chatState.setOpen, isClearing = chatState.isClearing, clearMessages = chatState.clearMessages, onClearTransitionEnd = chatState.onClearTransitionEnd, toolsFromConnector = chatState.tools, suggestions = chatState.suggestions, onFeedback = chatState.sendChatMessageFeedback, feedbackState = chatState.feedbackState;
23702
+ var messages = chatState.messages, sendMessage = chatState.sendMessage, status = chatState.status, regenerate = chatState.regenerate, stop = chatState.stop, error = chatState.error, input = chatState.input, setInput = chatState.setInput, open = chatState.open, setOpen = chatState.setOpen, clearMessages = chatState.clearMessages, toolsFromConnector = chatState.tools, suggestions = chatState.suggestions, onFeedback = chatState.sendChatMessageFeedback, feedbackState = chatState.feedbackState;
23464
23703
  React.useImperativeHandle(ref, function() {
23465
23704
  return {
23466
23705
  setOpen: setOpen,
@@ -23524,7 +23763,7 @@
23524
23763
  return setMaximized(!maximized);
23525
23764
  },
23526
23765
  onClear: clearMessages,
23527
- canClear: Boolean(messages === null || messages === void 0 ? void 0 : messages.length) && !isClearing,
23766
+ canClear: Boolean(messages === null || messages === void 0 ? void 0 : messages.length),
23528
23767
  titleIconComponent: headerTitleIconComponent,
23529
23768
  closeIconComponent: headerCloseIconComponent,
23530
23769
  minimizeIconComponent: headerMinimizeIconComponent,
@@ -23550,8 +23789,6 @@
23550
23789
  tools: toolsFromConnector,
23551
23790
  indexUiState: indexUiState,
23552
23791
  setIndexUiState: setIndexUiState,
23553
- isClearing: isClearing,
23554
- onClearTransitionEnd: onClearTransitionEnd,
23555
23792
  isScrollAtBottom: isAtBottom,
23556
23793
  scrollRef: scrollRef,
23557
23794
  contentRef: contentRef,
@@ -23806,7 +24043,10 @@
23806
24043
  "isShowingMore",
23807
24044
  "translations"
23808
24045
  ]);
23809
- return /*#__PURE__*/ React.createElement("button", props, translations.showMoreButtonText({
24046
+ return /*#__PURE__*/ React.createElement("button", _object_spread_props(_object_spread({}, props), {
24047
+ "aria-expanded": isShowingMore,
24048
+ "aria-label": translations.showMoreButtonLabel
24049
+ }), translations.showMoreButtonText({
23810
24050
  isShowingMore: isShowingMore
23811
24051
  }));
23812
24052
  }
@@ -24336,6 +24576,7 @@
24336
24576
  currentPage: page + 1,
24337
24577
  nbPages: nbPages
24338
24578
  }),
24579
+ "aria-current": page === currentPage ? 'page' : undefined,
24339
24580
  href: createURL(page),
24340
24581
  onClick: function onClick() {
24341
24582
  return onNavigate(page);
@@ -24804,13 +25045,15 @@
24804
25045
  })), /*#__PURE__*/ React.createElement("button", {
24805
25046
  className: cx('ais-SearchBox-submit', classNames.submit),
24806
25047
  type: "submit",
24807
- title: translations.submitButtonTitle
25048
+ title: translations.submitButtonTitle,
25049
+ "aria-label": translations.submitButtonTitle
24808
25050
  }, /*#__PURE__*/ React.createElement(SubmitIcon, {
24809
25051
  classNames: classNames
24810
25052
  })), /*#__PURE__*/ React.createElement("button", {
24811
25053
  className: cx('ais-SearchBox-reset', classNames.reset),
24812
25054
  type: "reset",
24813
25055
  title: translations.resetButtonTitle,
25056
+ "aria-label": translations.resetButtonTitle,
24814
25057
  hidden: value.length === 0 || isSearchStalled
24815
25058
  }, /*#__PURE__*/ React.createElement(ResetIcon, {
24816
25059
  classNames: classNames
@@ -24922,7 +25165,8 @@
24922
25165
  onToggleShowMore: toggleShowMore,
24923
25166
  isShowingMore: isShowingMore,
24924
25167
  translations: {
24925
- showMoreButtonText: mergedTranslations.showMoreButtonText
25168
+ showMoreButtonText: mergedTranslations.showMoreButtonText,
25169
+ showMoreButtonLabel: translations === null || translations === void 0 ? void 0 : translations.showMoreButtonLabel
24926
25170
  }
24927
25171
  };
24928
25172
  return /*#__PURE__*/ React.createElement(RefinementList$1, _object_spread_props(_object_spread({}, props, uiProps), {
@@ -25146,6 +25390,21 @@
25146
25390
  return /*#__PURE__*/ React.createElement(SortBy$1, _object_spread({}, props, uiProps));
25147
25391
  }
25148
25392
 
25393
+ // Delay before announcing an update, so that rapid changes (e.g. typing in the
25394
+ // search box) settle into a single announcement instead of piling up. Mirrors
25395
+ // the debounce used by GOV.UK's accessible-autocomplete.
25396
+ var ANNOUNCEMENT_DELAY = 1400;
25397
+ var visuallyHiddenStyle = {
25398
+ position: 'absolute',
25399
+ width: 1,
25400
+ height: 1,
25401
+ padding: 0,
25402
+ margin: -1,
25403
+ overflow: 'hidden',
25404
+ clip: 'rect(0, 0, 0, 0)',
25405
+ whiteSpace: 'nowrap',
25406
+ border: 0
25407
+ };
25149
25408
  function Stats$1(_0) {
25150
25409
  var _0_classNames = _0.classNames, classNames = _0_classNames === void 0 ? {} : _0_classNames, nbHits = _0.nbHits, processingTimeMS = _0.processingTimeMS, nbSortedHits = _0.nbSortedHits, areHitsSorted = _0.areHitsSorted, translations = _0.translations, props = _object_without_properties(_0, [
25151
25410
  "classNames",
@@ -25161,11 +25420,37 @@
25161
25420
  nbSortedHits: nbSortedHits,
25162
25421
  areHitsSorted: areHitsSorted
25163
25422
  };
25423
+ var nextAnnouncement = translations.announcementText ? translations.announcementText(translationOptions) : '';
25424
+ var _useState = _sliced_to_array(React.useState(''), 2), announcement = _useState[0], setAnnouncement = _useState[1];
25425
+ var timerRef = React.useRef(undefined);
25426
+ var isInitialRef = React.useRef(true);
25427
+ React.useEffect(function() {
25428
+ // Don't announce the initial results, only subsequent changes.
25429
+ if (isInitialRef.current) {
25430
+ isInitialRef.current = false;
25431
+ return undefined;
25432
+ }
25433
+ clearTimeout(timerRef.current);
25434
+ timerRef.current = setTimeout(function() {
25435
+ setAnnouncement(nextAnnouncement);
25436
+ }, ANNOUNCEMENT_DELAY);
25437
+ return function() {
25438
+ return clearTimeout(timerRef.current);
25439
+ };
25440
+ }, [
25441
+ nextAnnouncement
25442
+ ]);
25164
25443
  return /*#__PURE__*/ React.createElement("div", _object_spread_props(_object_spread({}, props), {
25165
25444
  className: cx('ais-Stats', classNames.root, props.className)
25166
25445
  }), /*#__PURE__*/ React.createElement("span", {
25167
25446
  className: "ais-Stats-text"
25168
- }, translations.rootElementText(translationOptions)));
25447
+ }, translations.rootElementText(translationOptions)), /*#__PURE__*/ React.createElement("span", {
25448
+ className: "ais-Stats-announcement",
25449
+ role: "status",
25450
+ "aria-live": "polite",
25451
+ "aria-atomic": "true",
25452
+ style: visuallyHiddenStyle
25453
+ }, announcement));
25169
25454
  }
25170
25455
 
25171
25456
  function Stats(_0) {
@@ -25183,6 +25468,9 @@
25183
25468
  translations: _object_spread({
25184
25469
  rootElementText: function rootElementText(options) {
25185
25470
  return "".concat(options.areHitsSorted ? getSortedResultsSentence(options) : getResultsSentence(options), " found in ").concat(options.processingTimeMS.toLocaleString(), "ms");
25471
+ },
25472
+ announcementText: function announcementText(options) {
25473
+ return options.areHitsSorted ? getSortedResultsSentence(options) : getResultsSentence(options);
25186
25474
  }
25187
25475
  }, translations)
25188
25476
  };