@cognigy/webchat 3.50.0 → 3.52.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,7 +1,7 @@
1
1
  /*!
2
- * webchat.esm.js v3.50.0
3
- * https://github.com/Cognigy/Webchat/tree/v3.50.0
4
- * https://github.com/Cognigy/Webchat/tree/v3.50.0/OSS_LICENSES.txt
2
+ * webchat.esm.js v3.52.0
3
+ * https://github.com/Cognigy/Webchat/tree/v3.52.0
4
+ * https://github.com/Cognigy/Webchat/tree/v3.52.0/OSS_LICENSES.txt
5
5
  */
6
6
  import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react";
7
7
  import * as __WEBPACK_EXTERNAL_MODULE_react_dom_7dac9eee__ from "react-dom";
@@ -35390,17 +35390,19 @@ const DeleteConfirmModal = props => {
35390
35390
  cancelButtonBackground,
35391
35391
  confirmButtonBackground
35392
35392
  } = props;
35393
+
35394
+ // Focus the safe default (Cancel) action via the Modal's deferred focus
35395
+ // path, not React's autoFocus: autoFocus fires in the same task that
35396
+ // inserts the dialog subtree, and VoiceOver then reads a stale
35397
+ // accessibility tree — the dialog role/title and the focused button are
35398
+ // never announced (CGY-3274). The deferral lets the tree settle first.
35399
+ const cancelButtonRef = react__WEBPACK_IMPORTED_MODULE_0__["default"].useRef(null);
35393
35400
  return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_Modal__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A, {
35394
35401
  footer: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(react__WEBPACK_IMPORTED_MODULE_0__["default"].Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(CancelButton, {
35402
+ ref: cancelButtonRef,
35395
35403
  className: "webchat-delete-confirmation-cancel-button",
35396
35404
  onClick: () => onClose(false),
35397
35405
  background: cancelButtonBackground
35398
- // Intentional: move focus to the safe default (Cancel) action
35399
- // when this confirmation modal opens — expected dialog focus
35400
- // management, not an unexpected focus shift.
35401
- // eslint-disable-next-line jsx-a11y/no-autofocus
35402
- ,
35403
- autoFocus: true
35404
35406
  }, cancelText), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(DeleteConfirmation, {
35405
35407
  className: "webchat-delete-confirmation-confirm-button",
35406
35408
  onClick: onConfirmDelete,
@@ -35408,7 +35410,8 @@ const DeleteConfirmModal = props => {
35408
35410
  }, confirmText)),
35409
35411
  isOpen: isOpen,
35410
35412
  onClose: onClose,
35411
- title: title
35413
+ title: title,
35414
+ initialFocusRef: cancelButtonRef
35412
35415
  }, children);
35413
35416
  };
35414
35417
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (DeleteConfirmModal);
@@ -35774,21 +35777,23 @@ const Modal = ({
35774
35777
  /* harmony import */ var _plugins_input_file_DropZone__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(1339);
35775
35778
  /* harmony import */ var react_transition_group__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(66492);
35776
35779
  /* harmony import */ var _presentational_TeaserMessage__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(49888);
35777
- /* harmony import */ var _functional_xapp_overlay_XAppOverlay__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(12381);
35778
- /* harmony import */ var _utils_sourceMapping__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(25091);
35779
- /* harmony import */ var _plugins_speech_output__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(83679);
35780
- /* harmony import */ var _utils_filter_out_control_commands__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(70562);
35781
- /* harmony import */ var _utils_isMobile__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(40794);
35782
- /* harmony import */ var _webchat_helper_handleMarkdown__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(71621);
35783
- /* harmony import */ var _presentational_previous_conversations_DeleteAllConversations__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(5196);
35784
- /* harmony import */ var _presentational_ScreenReaderLiveRegion__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(41426);
35785
- /* harmony import */ var _presentational_StatusLiveRegion__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(63813);
35786
- /* harmony import */ var _presentational_FreezeOnExit__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(97475);
35787
- /* harmony import */ var _presentational_HomeScreenAnnouncer__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(55115);
35788
- /* harmony import */ var _utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(39191);
35789
- /* harmony import */ var _utils_screen_visibility__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(48245);
35790
- /* harmony import */ var classnames__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(14176);
35791
- /* harmony import */ var classnames__WEBPACK_IMPORTED_MODULE_56___default = /*#__PURE__*/__webpack_require__.n(classnames__WEBPACK_IMPORTED_MODULE_56__);
35780
+ /* harmony import */ var _presentational_TeaserMessageAnnouncer__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(59359);
35781
+ /* harmony import */ var _presentational_UnreadMessagesAnnouncer__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(1715);
35782
+ /* harmony import */ var _functional_xapp_overlay_XAppOverlay__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(12381);
35783
+ /* harmony import */ var _utils_sourceMapping__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(25091);
35784
+ /* harmony import */ var _plugins_speech_output__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(83679);
35785
+ /* harmony import */ var _utils_filter_out_control_commands__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(70562);
35786
+ /* harmony import */ var _utils_isMobile__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(40794);
35787
+ /* harmony import */ var _webchat_helper_handleMarkdown__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(71621);
35788
+ /* harmony import */ var _presentational_previous_conversations_DeleteAllConversations__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(5196);
35789
+ /* harmony import */ var _presentational_ScreenReaderLiveRegion__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(41426);
35790
+ /* harmony import */ var _presentational_StatusLiveRegion__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(63813);
35791
+ /* harmony import */ var _presentational_FreezeOnExit__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(97475);
35792
+ /* harmony import */ var _presentational_HomeScreenAnnouncer__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(55115);
35793
+ /* harmony import */ var _utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(39191);
35794
+ /* harmony import */ var _utils_screen_visibility__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(48245);
35795
+ /* harmony import */ var classnames__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(14176);
35796
+ /* harmony import */ var classnames__WEBPACK_IMPORTED_MODULE_58___default = /*#__PURE__*/__webpack_require__.n(classnames__WEBPACK_IMPORTED_MODULE_58__);
35792
35797
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
35793
35798
 
35794
35799
 
@@ -35844,6 +35849,8 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
35844
35849
 
35845
35850
 
35846
35851
 
35852
+
35853
+
35847
35854
 
35848
35855
 
35849
35856
 
@@ -35949,7 +35956,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
35949
35956
  deleteConversationsModalState: false,
35950
35957
  liveContent: {},
35951
35958
  isMobile: false,
35952
- noticeSession: _utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_54__/* .INITIAL_NOTICE_SESSION */ .j_
35959
+ noticeSession: _utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_56__/* .INITIAL_NOTICE_SESSION */ .j_
35953
35960
  };
35954
35961
  unreadTitleIndicatorInterval = null;
35955
35962
  originalTitle = window.document.title;
@@ -35960,6 +35967,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
35960
35967
  engagementMessageTimeout = null;
35961
35968
  ratingFocusTimeout = null;
35962
35969
  homeScreenExitFocusTimeout = null;
35970
+ xAppOverlayCloseFocusTimeout = null;
35963
35971
 
35964
35972
  // Disarms the pending home-screen exit focus fallback. Also registered as
35965
35973
  // a capture-phase document pointerdown listener while the fallback is
@@ -35997,9 +36005,9 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
35997
36005
  const secondaryColor = props?.config?.settings?.colors?.secondaryColor;
35998
36006
  const chatInterfaceColor = props?.config?.settings?.colors?.chatInterfaceColor;
35999
36007
  const sourceColorMapping = props?.config?.settings?.widgetSettings?.sourceColorMapping;
36000
- const overrideBotMessageColor = (0,_utils_sourceMapping__WEBPACK_IMPORTED_MODULE_44__/* .getSourceBackgroundColor */ .N)(sourceColorMapping?.bot, props?.config?.settings?.colors);
36001
- const overrideUserMessageColor = (0,_utils_sourceMapping__WEBPACK_IMPORTED_MODULE_44__/* .getSourceBackgroundColor */ .N)(sourceColorMapping?.user, props?.config?.settings?.colors);
36002
- const overrideAgentMessageColor = (0,_utils_sourceMapping__WEBPACK_IMPORTED_MODULE_44__/* .getSourceBackgroundColor */ .N)(sourceColorMapping?.agent, props?.config?.settings?.colors);
36008
+ const overrideBotMessageColor = (0,_utils_sourceMapping__WEBPACK_IMPORTED_MODULE_46__/* .getSourceBackgroundColor */ .N)(sourceColorMapping?.bot, props?.config?.settings?.colors);
36009
+ const overrideUserMessageColor = (0,_utils_sourceMapping__WEBPACK_IMPORTED_MODULE_46__/* .getSourceBackgroundColor */ .N)(sourceColorMapping?.user, props?.config?.settings?.colors);
36010
+ const overrideAgentMessageColor = (0,_utils_sourceMapping__WEBPACK_IMPORTED_MODULE_46__/* .getSourceBackgroundColor */ .N)(sourceColorMapping?.agent, props?.config?.settings?.colors);
36003
36011
  const overrideBotMessageBorderColor = sourceColorMapping?.bot === "user" ? "transparent" : null;
36004
36012
  const overrideUserMessageBorderColor = sourceColorMapping?.user === "bot" ? state.theme.black80 : null;
36005
36013
  const overrideAgentMessageBorderColor = sourceColorMapping?.agent === "user" ? "transparent" : null;
@@ -36103,14 +36111,14 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36103
36111
  evaluateNoticeSession(prevConversationsSnapshot) {
36104
36112
  const id = this.props.currentSession || "";
36105
36113
  this.setState(prev => ({
36106
- noticeSession: (0,_utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_54__/* .computeNoticeSession */ .Kr)(prev.noticeSession, id, prevConversationsSnapshot, this.props.hasRestoredPersistedHistory)
36114
+ noticeSession: (0,_utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_56__/* .computeNoticeSession */ .Kr)(prev.noticeSession, id, prevConversationsSnapshot, this.props.hasRestoredPersistedHistory, this.props.willRestorePersistedConversation)
36107
36115
  }));
36108
36116
  }
36109
36117
  handleNoticeIntroAnnounced = introKey => {
36110
36118
  this.announcedNoticeKeys.add(introKey);
36111
36119
  };
36112
36120
  getNoticeIntro() {
36113
- const text = (0,_utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_54__/* .getAIAgentNoticeIntroText */ .bu)({
36121
+ const text = (0,_utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_56__/* .getAIAgentNoticeIntroText */ .bu)({
36114
36122
  behavior: this.props.config.settings.behavior,
36115
36123
  showDisconnectOverlay: this.showDisconnectOverlay,
36116
36124
  noticeSession: this.state.noticeSession,
@@ -36126,12 +36134,12 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36126
36134
  componentDidMount() {
36127
36135
  const defaultMessagePlugins = [];
36128
36136
  if (this.props.ttsActive) {
36129
- defaultMessagePlugins.push(_plugins_speech_output__WEBPACK_IMPORTED_MODULE_45__/* ["default"] */ .A);
36137
+ defaultMessagePlugins.push(_plugins_speech_output__WEBPACK_IMPORTED_MODULE_47__/* ["default"] */ .A);
36130
36138
  }
36131
36139
  this.setState({
36132
36140
  inputPlugins: [...(this.props.inputPlugins || []), _plugins_input_base__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .A],
36133
36141
  messagePlugins: [...(this.props.messagePlugins || []), ...defaultMessagePlugins],
36134
- isMobile: (0,_utils_isMobile__WEBPACK_IMPORTED_MODULE_47__/* .isMobileViewport */ .$)()
36142
+ isMobile: (0,_utils_isMobile__WEBPACK_IMPORTED_MODULE_49__/* .isMobileViewport */ .$)()
36135
36143
  });
36136
36144
  this.setupIconAnimationInterval();
36137
36145
 
@@ -36203,13 +36211,53 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36203
36211
  }
36204
36212
  }, 450);
36205
36213
  }
36214
+
36215
+ // Closing the xApp overlay unmounts the dialog together with whatever
36216
+ // was focused in it (its close button, or the frame), and the screen it
36217
+ // covered re-mounts — so focus cannot be "restored" to a surviving
36218
+ // element and would drop to document.body (SC 2.4.3). The chat screen
36219
+ // re-focuses itself via the message input's 200ms autofocus; when that
36220
+ // is disabled (`disableInputAutofocus`), or for any other view, this
36221
+ // late check moves focus to the re-mounted header title, mirroring the
36222
+ // home-screen exit fallback above. It never overrides focus that
36223
+ // landed anywhere else.
36224
+ if (prevProps.isXAppOverlayOpen && !this.props.isXAppOverlayOpen) {
36225
+ if (this.xAppOverlayCloseFocusTimeout) clearTimeout(this.xAppOverlayCloseFocusTimeout);
36226
+ this.xAppOverlayCloseFocusTimeout = setTimeout(() => {
36227
+ this.xAppOverlayCloseFocusTimeout = null;
36228
+ const webchatWindowEl = this.webchatWindowRef?.current;
36229
+ if (!webchatWindowEl) return;
36230
+ const active = document.activeElement;
36231
+ if (active === document.body || active === null) {
36232
+ (webchatWindowEl.querySelector(".webchat-header-bar .webchat-header-title") ?? (0,_utils_find_focusable__WEBPACK_IMPORTED_MODULE_23__/* ["default"] */ .A)(webchatWindowEl).firstFocusable)?.focus();
36233
+ }
36234
+ }, 450);
36235
+ }
36206
36236
  if (prevProps.currentSession !== this.props.currentSession) {
36207
36237
  this.evaluateNoticeSession(prevProps.prevConversations);
36208
36238
  }
36239
+
36240
+ // The persisted-conversation prediction is read from storage under a
36241
+ // key that contains the endpoint config's URLToken, so it only
36242
+ // becomes meaningful once that config has loaded — after this
36243
+ // component has already mounted. Re-evaluating on the flip is in
36244
+ // time for every case the notice can observe, and normally with
36245
+ // room to spare: `open()` waits for the config before showing
36246
+ // anything, and even if it gives up waiting (~1s by default, then
36247
+ // it opens regardless) the flip still lands within the intro's own
36248
+ // 600ms delay and its effect cleanup cancels the pending timer. A
36249
+ // config slower than roughly the sum of the two would let the
36250
+ // notice announce before the prediction arrives — the remaining
36251
+ // gap, and the reason the notice is not gated on the connect on
36252
+ // top of this. No session id exists yet at this point, so current
36253
+ // props are the pre-change snapshot.
36254
+ if (prevProps.willRestorePersistedConversation !== this.props.willRestorePersistedConversation && !this.props.currentSession) {
36255
+ this.evaluateNoticeSession(this.props.prevConversations);
36256
+ }
36209
36257
  if (prevProps.ttsActive !== this.props.ttsActive || prevProps.inputPlugins !== this.props.inputPlugins || prevProps.messagePlugins !== this.props.messagePlugins) {
36210
36258
  const defaultMessagePlugins = [];
36211
36259
  if (this.props.ttsActive) {
36212
- defaultMessagePlugins.push(_plugins_speech_output__WEBPACK_IMPORTED_MODULE_45__/* ["default"] */ .A);
36260
+ defaultMessagePlugins.push(_plugins_speech_output__WEBPACK_IMPORTED_MODULE_47__/* ["default"] */ .A);
36213
36261
  }
36214
36262
  this.setState({
36215
36263
  inputPlugins: [...(this.props.inputPlugins || []), _plugins_input_base__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .A],
@@ -36259,7 +36307,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36259
36307
  // TODO: Add markdown rendering if there is valid markdown and renderMarkdown is enabled
36260
36308
  // adding react-markdown is blocked by updating React to v18
36261
36309
  if (!this.props.config.settings.widgetSettings.disableTeaserMarkdownRemoval) {
36262
- lastUnseenMessageText = (0,_webchat_helper_handleMarkdown__WEBPACK_IMPORTED_MODULE_48__/* .removeMarkdownChars */ .$)(lastUnseenMessageText);
36310
+ lastUnseenMessageText = (0,_webchat_helper_handleMarkdown__WEBPACK_IMPORTED_MODULE_50__/* .removeMarkdownChars */ .$)(lastUnseenMessageText);
36263
36311
  }
36264
36312
  this.setState({
36265
36313
  lastUnseenMessageText
@@ -36319,6 +36367,10 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36319
36367
 
36320
36368
  // also removes the fallback's document pointerdown listener
36321
36369
  this.cancelHomeScreenExitFocusFallback();
36370
+ if (this.xAppOverlayCloseFocusTimeout) {
36371
+ clearTimeout(this.xAppOverlayCloseFocusTimeout);
36372
+ this.xAppOverlayCloseFocusTimeout = null;
36373
+ }
36322
36374
 
36323
36375
  // Teardown icon animation interval
36324
36376
  if (this.iconAnimationIntervalHandle) {
@@ -36328,7 +36380,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36328
36380
  window.removeEventListener("resize", this.handleResize);
36329
36381
  }
36330
36382
  handleResize() {
36331
- const isMobile = (0,_utils_isMobile__WEBPACK_IMPORTED_MODULE_47__/* .isMobileViewport */ .$)();
36383
+ const isMobile = (0,_utils_isMobile__WEBPACK_IMPORTED_MODULE_49__/* .isMobileViewport */ .$)();
36332
36384
  if (isMobile !== this.state.isMobile) {
36333
36385
  this.setState({
36334
36386
  isMobile
@@ -36462,7 +36514,10 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36462
36514
  // behind it is inert, so this trap would agree with it only by virtue
36463
36515
  // of getKeyboardFocusableElements skipping inert subtrees. Excluded
36464
36516
  // explicitly instead of relying on that coupling.
36465
- !this.showDisconnectOverlay) {
36517
+ !this.showDisconnectOverlay &&
36518
+ // The xApp overlay dialog traps focus with its own focus guards
36519
+ // (Tab presses inside its cross-origin frame are invisible here).
36520
+ !this.props.isXAppOverlayOpen) {
36466
36521
  // Get the first and last focusable elements within the webchat window and add focus
36467
36522
  const webchatWindowEl = this.webchatWindowRef?.current;
36468
36523
  const {
@@ -36738,7 +36793,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36738
36793
  // while the webchat is open, so no `open` check is needed here.
36739
36794
  const {
36740
36795
  showHomeScreenView
36741
- } = (0,_utils_screen_visibility__WEBPACK_IMPORTED_MODULE_55__/* .getScreenVisibility */ .p)(this.props, isInforming);
36796
+ } = (0,_utils_screen_visibility__WEBPACK_IMPORTED_MODULE_57__/* .getScreenVisibility */ .p)(this.props, isInforming);
36742
36797
  const openChatAriaLabel = () => {
36743
36798
  if (open) return config.settings.customTranslations?.ariaLabels?.closeChat ?? "Close chat";
36744
36799
  const openChat = config.settings.customTranslations?.ariaLabels?.openChat ?? "Open chat";
@@ -36813,7 +36868,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36813
36868
  el.removeAttribute("inert");
36814
36869
  }
36815
36870
  }
36816
- }, !fullscreenMessage ? this.renderRegularLayout(isInforming) : this.renderFullscreenMessageLayout()), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_StatusLiveRegion__WEBPACK_IMPORTED_MODULE_51__/* .StatusLiveRegion */ .t, null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_HomeScreenAnnouncer__WEBPACK_IMPORTED_MODULE_53__/* ["default"] */ .A, {
36871
+ }, !fullscreenMessage ? this.renderRegularLayout(isInforming) : this.renderFullscreenMessageLayout()), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_StatusLiveRegion__WEBPACK_IMPORTED_MODULE_53__/* .StatusLiveRegion */ .t, null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_HomeScreenAnnouncer__WEBPACK_IMPORTED_MODULE_55__/* ["default"] */ .A, {
36817
36872
  active: showHomeScreenView,
36818
36873
  label: config.settings.customTranslations?.ariaLabels?.homeScreen ?? "Chat window home screen"
36819
36874
  }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_DisconnectOverlay__WEBPACK_IMPORTED_MODULE_20__/* ["default"] */ .A, {
@@ -36823,7 +36878,16 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36823
36878
  isConnecting: !!this.props.connecting,
36824
36879
  onClose: handleClose,
36825
36880
  config: config
36826
- })), !disableToggleButton && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement("div", null,
36881
+ })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_UnreadMessagesAnnouncer__WEBPACK_IMPORTED_MODULE_44__/* ["default"] */ .A, {
36882
+ active: config.settings.unreadMessages.enableBadge || config.settings.unreadMessages.enableIndicator,
36883
+ count: unseenMessages.length,
36884
+ singularText: config.settings.customTranslations?.ariaLabels?.unreadMessageSingularText ?? "One unread message in chat.",
36885
+ pluralText: config.settings.customTranslations?.ariaLabels?.unreadMessagePluralText ?? "unread messages in chat."
36886
+ }), !disableToggleButton && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_TeaserMessageAnnouncer__WEBPACK_IMPORTED_MODULE_43__/* ["default"] */ .A, {
36887
+ active: !!lastUnseenMessageText && !open,
36888
+ text: lastUnseenMessageText,
36889
+ label: config.settings.customTranslations?.ariaLabels?.newMessagePreview ?? "New message preview"
36890
+ }),
36827
36891
  // Show the message teaser if there is a last bot message and the webchat is closed
36828
36892
  lastUnseenMessageText && !open && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_TeaserMessage__WEBPACK_IMPORTED_MODULE_42__/* .TeaserMessage */ .I, {
36829
36893
  messageText: lastUnseenMessageText,
@@ -36853,7 +36917,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36853
36917
  onClick: this.handleFabClick
36854
36918
  }, webchatToggleProps, {
36855
36919
  type: "button",
36856
- className: classnames__WEBPACK_IMPORTED_MODULE_56___default()("webchat-toggle-button burst", config.settings?.layout?.iconAnimation),
36920
+ className: classnames__WEBPACK_IMPORTED_MODULE_58___default()("webchat-toggle-button burst", config.settings?.layout?.iconAnimation),
36857
36921
  id: "webchatWindowToggleButton",
36858
36922
  "aria-label": openChatAriaLabel(),
36859
36923
  ref: this.chatToggleButtonRef,
@@ -36862,10 +36926,17 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36862
36926
  }
36863
36927
  }), open ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_assets_collapse_20px_svg__WEBPACK_IMPORTED_MODULE_19__/* ["default"] */ .A, null) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_ChatIcon__WEBPACK_IMPORTED_MODULE_18__/* ["default"] */ .A, {
36864
36928
  config: config
36865
- }), config.settings.unreadMessages.enableBadge ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_Badge__WEBPACK_IMPORTED_MODULE_21__/* ["default"] */ .A, {
36929
+ }), config.settings.unreadMessages.enableBadge ?
36930
+ /*#__PURE__*/
36931
+ // The count is already in the button's
36932
+ // accessible name (and announced live by
36933
+ // UnreadMessagesAnnouncer); the badge is a
36934
+ // visual duplicate. aria-label is prohibited
36935
+ // on a generic <span>.
36936
+ react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_Badge__WEBPACK_IMPORTED_MODULE_21__/* ["default"] */ .A, {
36866
36937
  _content: unseenMessages.length,
36867
36938
  className: "webchat-unread-message-badge",
36868
- "aria-label": `${unseenMessages.length} ${config.settings.customTranslations?.ariaLabels?.unreadMessages ?? "unread messages"}`
36939
+ "aria-hidden": "true"
36869
36940
  }) : null))))))));
36870
36941
  }
36871
36942
  renderRegularLayout(isInforming) {
@@ -36991,7 +37062,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
36991
37062
  onAcceptTerms: handleAcceptTerms,
36992
37063
  isHomeScreenEnabled: isHomeScreenEnabled
36993
37064
  });
36994
- if (isXAppOverlayOpen) return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_functional_xapp_overlay_XAppOverlay__WEBPACK_IMPORTED_MODULE_43__/* ["default"] */ .A, null);
37065
+ if (isXAppOverlayOpen) return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_functional_xapp_overlay_XAppOverlay__WEBPACK_IMPORTED_MODULE_45__/* ["default"] */ .A, null);
36995
37066
  if (showPrevConversations) return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_previous_conversations_ConversationsList__WEBPACK_IMPORTED_MODULE_33__/* .PrevConversationsList */ .K, {
36996
37067
  conversations: this.props.prevConversations,
36997
37068
  onSetShowPrevConversations: onSetShowPrevConversations,
@@ -37030,7 +37101,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
37030
37101
  }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement("h3", {
37031
37102
  className: "sr-only",
37032
37103
  id: "webchatChatHistoryHeading"
37033
- }, config.settings.customTranslations?.ariaLabels?.chatHistory ?? "Chat history"), this.renderHistory()), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_ScreenReaderLiveRegion__WEBPACK_IMPORTED_MODULE_50__/* ["default"] */ .A, {
37104
+ }, config.settings.customTranslations?.ariaLabels?.chatHistory ?? "Chat history"), this.renderHistory()), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_ScreenReaderLiveRegion__WEBPACK_IMPORTED_MODULE_52__/* ["default"] */ .A, {
37034
37105
  liveContent: this.state.liveContent,
37035
37106
  intro: this.getNoticeIntro(),
37036
37107
  onIntroAnnounced: this.handleNoticeIntroAnnounced
@@ -37061,7 +37132,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
37061
37132
  const {
37062
37133
  showEnabledHomeScreen,
37063
37134
  showChatScreen
37064
- } = (0,_utils_screen_visibility__WEBPACK_IMPORTED_MODULE_55__/* .getScreenVisibility */ .p)(this.props, isInforming);
37135
+ } = (0,_utils_screen_visibility__WEBPACK_IMPORTED_MODULE_57__/* .getScreenVisibility */ .p)(this.props, isInforming);
37065
37136
  const isChatOptionsButtonVisible = config.settings.chatOptions.enabled && showChatScreen;
37066
37137
  const hideBackButton = showChatScreen && !isHomeScreenEnabled;
37067
37138
  const showDeleteAllConversationButton = !!((config.settings.privacyNotice.enabled && this.props.hasAcceptedTerms || !config.settings.privacyNotice.enabled) && config.settings.homeScreen.previousConversations.enableDeleteAllConversations && showPrevConversations && Object.keys(this.props.prevConversations).length);
@@ -37133,9 +37204,9 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
37133
37204
  className: "webchat-regular-layout-content",
37134
37205
  "aria-hidden": isRegularLayoutActiveView ? undefined : true,
37135
37206
  inert: isRegularLayoutActiveView ? undefined : ""
37136
- }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_FreezeOnExit__WEBPACK_IMPORTED_MODULE_52__/* ["default"] */ .A, {
37207
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_FreezeOnExit__WEBPACK_IMPORTED_MODULE_54__/* ["default"] */ .A, {
37137
37208
  active: isRegularLayoutActiveView
37138
- }, getRegularLayoutContent()), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_previous_conversations_DeleteAllConversations__WEBPACK_IMPORTED_MODULE_49__/* ["default"] */ .A, {
37209
+ }, getRegularLayoutContent()), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_previous_conversations_DeleteAllConversations__WEBPACK_IMPORTED_MODULE_51__/* ["default"] */ .A, {
37139
37210
  config: config,
37140
37211
  isOpen: this.state.showDeleteAllConversationsModal,
37141
37212
  onOpenChange: (open, confirmDelete) => {
@@ -37198,7 +37269,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
37198
37269
 
37199
37270
  // Find privacy message and remove it from the messages list (these message types are not displayed in the chat log).
37200
37271
  // If we do not remove, it will cause the collatation of the first user message.
37201
- const messagesExcludingPrivacyMessage = (0,_utils_filter_out_control_commands__WEBPACK_IMPORTED_MODULE_46__/* ["default"] */ .A)(messages, ["acceptPrivacyPolicy"]);
37272
+ const messagesExcludingPrivacyMessage = (0,_utils_filter_out_control_commands__WEBPACK_IMPORTED_MODULE_48__/* ["default"] */ .A)(messages, ["acceptPrivacyPolicy"]);
37202
37273
 
37203
37274
  // Filter messages based on progressive rendering settings
37204
37275
  const visibleMessages = progressiveMessageRendering ? messagesExcludingPrivacyMessage.filter(message => {
@@ -37219,7 +37290,7 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
37219
37290
  variant: "body-regular",
37220
37291
  component: "div",
37221
37292
  className: "webchat-log-ai-agent-notice-text"
37222
- }, AIAgentNoticeText || _utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_54__/* .DEFAULT_AI_AGENT_NOTICE_TEXT */ .S5), visibleMessages.map((message, index) => {
37293
+ }, AIAgentNoticeText || _utils_ai_agent_notice__WEBPACK_IMPORTED_MODULE_56__/* .DEFAULT_AI_AGENT_NOTICE_TEXT */ .S5), visibleMessages.map((message, index) => {
37223
37294
  // Lookahead if there is a user reply that includes text or attachments
37224
37295
  const hasReply = visibleMessages.slice(index + 1).some(message => {
37225
37296
  const isUser = message.source === "user";
@@ -37256,7 +37327,8 @@ class WebchatUI extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
37256
37327
  active: isTyping,
37257
37328
  delay: messageDelay,
37258
37329
  direction: config?.settings?.widgetSettings?.sourceDirectionMapping?.bot || "incoming",
37259
- disableBorder: config?.settings?.layout?.disableBotOutputBorder
37330
+ disableBorder: config?.settings?.layout?.disableBotOutputBorder,
37331
+ announcementText: config?.settings?.customTranslations?.ariaLabels?.typingIndicator
37260
37332
  }));
37261
37333
  }
37262
37334
  }
@@ -37411,6 +37483,8 @@ const MobileScrollLock = ({
37411
37483
  /* harmony import */ var _webchat_helper_useSelector__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(3862);
37412
37484
  /* harmony import */ var _presentational_Header__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(55922);
37413
37485
  /* harmony import */ var _webchat_store_messages_message_middleware__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(20570);
37486
+ /* harmony import */ var _utils_find_focusable__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(41098);
37487
+
37414
37488
 
37415
37489
 
37416
37490
 
@@ -37420,12 +37494,17 @@ const MobileScrollLock = ({
37420
37494
 
37421
37495
 
37422
37496
 
37497
+ const TITLE_ID = "webchatXAppOverlayTitle";
37498
+ const FOCUS_GUARD_ATTRIBUTE = "data-xapp-overlay-focus-guard";
37423
37499
  const Root = _emotion_styled__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .A.div(() => ({
37424
37500
  display: "flex",
37425
37501
  flexDirection: "column",
37426
37502
  height: "100%",
37427
37503
  width: "100%",
37428
37504
  animation: "fade-in-xapp .25s ease-out",
37505
+ "@media (prefers-reduced-motion: reduce)": {
37506
+ animation: "none"
37507
+ },
37429
37508
  "@keyframes fade-in-xapp": {
37430
37509
  from: {
37431
37510
  transform: "scale(.875)",
@@ -37443,6 +37522,9 @@ const Iframe = _emotion_styled__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .A.
37443
37522
  height: "100%",
37444
37523
  width: "100%",
37445
37524
  animation: "fade-in-xapp-2 .325s ease-in",
37525
+ "@media (prefers-reduced-motion: reduce)": {
37526
+ animation: "none"
37527
+ },
37446
37528
  "@keyframes fade-in-xapp-2": {
37447
37529
  from: {
37448
37530
  opacity: 0.87,
@@ -37456,6 +37538,21 @@ const Iframe = _emotion_styled__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .A.
37456
37538
  }
37457
37539
  }
37458
37540
  }));
37541
+
37542
+ // Visually hidden but reachable by sequential focus navigation. Not
37543
+ // `aria-hidden`: a focusable aria-hidden node is an axe violation
37544
+ // (aria-hidden-focus) — and focus never rests here anyway, the onFocus
37545
+ // handler redirects it immediately.
37546
+ const FocusGuard = _emotion_styled__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .A.div(() => ({
37547
+ position: "absolute",
37548
+ width: 1,
37549
+ height: 1,
37550
+ margin: -1,
37551
+ padding: 0,
37552
+ overflow: "hidden",
37553
+ clip: "rect(0, 0, 0, 0)",
37554
+ outline: "none"
37555
+ }));
37459
37556
  const xAppOverlay = () => {
37460
37557
  const url = (0,_webchat_helper_useSelector__WEBPACK_IMPORTED_MODULE_6__/* .useSelector */ .d)(state => state.xAppOverlay.currentUrl) || "";
37461
37558
  const {
@@ -37465,7 +37562,17 @@ const xAppOverlay = () => {
37465
37562
  sendEventOnCloseIconClick,
37466
37563
  showCloseIcon
37467
37564
  } = (0,_webchat_store_xapp_overlay_hooks__WEBPACK_IMPORTED_MODULE_5__/* .useOverlaySettingsByUrl */ .Z)(url);
37565
+ const ariaLabels = (0,_webchat_helper_useSelector__WEBPACK_IMPORTED_MODULE_6__/* .useSelector */ .d)(state => state.config.settings.customTranslations?.ariaLabels);
37566
+ // A whitespace-only screen title has no accessible text: it would render
37567
+ // an empty heading and name the dialog after it. Treat it as absent.
37568
+ const title = screenTitle?.trim() ?? "";
37569
+ // Names the dialog and its frame when the xApp has no screen title.
37570
+ const fallbackName = ariaLabels?.xAppOverlay ?? "Embedded app";
37571
+ const closeButtonAriaLabel = ariaLabels?.closeDialog ?? "Close dialog";
37468
37572
  const dispatch = (0,react_redux__WEBPACK_IMPORTED_MODULE_0__/* .useDispatch */ .wA)();
37573
+ const rootRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null);
37574
+ const closeButtonRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null);
37575
+ const iframeRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null);
37469
37576
  const handleClose = () => {
37470
37577
  if (closeOnSubmit) {
37471
37578
  dispatch((0,_webchat_store_xapp_overlay_slice__WEBPACK_IMPORTED_MODULE_4__/* .closeOverlay */ .L9)());
@@ -37482,7 +37589,20 @@ const xAppOverlay = () => {
37482
37589
  dispatch((0,_webchat_store_xapp_overlay_slice__WEBPACK_IMPORTED_MODULE_4__/* .closeOverlay */ .L9)());
37483
37590
  };
37484
37591
  const handleSubmit = event => {
37485
- if (url.startsWith(event.origin) === false) {
37592
+ // WCH-SI10-004: compare canonical origins, not raw URL strings.
37593
+ // The previous url.startsWith(event.origin) check was semantically backwards —
37594
+ // a domain that is a string-prefix of url (e.g. "https://xapp.cognigy.a" for
37595
+ // "https://xapp.cognigy.ai/form") could pass the check despite being a different
37596
+ // origin. new URL(url).origin extracts the canonical scheme+host+port for an
37597
+ // exact match, which is the correct cross-origin security boundary.
37598
+ let urlOrigin;
37599
+ try {
37600
+ urlOrigin = new URL(url).origin;
37601
+ } catch {
37602
+ // url is empty or not a valid absolute URL — reject all postMessages.
37603
+ return;
37604
+ }
37605
+ if (urlOrigin !== event.origin) {
37486
37606
  return;
37487
37607
  }
37488
37608
  if (event.data.type !== "x-app-submit") {
@@ -37508,8 +37628,12 @@ const xAppOverlay = () => {
37508
37628
  handleClose();
37509
37629
  };
37510
37630
 
37511
- // We revieve a MessageEvent from the xApp iframe when submission happens
37631
+ // We receive a MessageEvent from the xApp iframe when submission happens.
37512
37632
  // https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent
37633
+ // url and feedbackMessage are included in deps so the handler is re-registered
37634
+ // whenever either changes — both affect the handleSubmit closure and can change
37635
+ // independently (e.g. a subsequent RECEIVE_MESSAGE can update overlay settings
37636
+ // for the same URL, which would change feedbackMessage without changing url).
37513
37637
  (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
37514
37638
  function unsubscribe() {
37515
37639
  window.removeEventListener("message", handleSubmit);
@@ -37518,19 +37642,88 @@ const xAppOverlay = () => {
37518
37642
  return () => {
37519
37643
  unsubscribe();
37520
37644
  };
37521
- }, [closeOnSubmit]);
37522
- const showHeader = screenTitle || showCloseIcon;
37645
+ }, [closeOnSubmit, url, feedbackMessage]);
37646
+
37647
+ // APG modal dialog: move focus into the dialog once on open — to the
37648
+ // close button (the first control, as Modal does), else the frame itself.
37649
+ // Deliberately NOT the title: the dialog is named by that heading, so
37650
+ // focusing it makes NVDA read the same text as dialog name, as focused
37651
+ // heading, and again on its browse-mode pass. Deferred like
37652
+ // Modal.initialFocusRef: focusing in the same task that inserted the
37653
+ // subtree is not announced by VoiceOver (CGY-3274).
37654
+ (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
37655
+ const focusTimer = window.setTimeout(() => {
37656
+ const root = rootRef.current;
37657
+ if (!root || root.closest("[inert]")) return;
37658
+ (closeButtonRef.current ?? iframeRef.current)?.focus();
37659
+ }, 200);
37660
+ return () => window.clearTimeout(focusTimer);
37661
+ }, []);
37662
+
37663
+ // Escape dismisses the dialog exactly like the close icon (same side
37664
+ // effects), and only when the xApp is dismissable — without a close icon
37665
+ // the overlay is a blocking step that ends on submission inside the app.
37666
+ // Keys pressed inside the cross-origin frame never reach this document.
37667
+ (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
37668
+ if (!showCloseIcon) return;
37669
+ const handleKeyDown = event => {
37670
+ if (event.key !== "Escape") return;
37671
+ // Another modal surface (e.g. the disconnect overlay) is stacked on
37672
+ // top — leave Esc to that surface.
37673
+ if (rootRef.current?.closest("[inert]")) return;
37674
+ handleCloseIconClick();
37675
+ };
37676
+ document.addEventListener("keydown", handleKeyDown);
37677
+ return () => document.removeEventListener("keydown", handleKeyDown);
37678
+ }, [showCloseIcon, sendEventOnCloseIconClick]);
37679
+
37680
+ // Focus trap. A keydown-based trap (Modal) cannot see Tab presses inside
37681
+ // the cross-origin frame, so the dialog is bracketed by two focus guards
37682
+ // instead: tabbing out of the frame lands on a guard, which sends focus
37683
+ // back to the opposite edge of the dialog. Arriving at a guard from
37684
+ // outside the dialog (e.g. Tab from the host page) enters at the nearest
37685
+ // edge instead of wrapping. `relatedTarget` is null when focus comes from
37686
+ // the frame's document, which is the wrap case.
37687
+ const handleFocusGuard = edge => event => {
37688
+ const root = rootRef.current;
37689
+ if (!root) return;
37690
+ const focusable = (0,_utils_find_focusable__WEBPACK_IMPORTED_MODULE_9__/* ["default"] */ .A)(root).focusable.filter(el => !el.hasAttribute(FOCUS_GUARD_ATTRIBUTE));
37691
+ const first = focusable[0];
37692
+ const last = focusable[focusable.length - 1];
37693
+ const relatedTarget = event.relatedTarget;
37694
+ const cameFromInside = !relatedTarget || root.contains(relatedTarget);
37695
+ const target = edge === "start" ? cameFromInside ? last : first : cameFromInside ? first : last;
37696
+ target?.focus();
37697
+ };
37698
+ const showHeader = title || showCloseIcon;
37523
37699
  return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["default"].createElement(Root, {
37524
- tabIndex: 0,
37700
+ ref: rootRef,
37525
37701
  role: "dialog",
37526
- "aria-modal": "true"
37527
- }, showHeader && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["default"].createElement(_presentational_Header__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A, {
37528
- title: screenTitle,
37702
+ "aria-modal": "true",
37703
+ "aria-labelledby": title ? TITLE_ID : undefined,
37704
+ "aria-label": title ? undefined : fallbackName,
37705
+ className: "webchat-xapp-overlay-root",
37706
+ "data-xapp-overlay": true
37707
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["default"].createElement(FocusGuard, {
37708
+ tabIndex: 0,
37709
+ onFocus: handleFocusGuard("start"),
37710
+ [FOCUS_GUARD_ATTRIBUTE]: "start"
37711
+ }), showHeader && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["default"].createElement(_presentational_Header__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A, {
37712
+ title: title,
37713
+ titleId: TITLE_ID,
37529
37714
  hideBackButton: true,
37530
- onClose: showCloseIcon ? handleCloseIconClick : undefined
37715
+ onClose: showCloseIcon ? handleCloseIconClick : undefined,
37716
+ closeButtonAriaLabel: closeButtonAriaLabel,
37717
+ closeButtonRef: closeButtonRef
37531
37718
  }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["default"].createElement(Iframe, {
37719
+ ref: iframeRef,
37532
37720
  src: url,
37533
- allow: " accelerometer; ambient-light-sensor; autoplay; battery; bluetooth; camera; cross-origin-isolated; display-capture; document-domain; encrypted-media; execution-while-not-rendered; execution-while-out-of-viewport; fullscreen; gamepad; geolocation; gyroscope; hid; idle-detection; interest-cohort; local-fonts; magnetometer; microphone; midi; otp-credentials; payment; picture-in-picture; publickey-credentials-get; screen-wake-lock; serial; speaker-selection; usb; web-share; xr-spatial-tracking"
37721
+ title: title || fallbackName,
37722
+ allow: " accelerometer; ambient-light-sensor; autoplay; battery; bluetooth; camera; cross-origin-isolated; display-capture; document-domain; encrypted-media; execution-while-not-rendered; execution-while-out-of-viewport; fullscreen; gamepad; geolocation; gyroscope; hid; idle-detection; interest-cohort; local-fonts; magnetometer; microphone; midi; otp-credentials; payment; picture-in-picture; publickey-credentials-get; screen-wake-lock; serial; speaker-selection; usb; web-share; xr-spatial-tracking"
37723
+ }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["default"].createElement(FocusGuard, {
37724
+ tabIndex: 0,
37725
+ onFocus: handleFocusGuard("end"),
37726
+ [FOCUS_GUARD_ATTRIBUTE]: "end"
37534
37727
  }));
37535
37728
  };
37536
37729
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (xAppOverlay);
@@ -37848,10 +38041,23 @@ const QueueUpdates = props => {
37848
38041
  /* harmony import */ var _emotion_styled__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(84937);
37849
38042
  /* harmony import */ var _cognigy_chat_components__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2854);
37850
38043
  /* harmony import */ var _utils_is_mounted__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3657);
38044
+ /* harmony import */ var _presentational_SrOnlyLiveRegion__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(65766);
38045
+
37851
38046
 
37852
38047
 
37853
38048
 
37854
38049
 
38050
+ // How long typing must be continuously visible before it is announced to
38051
+ // screen readers (CGY-3146). Short bursts stay silent on purpose: when the
38052
+ // reply lands within this window, its own announcement (through
38053
+ // <ScreenReaderLiveRegion>) supersedes a "typing" heads-up, which would only
38054
+ // add noise to the polite queue.
38055
+ const ANNOUNCE_DELAY_MS = 2000;
38056
+
38057
+ // Module-global so every typing session gets a fresh LiveRegionMessage id —
38058
+ // a repeated announcement with the same text still needs a new node to be
38059
+ // re-announced (see SrOnlyLiveRegion's keying).
38060
+ let announcementCounter = 0;
37855
38061
  const ChatTypingIndicator = (0,_emotion_styled__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A)(_cognigy_chat_components__WEBPACK_IMPORTED_MODULE_2__/* .TypingIndicator */ .Vp)({
37856
38062
  marginBlock: 0
37857
38063
  });
@@ -37863,7 +38069,8 @@ const TypingIndicator = props => {
37863
38069
  active,
37864
38070
  delay,
37865
38071
  direction,
37866
- disableBorder
38072
+ disableBorder,
38073
+ announcementText
37867
38074
  } = props;
37868
38075
  const isMounted = (0,_utils_is_mounted__WEBPACK_IMPORTED_MODULE_3__/* .useIsMounted */ .a)();
37869
38076
 
@@ -37878,6 +38085,7 @@ const TypingIndicator = props => {
37878
38085
  * -----++++++++++++++++++++++--------++++++++-
37879
38086
  */
37880
38087
  const [isVisible, setIsVisible] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(active);
38088
+ const [announcement, setAnnouncement] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
37881
38089
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
37882
38090
  let timeout;
37883
38091
  if (active) {
@@ -37891,11 +38099,51 @@ const TypingIndicator = props => {
37891
38099
  if (timeout) clearTimeout(timeout);
37892
38100
  };
37893
38101
  }, [active]);
37894
- if (!isVisible) return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(HiddenChatTypingIndicator, null);
37895
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(ChatTypingIndicator, {
38102
+
38103
+ // Read at fire time through a ref so a translations/config update while
38104
+ // typing is visible neither restarts the delay nor emits a duplicate
38105
+ // announcement mid-session.
38106
+ const announcementTextRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(announcementText);
38107
+ announcementTextRef.current = announcementText;
38108
+
38109
+ // Announce a sustained typing session once (WCAG 4.1.3 Status Messages).
38110
+ //
38111
+ // The delay counts continuous typing ("active"): typing stopping (typingOff,
38112
+ // or an output removing the indicator) cancels the pending announcement,
38113
+ // resuming restarts it. The indicator's visible hide tail (`delay`) is not
38114
+ // typing, so nothing can be announced after the reply has already landed.
38115
+ //
38116
+ // The emitted announcement lives as long as the indicator is visible: at
38117
+ // most one per visible session, so typing flapping off/on between queued
38118
+ // delayed messages of one bot turn doesn't re-announce. When the indicator
38119
+ // hides, the text is removed silently (removals aren't announced) so it
38120
+ // can't be read later as stale status. Typing-stopped itself is not
38121
+ // announced — the arriving message covers it.
38122
+ const hasAnnouncedRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(false);
38123
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
38124
+ if (isVisible) return;
38125
+ hasAnnouncedRef.current = false;
38126
+ setAnnouncement(null);
38127
+ }, [isVisible]);
38128
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
38129
+ if (!active || hasAnnouncedRef.current) return;
38130
+ const timeout = setTimeout(() => {
38131
+ hasAnnouncedRef.current = true;
38132
+ setAnnouncement({
38133
+ id: `typing-${++announcementCounter}`,
38134
+ text: announcementTextRef.current ?? "A reply is being typed"
38135
+ });
38136
+ }, ANNOUNCE_DELAY_MS);
38137
+ return () => clearTimeout(timeout);
38138
+ }, [active]);
38139
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(react__WEBPACK_IMPORTED_MODULE_0__["default"].Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_presentational_SrOnlyLiveRegion__WEBPACK_IMPORTED_MODULE_4__/* .SrOnlyLiveRegion */ .Y, {
38140
+ id: "webchatTypingIndicatorLiveRegion",
38141
+ role: "status",
38142
+ message: announcement
38143
+ }), isVisible ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(ChatTypingIndicator, {
37896
38144
  direction: direction,
37897
38145
  disableBorder: disableBorder
37898
- });
38146
+ }) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(HiddenChatTypingIndicator, null));
37899
38147
  };
37900
38148
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (TypingIndicator);
37901
38149
 
@@ -38100,6 +38348,10 @@ const InputPluginRenderer = ({
38100
38348
  /* harmony import */ var react_responsive__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(react_responsive__WEBPACK_IMPORTED_MODULE_9__);
38101
38349
  /* harmony import */ var _menu_PersistentMenu__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(71117);
38102
38350
  /* harmony import */ var _FloatingLabel__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(93277);
38351
+ /* harmony import */ var _presentational_Notifications__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(82833);
38352
+ /* harmony import */ var _utils_speech_recognition__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(44120);
38353
+
38354
+
38103
38355
 
38104
38356
 
38105
38357
 
@@ -38249,46 +38501,66 @@ const InputContainer = _emotion_styled__WEBPACK_IMPORTED_MODULE_1__/* ["default"
38249
38501
  const Label = (0,_emotion_styled__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A)(_FloatingLabel__WEBPACK_IMPORTED_MODULE_11__/* ["default"] */ .A)({
38250
38502
  padding: "8px 2px"
38251
38503
  });
38252
- const getSpeechRecognition = () => {
38253
- try {
38254
- return new SpeechRecognition();
38255
- } catch (e) {}
38256
- try {
38257
- return new webkitSpeechRecognition();
38258
- } catch (e) {}
38259
- return null;
38260
- };
38261
38504
  const combineStrings = (str1, str2) => {
38262
38505
  if (!str1) return str2;
38263
38506
  if (!str2) return str1;
38264
38507
  return str1 + " " + str2;
38265
38508
  };
38266
- let webchatSpeechTimeoutRef = null;
38267
38509
  class BaseInput extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureComponent {
38268
38510
  constructor(props) {
38269
38511
  super(props);
38270
- const speechRecognition = getSpeechRecognition();
38271
- if (speechRecognition) {
38272
- speechRecognition.continuous = true;
38273
- speechRecognition.interimResults = true;
38274
- speechRecognition.onresult = this.handleSpeechResult;
38275
- if (props.config.settings.widgetSettings.STTLanguage) {
38276
- speechRecognition.lang = props.config.settings.widgetSettings.STTLanguage;
38277
- }
38278
- }
38279
38512
  this.state = {
38280
38513
  text: "",
38281
- speechRecognition,
38282
38514
  speechResult: "",
38283
- isFinalResult: false,
38284
38515
  isMenuOpen: false,
38285
38516
  selectionStart: 0,
38286
38517
  selectionEnd: 0
38287
38518
  };
38519
+ this.configureSpeechRecognition();
38288
38520
  }
38289
38521
  inputRef = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createRef();
38290
38522
  menuRef = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createRef();
38291
38523
  fileInputRef = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createRef();
38524
+
38525
+ /**
38526
+ * The live recognizer, or null where the browser has no Web Speech API.
38527
+ *
38528
+ * Deliberately NOT component state: it is a mutable host object whose
38529
+ * identity never changes, and keeping it in state invited
38530
+ * `setState({ speechRecognition: { ...recognizer, lang } })` to apply the
38531
+ * language. Native properties live on the prototype, so that spread
38532
+ * copied nothing but `lang` — `start`, `stop` and every event handler
38533
+ * disappeared, and the next click threw "start is not a function"
38534
+ * (CGY-37417).
38535
+ */
38536
+ speechRecognition = (0,_utils_speech_recognition__WEBPACK_IMPORTED_MODULE_13__/* .createSpeechRecognition */ .oC)();
38537
+
38538
+ /** The warm-up or idle stop timer, whichever phase recognition is in. */
38539
+ speechTimeout = null;
38540
+
38541
+ /** Whether the engine has produced any transcript since `start()`. */
38542
+ hasTranscript = false;
38543
+
38544
+ /**
38545
+ * Set while we are the ones ending recognition, so `onend` can tell an
38546
+ * engine-initiated end (which has to reconcile the UI) from our own.
38547
+ */
38548
+ endingDeliberately = false;
38549
+
38550
+ /**
38551
+ * Set on the submit path, where a transcript arriving afterwards belongs
38552
+ * to the message that was already sent. `abort()` should prevent one, but
38553
+ * a result already dispatched can still be delivered, so the handler
38554
+ * checks this too.
38555
+ */
38556
+ discardResults = false;
38557
+
38558
+ /**
38559
+ * A start() the engine rejected because a previous stop() had not reached
38560
+ * `onend` yet. Retried once from `onend`, so a stop-then-start inside that
38561
+ * window isn't silently dropped.
38562
+ */
38563
+ restartPending = false;
38292
38564
  componentDidMount() {
38293
38565
  // Global handler to modify the input text
38294
38566
  window.WebChatInputTextCallback = text => {
@@ -38297,98 +38569,311 @@ class BaseInput extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
38297
38569
  });
38298
38570
  };
38299
38571
  setTimeout(() => {
38572
+ // Don't pull focus away from a modal dialog the widget has opened in
38573
+ // the meantime (date picker, xApp overlay, Modal). Scoped to the
38574
+ // widget root: a dialog elsewhere on the host page (cookie banner, a
38575
+ // modal that embeds the launcher) must not suppress the autofocus.
38576
+ const root = this.inputRef.current?.closest("[data-cognigy-webchat-root]");
38577
+ const hasOpenDialog = !!root?.querySelector('[role="dialog"][aria-modal="true"], dialog[open]');
38578
+ if (hasOpenDialog) return;
38300
38579
  if (!this.props.config.settings.widgetSettings.disableInputAutofocus) {
38301
38580
  this.inputRef.current?.focus?.();
38302
38581
  }
38303
38582
  }, 200);
38304
38583
  }
38305
38584
  componentDidUpdate() {
38585
+ this.applySTTLanguage();
38586
+ }
38587
+ componentWillUnmount() {
38588
+ this.clearSpeechTimeout();
38589
+
38590
+ // The input unmounts on every screen change (back to the home screen,
38591
+ // into the previous-conversations list). Without releasing the engine
38592
+ // here the microphone stays open — browser recording indicator and
38593
+ // all — with nothing left to receive the transcript.
38594
+ if (this.speechRecognition) {
38595
+ this.endingDeliberately = true;
38596
+ this.speechRecognition.onresult = null;
38597
+ this.speechRecognition.onerror = null;
38598
+ this.speechRecognition.onend = null;
38599
+ try {
38600
+ // abort(), not stop(): a final transcript can no longer be
38601
+ // delivered anywhere, so don't wait for one.
38602
+ this.speechRecognition.abort();
38603
+ } catch {
38604
+ // Never started, or already finished.
38605
+ }
38606
+ }
38607
+
38608
+ // `sttActive` lives in the store, which outlives this component —
38609
+ // leaving it set would show an active mic button on the next visit to
38610
+ // the chat screen with nothing actually listening.
38611
+ if (this.props.sttActive) this.props.onSetSTTActive(false);
38612
+ }
38613
+ configureSpeechRecognition() {
38614
+ const recognition = this.speechRecognition;
38615
+ if (!recognition) return;
38616
+ recognition.continuous = true;
38617
+ recognition.interimResults = true;
38618
+ recognition.onresult = this.handleSpeechResult;
38619
+ recognition.onerror = this.handleSpeechError;
38620
+ recognition.onend = this.handleSpeechEnd;
38621
+ this.applySTTLanguage();
38622
+ }
38623
+
38624
+ /**
38625
+ * Applies the configured STT language to the live recognizer.
38626
+ *
38627
+ * Runs on every update because the endpoint config is fetched
38628
+ * asynchronously, so `STTLanguage` is typically absent when this
38629
+ * component first mounts. While it is unset we leave the engine's own
38630
+ * default (which follows the page's `lang`) rather than forcing a locale,
38631
+ * so an unconfigured German page keeps transcribing German.
38632
+ */
38633
+ applySTTLanguage() {
38306
38634
  const sttLanguage = this.props.config.settings.widgetSettings.STTLanguage;
38307
- if (this.state.speechRecognition && sttLanguage && this.state.speechRecognition.lang !== sttLanguage) {
38308
- this.setState({
38309
- speechRecognition: {
38310
- ...this.state.speechRecognition,
38311
- lang: sttLanguage
38312
- }
38313
- });
38635
+ if (this.speechRecognition && sttLanguage && this.speechRecognition.lang !== sttLanguage) {
38636
+ this.speechRecognition.lang = sttLanguage;
38314
38637
  }
38315
38638
  }
38316
- componentWillUnmount() {
38317
- if (webchatSpeechTimeoutRef) {
38318
- clearTimeout(webchatSpeechTimeoutRef);
38639
+ clearSpeechTimeout() {
38640
+ if (this.speechTimeout) {
38641
+ clearTimeout(this.speechTimeout);
38642
+ this.speechTimeout = null;
38319
38643
  }
38320
38644
  }
38645
+
38646
+ /**
38647
+ * Arms the single stop timer. `delay` is the warm-up budget before the
38648
+ * first transcript and the idle budget after it — the two differ by an
38649
+ * order of magnitude, see the constants' rationale.
38650
+ */
38651
+ armSpeechTimeout(delay) {
38652
+ this.clearSpeechTimeout();
38653
+ this.speechTimeout = setTimeout(() => {
38654
+ this.speechTimeout = null;
38655
+ const recognizedNothing = !this.hasTranscript;
38656
+
38657
+ // A dictation that produced text ended normally, and the user's
38658
+ // next move is to edit or send it, so focus goes to the input.
38659
+ // Having heard nothing is a failure like any other: leave focus
38660
+ // wherever the user put it (SC 3.2.1).
38661
+ this.endSpeech({
38662
+ restoreFocus: !recognizedNothing
38663
+ });
38664
+
38665
+ // The whole warm-up budget spent without a single word: the
38666
+ // engine never reached its speech service, or the user never
38667
+ // spoke. Either way, say so — this path used to stop the
38668
+ // microphone silently (CGY-37417).
38669
+ if (recognizedNothing) this.notifySpeechFailure("no-transcript");
38670
+ }, delay);
38671
+ }
38672
+ notifySpeechFailure(failure) {
38673
+ (0,_presentational_Notifications__WEBPACK_IMPORTED_MODULE_12__/* .createErrorNotification */ .gi)((0,_utils_speech_recognition__WEBPACK_IMPORTED_MODULE_13__/* .getSpeechRecognitionErrorMessage */ .JO)(failure, this.props.config.settings.customTranslations));
38674
+ }
38321
38675
  handleSpeechResult = e => {
38676
+ // A result that raced the abort() on the submit path. The message it
38677
+ // belongs to has already been sent and `text` cleared, so committing
38678
+ // it would refill the input with what the user just sent — and their
38679
+ // next Enter would send it a second time.
38680
+ if (this.discardResults) return;
38322
38681
  const result = e.results[e.resultIndex];
38323
- const {
38324
- isFinal
38325
- } = result;
38326
38682
  const {
38327
38683
  transcript
38328
38684
  } = result[0];
38329
38685
 
38330
- // Reset the 3s timeout for active speech recognition
38331
- if (webchatSpeechTimeoutRef) {
38332
- clearTimeout(webchatSpeechTimeoutRef);
38686
+ // Edge emits placeholder results — `isFinal` with an empty transcript
38687
+ // — when speech starts and again on stop(); Chrome never does.
38688
+ // Committing one would wipe the interim transcript on screen, and
38689
+ // counting one as "the engine is producing output" would start the
38690
+ // short idle countdown seconds before the first real word arrives.
38691
+ if (!transcript) return;
38692
+ this.hasTranscript = true;
38693
+
38694
+ // Only while listening: stop() lets one last result land afterwards,
38695
+ // and re-arming then would stop recognition and steal focus back to
38696
+ // the input seconds after the user had moved on.
38697
+ if (this.props.sttActive) this.armSpeechTimeout(_utils_speech_recognition__WEBPACK_IMPORTED_MODULE_13__/* .TRANSCRIPT_IDLE_TIMEOUT_MS */ .r0);
38698
+
38699
+ // Interim results are shown next to the typed text but not committed;
38700
+ // only a final result becomes part of the message.
38701
+ if (result.isFinal) {
38702
+ this.setState(({
38703
+ text
38704
+ }) => ({
38705
+ speechResult: "",
38706
+ text: combineStrings(text, transcript)
38707
+ }));
38708
+ return;
38333
38709
  }
38334
- webchatSpeechTimeoutRef = setTimeout(() => {
38335
- this.handleCancelSpeech();
38336
- }, 3000);
38337
38710
  this.setState({
38338
- speechResult: transcript,
38339
- isFinalResult: isFinal
38711
+ speechResult: transcript
38712
+ });
38713
+ };
38714
+ handleSpeechError = event => {
38715
+ // `aborted` is just the engine acknowledging our own stop()/abort().
38716
+ if (event.error === "aborted") return;
38717
+ if (event.error === "language-not-supported" || event.error === "bad-grammar") {
38718
+ // Misconfiguration the end user cannot act on: they get the
38719
+ // generic message, the operator gets the detail.
38720
+ console.warn(`[cognigy-webchat] speech recognition rejected the configured STT language "${this.speechRecognition?.lang}" (${event.error})`);
38721
+ }
38722
+
38723
+ // A failure is not a user-initiated stop: leave focus alone. The
38724
+ // button's `aria-pressed` change and the notification convey it.
38725
+ this.endSpeech({
38726
+ restoreFocus: false
38727
+ });
38728
+ this.notifySpeechFailure(event.error);
38729
+ };
38730
+ handleSpeechEnd = () => {
38731
+ const wasDeliberate = this.endingDeliberately;
38732
+ this.endingDeliberately = false;
38733
+
38734
+ // The engine is finished, so anything still held as an interim never
38735
+ // got a final result. Commit it rather than let the user's visible
38736
+ // words vanish. A real final would already have moved it into `text`
38737
+ // and emptied this, so there is nothing to duplicate.
38738
+ this.commitPendingTranscript();
38739
+
38740
+ // The user pressed the button again while the engine was still
38741
+ // winding down from the previous stop, so `start()` was rejected.
38742
+ // Honour it now that the engine has actually ended — once, because
38743
+ // only a rejected start sets the flag.
38744
+ if (this.restartPending) {
38745
+ this.restartPending = false;
38746
+ this.startSpeech();
38747
+ return;
38748
+ }
38749
+ if (wasDeliberate) return;
38750
+
38751
+ // The engine ended on its own — its service dropped the connection,
38752
+ // or it decided the utterance was over despite `continuous`.
38753
+ // Reconcile, so the button can never claim to be listening when
38754
+ // nothing is (SC 4.1.2).
38755
+ if (!this.props.sttActive) return;
38756
+ const recognizedNothing = !this.hasTranscript;
38757
+ this.endSpeech({
38758
+ restoreFocus: false
38340
38759
  });
38341
38760
 
38342
- // only send messages that are not 'interim'
38343
- if (isFinal) {
38344
- this.setState({
38345
- speechResult: "",
38346
- text: combineStrings(this.state.text, transcript)
38347
- });
38348
- }
38761
+ // Ending with nothing to show for it is exactly the silent failure
38762
+ // this change exists to remove, so say so. `onerror` cannot reach
38763
+ // here — it ends recognition itself, which marks the end deliberate.
38764
+ if (recognizedNothing) this.notifySpeechFailure("no-transcript");
38349
38765
  };
38766
+
38767
+ /**
38768
+ * Moves an un-finalized transcript into the message text. No-op when the
38769
+ * engine already finalized it (or when the submit path discarded it).
38770
+ */
38771
+ commitPendingTranscript() {
38772
+ this.setState(({
38773
+ text,
38774
+ speechResult
38775
+ }) => speechResult ? {
38776
+ text: combineStrings(text, speechResult),
38777
+ speechResult: ""
38778
+ } : null);
38779
+ }
38780
+
38781
+ /** The user pressed the microphone button to stop dictating. */
38350
38782
  handleCancelSpeech = () => {
38351
- const {
38352
- speechRecognition
38353
- } = this.state;
38354
- speechRecognition.stop();
38355
- if (webchatSpeechTimeoutRef) {
38356
- clearTimeout(webchatSpeechTimeoutRef);
38783
+ this.endSpeech({
38784
+ restoreFocus: true
38785
+ });
38786
+ };
38787
+
38788
+ /**
38789
+ * Ends recognition and reconciles the UI.
38790
+ *
38791
+ * `discardPending` is for the submit path only: the message has been sent
38792
+ * and `text` cleared, so a transcript arriving afterwards has to be
38793
+ * thrown away rather than committed. Everywhere else a late final is
38794
+ * welcome — it is the engine's better-punctuated version of the interim
38795
+ * that was on screen, and dropping it would lose the user's words.
38796
+ *
38797
+ * `restoreFocus` is true only when the user themselves stopped: they are
38798
+ * likely to carry on typing. On an error or a timeout the stop was not
38799
+ * requested, and moving focus then would take it from wherever the user
38800
+ * had put it (SC 3.2.1).
38801
+ */
38802
+ endSpeech({
38803
+ discardPending = false,
38804
+ restoreFocus
38805
+ }) {
38806
+ this.clearSpeechTimeout();
38807
+ this.endingDeliberately = true;
38808
+ this.discardResults = discardPending;
38809
+ try {
38810
+ if (discardPending) {
38811
+ // abort() asks the engine not to return a result at all,
38812
+ // unlike stop(), which finalizes what it heard.
38813
+ this.speechRecognition?.abort();
38814
+ } else {
38815
+ this.speechRecognition?.stop();
38816
+ }
38817
+ } catch {
38818
+ // Not currently running.
38357
38819
  }
38358
38820
  this.props.onSetSTTActive(false);
38359
- this.setState({
38360
- speechResult: "",
38361
- isFinalResult: false
38821
+
38822
+ // The interim transcript deliberately stays on screen. The engine may
38823
+ // still upgrade it to a final; if it never does, `onend` commits it.
38824
+ // Clearing it here would lose the words the user watched appear —
38825
+ // Edge answers stop() with an empty placeholder final, which carries
38826
+ // no text to put back. Only the submit path clears it, because that
38827
+ // text is already on its way.
38828
+ if (discardPending) this.setState({
38829
+ speechResult: ""
38362
38830
  });
38363
- if (this.inputRef.current) {
38831
+ if (restoreFocus && this.inputRef.current) {
38364
38832
  this.inputRef.current.focus();
38365
38833
  }
38366
- };
38834
+ }
38367
38835
  isSTTSupported() {
38368
- return !!this.state.speechRecognition;
38836
+ return !!this.speechRecognition;
38369
38837
  }
38370
38838
  toggleSTT = e => {
38371
38839
  e.preventDefault();
38372
- const {
38373
- speechRecognition
38374
- } = this.state;
38375
- const {
38376
- sttActive,
38377
- onSetSTTActive
38378
- } = this.props;
38379
- if (sttActive) {
38840
+ if (this.props.sttActive) {
38380
38841
  this.handleCancelSpeech();
38381
- } else {
38382
- speechRecognition.start();
38383
- if (webchatSpeechTimeoutRef) {
38384
- clearTimeout(webchatSpeechTimeoutRef);
38385
- }
38386
- webchatSpeechTimeoutRef = setTimeout(() => {
38387
- this.handleCancelSpeech();
38388
- }, 3000);
38842
+ return;
38389
38843
  }
38390
- onSetSTTActive(!sttActive);
38844
+ this.startSpeech();
38391
38845
  };
38846
+ startSpeech() {
38847
+ const recognition = this.speechRecognition;
38848
+ if (!recognition) return;
38849
+ try {
38850
+ recognition.start();
38851
+ } catch (error) {
38852
+ if (error?.name === "InvalidStateError") {
38853
+ // The engine is still winding down from a previous stop()
38854
+ // whose `onend` hasn't arrived. Claiming to listen here would
38855
+ // leave the button on with nothing running, so wait for the
38856
+ // end and start then.
38857
+ this.restartPending = true;
38858
+ return;
38859
+ }
38860
+
38861
+ // The engine never started listening, so the button must not
38862
+ // claim that it did.
38863
+ this.notifySpeechFailure("start-failed");
38864
+ return;
38865
+ }
38866
+
38867
+ // Only now that a session is really running: a rejected start above
38868
+ // leaves the previous session's flags in place, so a stale result
38869
+ // still in flight from an aborted submit stays discarded instead of
38870
+ // refilling the input with the message that was just sent.
38871
+ this.hasTranscript = false;
38872
+ this.endingDeliberately = false;
38873
+ this.discardResults = false;
38874
+ this.armSpeechTimeout(_utils_speech_recognition__WEBPACK_IMPORTED_MODULE_13__/* .FIRST_TRANSCRIPT_TIMEOUT_MS */ .rt);
38875
+ this.props.onSetSTTActive(true);
38876
+ }
38392
38877
  handleChangeTextValue = e => {
38393
38878
  this.setState({
38394
38879
  text: e.target.value
@@ -38404,16 +38889,39 @@ class BaseInput extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
38404
38889
  } = this.state;
38405
38890
  const {
38406
38891
  sttActive,
38407
- fileList
38892
+ fileList,
38893
+ fileUploadError
38408
38894
  } = this.props;
38409
- let messageText = text;
38895
+
38896
+ // Exactly what the field shows, which is `text` plus any transcript
38897
+ // not yet finalized — including after recognition stopped, while the
38898
+ // interim waits for `onend` to commit it.
38899
+ const messageText = combineStrings(text, speechResult);
38410
38900
  if (sttActive) {
38411
- if (text && speechResult) {
38412
- messageText = text + " " + speechResult;
38413
- }
38414
- this.handleCancelSpeech();
38901
+ // Discard whatever the engine still owes us: it belongs to this
38902
+ // message, which is on its way. handleSubmit restores focus to
38903
+ // the input itself once the message is sent.
38904
+ this.endSpeech({
38905
+ discardPending: true,
38906
+ restoreFocus: false
38907
+ });
38415
38908
  }
38416
- if (!text && !fileList) return;
38909
+
38910
+ /**
38911
+ * Enter reaches `handleSubmit` straight from `handleInputKeyDown`, which does
38912
+ * not consult the Send button — so both of the button's `disabled` conditions
38913
+ * have to be repeated here or Enter bypasses them.
38914
+ *
38915
+ * `fileList` is always an array (it defaults to `[]`), so emptiness has to be
38916
+ * checked by length: `!fileList` would never be true.
38917
+ *
38918
+ * The text half checks `messageText` rather than the button's `state.text`
38919
+ * on purpose: while dictating, the pending transcript is shown in the field
38920
+ * but is not in `text` yet, and a dictation the user never typed a word of
38921
+ * must still submit (CGY-37417).
38922
+ */
38923
+ if (fileUploadError) return;
38924
+ if (!messageText && !fileList?.length) return;
38417
38925
  const attachments = [];
38418
38926
  fileList.forEach(fileItem => {
38419
38927
  if (fileItem.uploadFileMeta) {
@@ -38430,7 +38938,8 @@ class BaseInput extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
38430
38938
  }
38431
38939
  this.props.onSetFileList([]);
38432
38940
  this.setState({
38433
- text: ""
38941
+ text: "",
38942
+ speechResult: ""
38434
38943
  }, () => {
38435
38944
  this.props.onSendMessage(messageText, data, {
38436
38945
  collate: true
@@ -38592,8 +39101,15 @@ class BaseInput extends react__WEBPACK_IMPORTED_MODULE_0__["default"].PureCompon
38592
39101
  } : undefined
38593
39102
  }));
38594
39103
  }), props.config.settings.behavior.enableSTT && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(SpeechButton, {
39104
+ type: "button",
38595
39105
  className: classnames__WEBPACK_IMPORTED_MODULE_2___default()("webchat-input-button-speech", sttActive && "webchat-input-button-speech-active"),
38596
- "aria-label": customTranslations?.ariaLabels?.speechToText ?? "Speech to text",
39106
+ "aria-label": customTranslations?.ariaLabels?.speechToText ?? "Speech to text"
39107
+ // APG toggle button: the "listening"
39108
+ // state is otherwise conveyed only by
39109
+ // the animated background, which is
39110
+ // aria-hidden (SC 4.1.2).
39111
+ ,
39112
+ "aria-pressed": sttActive,
38597
39113
  id: "webchatInputMessageSpeechButton",
38598
39114
  onClick: this.toggleSTT,
38599
39115
  disabled: !this.isSTTSupported()
@@ -38934,6 +39450,7 @@ const PreviewUploadedFiles = () => {
38934
39450
  key: index,
38935
39451
  id: `filePreview${index}`
38936
39452
  }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(UploadedFilePreview, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(RemoveFileButton, {
39453
+ type: "button",
38937
39454
  onClick: () => onRemoveFileButtonClick(index),
38938
39455
  onFocus: () => {
38939
39456
  if (removeFileButtonRefs.current[index]) {
@@ -39914,6 +40431,8 @@ const Header = props => {
39914
40431
  showChatScreen,
39915
40432
  autoFocusScreenTitle,
39916
40433
  onDeleteAllConversations,
40434
+ titleId = "webchatHeaderTitle",
40435
+ closeButtonAriaLabel,
39917
40436
  ...rest
39918
40437
  } = props;
39919
40438
  const ariaLabels = (0,_webchat_helper_useSelector__WEBPACK_IMPORTED_MODULE_13__/* .useSelector */ .d)(state => state.config.settings.customTranslations?.ariaLabels);
@@ -39958,10 +40477,10 @@ const Header = props => {
39958
40477
  title: "Cognigy.AI Logo",
39959
40478
  role: "img",
39960
40479
  className: classnames__WEBPACK_IMPORTED_MODULE_8___default()("webchat-header-cognigy-logo")
39961
- })), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(HeaderText, {
40480
+ })), title?.trim() && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(HeaderText, {
39962
40481
  ref: headerTextRef,
39963
40482
  variant: "h2-semibold",
39964
- id: "webchatHeaderTitle",
40483
+ id: titleId,
39965
40484
  className: "webchat-header-title",
39966
40485
  margin: 0,
39967
40486
  tabIndex: -1
@@ -39993,7 +40512,7 @@ const Header = props => {
39993
40512
  "data-header-close-button": true,
39994
40513
  onClick: handleCloseClick,
39995
40514
  className: "webchat-header-close-button",
39996
- "aria-label": ariaLabels?.closeChat ?? "Close chat",
40515
+ "aria-label": closeButtonAriaLabel ?? ariaLabels?.closeChat ?? "Close chat",
39997
40516
  ref: closeButtonRef
39998
40517
  }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_assets_close_16px_svg__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .A, null)))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_Notifications__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .Ay, null));
39999
40518
  };
@@ -40581,7 +41100,8 @@ MultilineInput.displayName = "MultilineInput";
40581
41100
 
40582
41101
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
40583
41102
  /* harmony export */ Ay: () => (__WEBPACK_DEFAULT_EXPORT__),
40584
- /* harmony export */ UI: () => (/* binding */ createNotification)
41103
+ /* harmony export */ UI: () => (/* binding */ createNotification),
41104
+ /* harmony export */ gi: () => (/* binding */ createErrorNotification)
40585
41105
  /* harmony export */ });
40586
41106
  /* unused harmony export createPersistentNotification */
40587
41107
  /* unused harmony import specifier */ var toast;
@@ -40597,6 +41117,25 @@ const Notifications = () => {
40597
41117
  gutter: 1,
40598
41118
  toastOptions: {
40599
41119
  duration: 1500,
41120
+ // Failures stay up much longer than confirmations: the user has
41121
+ // to read a remedy and act on it, not just register that
41122
+ // something worked. The longest of these ("Microphone access
41123
+ // is blocked. Allow it in your browser settings…") is ~95
41124
+ // characters, which needs well over 5s to notice and read
41125
+ // (SC 2.2.1).
41126
+ // red40 on red10 is 5.27:1, mirroring the vetted green pairing
41127
+ // below (SC 1.4.3).
41128
+ error: {
41129
+ duration: 12000,
41130
+ style: {
41131
+ backgroundColor: theme.red10,
41132
+ color: theme.red40
41133
+ },
41134
+ iconTheme: {
41135
+ primary: theme.red40,
41136
+ secondary: theme.red10
41137
+ }
41138
+ },
40600
41139
  style: {
40601
41140
  backgroundColor: theme.green10,
40602
41141
  borderRadius: 0,
@@ -40648,6 +41187,20 @@ function createNotification(message, options = {}) {
40648
41187
  });
40649
41188
  }
40650
41189
 
41190
+ /**
41191
+ * Same as `createNotification`, styled as a failure and shown for longer.
41192
+ * Use for anything the user needs to act on (e.g. a dictation that could not
41193
+ * be started) — the message is mirrored into <StatusLiveRegion> like every
41194
+ * other toast, so it reaches screen readers too (SC 3.3.1 / 4.1.3).
41195
+ */
41196
+ function createErrorNotification(message, options = {}) {
41197
+ react_hot_toast__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .Ay.error(message, {
41198
+ ...options,
41199
+ className: "webchat-toast-notification webchat-toast-notification-error",
41200
+ ariaProps: silencedAriaProps
41201
+ });
41202
+ }
41203
+
40651
41204
  /**
40652
41205
  * Creates a persistent notification.
40653
41206
  * Can be dismissed by calling the returned function.
@@ -41388,8 +41941,7 @@ const TeaserMessage = props => {
41388
41941
  className: "webchat-teaser-message-root"
41389
41942
  }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_UnreadMessagePreview__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .A, {
41390
41943
  className: "webchat-teaser-message-bubble",
41391
- onClick: handleMessageClick,
41392
- "aria-live": "polite"
41944
+ onClick: handleMessageClick
41393
41945
  }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(TeaserMessageHeader, {
41394
41946
  className: "webchat-teaser-message-header"
41395
41947
  }, config?.settings?.layout?.logoUrl ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(HeaderLogo, {
@@ -41430,6 +41982,63 @@ const TeaserMessage = props => {
41430
41982
 
41431
41983
  /***/ },
41432
41984
 
41985
+ /***/ 59359
41986
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
41987
+
41988
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
41989
+ /* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__)
41990
+ /* harmony export */ });
41991
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(51649);
41992
+ /* harmony import */ var _SrOnlyLiveRegion__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(65766);
41993
+
41994
+
41995
+ let teaserAnnouncementCounter = 0;
41996
+
41997
+ /**
41998
+ * Announces the teaser message popup when it appears next to the toggle
41999
+ * button (WCAG 4.1.3 Status Messages, CGY-3270). The teaser shows while the
42000
+ * webchat is CLOSED, so it cannot announce through <StatusLiveRegion> —
42001
+ * that region lives inside the open chat window and is unmounted at that
42002
+ * point. This announcer therefore owns a separate region that is mounted
42003
+ * with the toggle button for the whole page lifetime, so it pre-exists any
42004
+ * teaser (a live region only announces changes to a node already in the
42005
+ * accessibility tree — an `aria-live` attribute on the teaser bubble itself
42006
+ * mounts together with its content and is never voiced).
42007
+ *
42008
+ * role="status" (polite), not role="alert": a proactive teaser is advisory
42009
+ * and must not interrupt what the user is currently doing on the host page.
42010
+ *
42011
+ * Announces again when the preview text changes while the teaser is showing
42012
+ * (a newer bot message replaces the preview). Hiding the teaser (dismissed,
42013
+ * chat opened) clears the region silently so users browsing the page later
42014
+ * don't find stale preview text.
42015
+ */
42016
+ const TeaserMessageAnnouncer = ({
42017
+ active,
42018
+ text,
42019
+ label
42020
+ }) => {
42021
+ const [message, setMessage] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
42022
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
42023
+ if (!active || !text) {
42024
+ setMessage(null);
42025
+ return;
42026
+ }
42027
+ setMessage({
42028
+ id: `webchatTeaserMessage-${++teaserAnnouncementCounter}`,
42029
+ text: `${label}: ${text}`
42030
+ });
42031
+ }, [active, text, label]);
42032
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_SrOnlyLiveRegion__WEBPACK_IMPORTED_MODULE_1__/* .SrOnlyLiveRegion */ .Y, {
42033
+ id: "webchatTeaserMessageLiveRegion",
42034
+ role: "status",
42035
+ message: message
42036
+ });
42037
+ };
42038
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (TeaserMessageAnnouncer);
42039
+
42040
+ /***/ },
42041
+
41433
42042
  /***/ 52077
41434
42043
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
41435
42044
 
@@ -41454,10 +42063,28 @@ const StyledToggleButtonOuter = _emotion_styled__WEBPACK_IMPORTED_MODULE_1__/* [
41454
42063
  width: 30,
41455
42064
  height: 16,
41456
42065
  borderRadius: 15,
41457
- border: `1px solid ${theme.black80}`,
42066
+ // black50 (#808080) keeps the track boundary ≥ 3:1 on white (WCAG 1.4.11) — black80 was ~1.6:1
42067
+ border: `1px solid ${theme.black50}`,
41458
42068
  backgroundColor: theme.white,
41459
42069
  cursor: disabled ? "default" : "pointer",
41460
42070
  transition: "background-color 0.2s ease-in-out",
42071
+ // Invisible hit-area extension so the pointer target is ≥ 24x24px (WCAG 2.2 SC 2.5.8)
42072
+ position: "relative",
42073
+ "&::before": {
42074
+ content: '""',
42075
+ position: "absolute",
42076
+ top: -5,
42077
+ bottom: -5,
42078
+ left: 0,
42079
+ right: 0
42080
+ },
42081
+ "&:focus-visible": {
42082
+ outline: `2px solid ${theme.primaryColorFocus}`,
42083
+ outlineOffset: 2
42084
+ },
42085
+ "@media (prefers-reduced-motion: reduce)": {
42086
+ transition: "none"
42087
+ },
41461
42088
  "&.active": {
41462
42089
  backgroundColor: disabled ? theme.secondaryColorDisabled : theme.secondaryColor,
41463
42090
  "&:hover": {
@@ -41477,6 +42104,9 @@ const StyledToggleButtonInner = _emotion_styled__WEBPACK_IMPORTED_MODULE_1__/* [
41477
42104
  cursor: disabled ? "default" : "pointer",
41478
42105
  transform: isActive ? "translateX(14px)" : "translateX(0px)",
41479
42106
  transition: "transform 0.2s ease-in-out, background-color 0.2s ease-in-out",
42107
+ "@media (prefers-reduced-motion: reduce)": {
42108
+ transition: "none"
42109
+ },
41480
42110
  "&:hover": {
41481
42111
  backgroundColor: disabled ? theme.secondaryColorDisabled : theme.secondaryColorHover
41482
42112
  },
@@ -41493,10 +42123,13 @@ const ToggleButton = props => {
41493
42123
  isActive,
41494
42124
  className,
41495
42125
  disabled,
42126
+ id,
41496
42127
  "aria-labelledby": ariaLabelledBy
41497
42128
  } = props;
41498
42129
  const [isHovered, setIsHovered] = react__WEBPACK_IMPORTED_MODULE_0__["default"].useState(false);
41499
42130
  return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(StyledToggleButtonOuter, {
42131
+ type: "button",
42132
+ id: id,
41500
42133
  className: classnames__WEBPACK_IMPORTED_MODULE_2___default()(className, "webchat-toggle-button-root", isActive && "active"),
41501
42134
  onClick: onClick,
41502
42135
  isActive: isActive,
@@ -41508,7 +42141,6 @@ const ToggleButton = props => {
41508
42141
  onMouseLeave: () => setIsHovered(false)
41509
42142
  }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(StyledToggleButtonInner, {
41510
42143
  className: classnames__WEBPACK_IMPORTED_MODULE_2___default()("webchat-toggle-button-inner-circle", isActive && "active", isHovered && "hovered"),
41511
- onClick: onClick,
41512
42144
  isActive: isActive,
41513
42145
  disabled: disabled
41514
42146
  }));
@@ -41572,6 +42204,68 @@ const UnreadMessagePreview = _emotion_styled__WEBPACK_IMPORTED_MODULE_0__/* ["de
41572
42204
 
41573
42205
  /***/ },
41574
42206
 
42207
+ /***/ 1715
42208
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
42209
+
42210
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
42211
+ /* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__)
42212
+ /* harmony export */ });
42213
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(51649);
42214
+ /* harmony import */ var _SrOnlyLiveRegion__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(65766);
42215
+
42216
+
42217
+ let unreadAnnouncementCounter = 0;
42218
+
42219
+ /**
42220
+ * Announces the unread-message count when it changes (WCAG 4.1.3 Status
42221
+ * Messages, technique ARIA22, CGY-3163). Sighted users get this count from
42222
+ * the badge on the toggle button and from the page title indicator; neither
42223
+ * reaches a screen reader on its own — the badge only changes the toggle
42224
+ * button's accessible name (read on focus, never live) and browsers do not
42225
+ * announce `document.title` changes at all.
42226
+ *
42227
+ * Unread messages only accumulate while the chat window is closed or the
42228
+ * page is hidden, so <StatusLiveRegion> (inside the open window) cannot
42229
+ * carry this. The region is mounted for the page lifetime — next to the
42230
+ * toggle button, independent of it — so it pre-exists the first count
42231
+ * change (a live region only announces changes to a node already in the
42232
+ * accessibility tree).
42233
+ *
42234
+ * role="status" (polite), not role="alert": a new-message notice is
42235
+ * advisory and must not interrupt what the user is doing on the host page.
42236
+ *
42237
+ * `active` mirrors the visual indicators (badge or title indicator
42238
+ * enabled): when neither is shown, screen-reader users are not notified
42239
+ * either. Clearing the count (chat opened, page visible again) empties the
42240
+ * region silently so users browsing the page later don't find stale text.
42241
+ */
42242
+ const UnreadMessagesAnnouncer = ({
42243
+ active,
42244
+ count,
42245
+ singularText,
42246
+ pluralText
42247
+ }) => {
42248
+ const [message, setMessage] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
42249
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
42250
+ if (!active || count === 0) {
42251
+ setMessage(null);
42252
+ return;
42253
+ }
42254
+ setMessage({
42255
+ id: `webchatUnreadMessages-${++unreadAnnouncementCounter}`,
42256
+ text: count === 1 ? singularText : `${count} ${pluralText}`
42257
+ });
42258
+ }, [active, count, singularText, pluralText]);
42259
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_SrOnlyLiveRegion__WEBPACK_IMPORTED_MODULE_1__/* .SrOnlyLiveRegion */ .Y, {
42260
+ id: "webchatUnreadMessagesLiveRegion",
42261
+ role: "status",
42262
+ message: message
42263
+ });
42264
+ };
42265
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (UnreadMessagesAnnouncer);
42266
+
42267
+ /***/ },
42268
+
41575
42269
  /***/ 31961
41576
42270
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
41577
42271
 
@@ -41845,8 +42539,7 @@ const ChatOptionsFooter = props => {
41845
42539
  /* harmony import */ var _emotion_styled__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(84937);
41846
42540
  /* harmony import */ var _webchat_store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(22284);
41847
42541
  /* harmony import */ var _Modal_DeleteConfirmModal__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(75691);
41848
- /* harmony import */ var _webchat_store_previous_conversations_previous_conversations_middleware__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(92101);
41849
- /* harmony import */ var _webchat_store_options_options__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(48242);
42542
+ /* harmony import */ var _webchat_store_options_options__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(48242);
41850
42543
 
41851
42544
 
41852
42545
 
@@ -41888,14 +42581,14 @@ const DeleteConversation = props => {
41888
42581
  const handleConfirmDelete = () => {
41889
42582
  dispatch((0,_webchat_store_previous_conversations_previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_3__/* .deletePrevConversation */ .YD)(sessionId));
41890
42583
  dispatch((0,_webchat_store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_7__/* .clearMessages */ .oI)());
41891
- dispatch((0,_webchat_store_previous_conversations_previous_conversations_middleware__WEBPACK_IMPORTED_MODULE_9__/* .switchSession */ .r)());
42584
+ dispatch((0,_webchat_store_previous_conversations_previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_3__/* .switchSession */ .rm)());
41892
42585
  const storage = (0,_webchat_helper_storage__WEBPACK_IMPORTED_MODULE_4__/* .getStorage */ .c)({
41893
42586
  disableLocalStorage: props.config.settings.embeddingConfiguration?.disableLocalStorage ?? false,
41894
42587
  useSessionStorage: props.config.settings.embeddingConfiguration?.useSessionStorage ?? false
41895
42588
  });
41896
42589
  if (storage) {
41897
42590
  Object.keys(storage).forEach(_ => {
41898
- const key = (0,_webchat_store_options_options__WEBPACK_IMPORTED_MODULE_10__/* .getOptionsKey */ .W)({
42591
+ const key = (0,_webchat_store_options_options__WEBPACK_IMPORTED_MODULE_9__/* .getOptionsKey */ .W)({
41899
42592
  channel,
41900
42593
  userId,
41901
42594
  sessionId
@@ -42190,6 +42883,11 @@ const TTSOptionRoot = _emotion_styled__WEBPACK_IMPORTED_MODULE_1__/* ["default"]
42190
42883
  alignItems: "center",
42191
42884
  height: 50
42192
42885
  }));
42886
+
42887
+ // Native <label for> so clicking the visible text also activates the switch (WCAG technique H44)
42888
+ const ToggleLabel = _emotion_styled__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.label(() => ({
42889
+ cursor: "pointer"
42890
+ }));
42193
42891
  const TTSOption = props => {
42194
42892
  const {
42195
42893
  config,
@@ -42197,6 +42895,7 @@ const TTSOption = props => {
42197
42895
  } = props;
42198
42896
  const isActive = (0,_webchat_helper_useSelector__WEBPACK_IMPORTED_MODULE_4__/* .useSelector */ .d)(state => state.ui.ttsActive);
42199
42897
  const labelId = react__WEBPACK_IMPORTED_MODULE_0__["default"].useId();
42898
+ const toggleId = react__WEBPACK_IMPORTED_MODULE_0__["default"].useId();
42200
42899
  const label = config.settings.chatOptions.labelTTSToggle || "Enable Text-to-Speech";
42201
42900
  return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(TTSOptionRoot, {
42202
42901
  className: "webchat-tts-option-root"
@@ -42205,7 +42904,10 @@ const TTSOption = props => {
42205
42904
  variant: "title1-semibold",
42206
42905
  margin: 0,
42207
42906
  className: "webchat-chat-options-tts-option-label"
42208
- }, label), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_ToggleButton__WEBPACK_IMPORTED_MODULE_3__/* .ToggleButton */ .f, {
42907
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(ToggleLabel, {
42908
+ htmlFor: toggleId
42909
+ }, label)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(_ToggleButton__WEBPACK_IMPORTED_MODULE_3__/* .ToggleButton */ .f, {
42910
+ id: toggleId,
42209
42911
  onClick: onToggle,
42210
42912
  className: "webchat-chat-options-tts-option-toggle",
42211
42913
  isActive: isActive,
@@ -42532,7 +43234,6 @@ const ConversationsListItem = props => {
42532
43234
  /* harmony import */ var _cognigy_chat_components__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(2854);
42533
43235
  /* harmony import */ var _webchat_store_connection_connection_middleware__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(12193);
42534
43236
  /* harmony import */ var _webchat_store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(22284);
42535
- /* harmony import */ var _webchat_store_previous_conversations_previous_conversations_middleware__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(92101);
42536
43237
 
42537
43238
 
42538
43239
 
@@ -42556,7 +43257,7 @@ const DeleteAllConversationsModal = props => {
42556
43257
  const handleConfirmDelete = () => {
42557
43258
  dispatch((0,_webchat_store_previous_conversations_previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_2__/* .setConversations */ .dU)({}));
42558
43259
  dispatch((0,_webchat_store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_7__/* .clearMessages */ .oI)()); // Clear any existing messages
42559
- dispatch((0,_webchat_store_previous_conversations_previous_conversations_middleware__WEBPACK_IMPORTED_MODULE_8__/* .switchSession */ .r)()); // Switch the session to a new one
43260
+ dispatch((0,_webchat_store_previous_conversations_previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_2__/* .switchSession */ .rm)()); // Switch the session to a new one
42560
43261
  dispatch((0,_webchat_store_connection_connection_middleware__WEBPACK_IMPORTED_MODULE_6__/* .disconnect */ .Zf)()); // Disconnect the socket to prevent from receiving any new messages. Socket will be reconnected upon starting a new conversation
42561
43262
  const storage = (0,_webchat_helper_storage__WEBPACK_IMPORTED_MODULE_3__/* .getStorage */ .c)({
42562
43263
  disableLocalStorage: config.settings.embeddingConfiguration?.disableLocalStorage ?? false,
@@ -43045,9 +43746,18 @@ const INITIAL_NOTICE_SESSION = {
43045
43746
  * only — later restores (reopening a previous conversation) are already
43046
43747
  * covered by the snapshot lookup, and the flag must not silence a
43047
43748
  * brand-new conversation started afterwards.
43048
- */
43049
- function computeNoticeSession(prev, currentSessionId, prevConversationsSnapshot, hasRestoredPersistedHistory) {
43050
- const isRestoredFirstConnect = prev.id === "" && !!hasRestoredPersistedHistory;
43749
+ *
43750
+ * `willRestorePersistedConversation` is that same page-reload case seen
43751
+ * BEFORE the connect: the restore only happens when the connect
43752
+ * resolves, which can take longer than the notice's 600ms announce
43753
+ * delay, and by then an announcement can no longer be taken back. It is
43754
+ * read from storage through the very helpers the restore uses (see
43755
+ * `hasPersistedConversationForInitialSession`), so it cannot disagree
43756
+ * with the restore that follows. Same first-connect-only scope as the
43757
+ * flag above, for the same reason.
43758
+ */
43759
+ function computeNoticeSession(prev, currentSessionId, prevConversationsSnapshot, hasRestoredPersistedHistory, willRestorePersistedConversation) {
43760
+ const isRestoredFirstConnect = prev.id === "" && (!!hasRestoredPersistedHistory || !!willRestorePersistedConversation);
43051
43761
  const isNew = !prevConversationsSnapshot?.[currentSessionId] && !isRestoredFirstConnect;
43052
43762
  const isFirstConnectOfNewConversation = prev.id === "" && prev.isNew && isNew;
43053
43763
  return {
@@ -43065,6 +43775,12 @@ function computeNoticeSession(prev, currentSessionId, prevConversationsSnapshot,
43065
43775
  * reconnect the socket and open it — its dialog and focus utterances
43066
43776
  * would cancel the notice; on close, the intro becomes pending again
43067
43777
  * and is announced after the "Connection restored" utterances).
43778
+ *
43779
+ * Eligibility only — WHEN an eligible notice is spoken is the live
43780
+ * region's business (it defers the intro past the screen's focus
43781
+ * utterances). That deferral is why the verdict must be final before the
43782
+ * first connect resolves rather than after it, which is what
43783
+ * `willRestorePersistedConversation` in `computeNoticeSession` provides.
43068
43784
  */
43069
43785
  function getAIAgentNoticeIntroText(args) {
43070
43786
  const {
@@ -43192,8 +43908,10 @@ const getMessagesListWithoutControlCommands = (messages, types = EXCLUDE_CC_TYPE
43192
43908
  * @returns {Array}
43193
43909
  */
43194
43910
  const getKeyboardFocusableElements = element => {
43195
- // Get all interactive elements in given element
43196
- const interactiveEls = element?.querySelectorAll('a[href], button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])');
43911
+ // Get all interactive elements in given element. An <iframe> is a
43912
+ // sequential-focus stop in every browser (Tab enters the frame's
43913
+ // document), so it counts as focusable — e.g. the xApp overlay's frame.
43914
+ const interactiveEls = element?.querySelectorAll('a[href], button, input, textarea, select, details, iframe, [tabindex]:not([tabindex="-1"])');
43197
43915
  const interactiveElsArray = interactiveEls && Array.from(interactiveEls);
43198
43916
 
43199
43917
  // Two lists are derived from the interactive elements:
@@ -43536,6 +44254,113 @@ function getSourceBackgroundColor(mappedValue, colors) {
43536
44254
 
43537
44255
  /***/ },
43538
44256
 
44257
+ /***/ 44120
44258
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
44259
+
44260
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
44261
+ /* harmony export */ JO: () => (/* binding */ getSpeechRecognitionErrorMessage),
44262
+ /* harmony export */ oC: () => (/* binding */ createSpeechRecognition),
44263
+ /* harmony export */ r0: () => (/* binding */ TRANSCRIPT_IDLE_TIMEOUT_MS),
44264
+ /* harmony export */ rt: () => (/* binding */ FIRST_TRANSCRIPT_TIMEOUT_MS)
44265
+ /* harmony export */ });
44266
+ /**
44267
+ * Web Speech API plumbing for the message input's speech-to-text button.
44268
+ *
44269
+ * The spec says nothing about latency, and engines differ by seconds — which
44270
+ * is what CGY-37417 turned out to be. Measured on macOS with a real
44271
+ * microphone, one spoken sentence, `continuous`/`interimResults` both on:
44272
+ *
44273
+ * | event | Chrome 152 | Edge 152 |
44274
+ * | --------------------------- | ---------- | ------------- |
44275
+ * | `audiostart` after `start()`| 0.55 s | 0.52 s |
44276
+ * | `speechstart` -> 1st result | 0.00 s | 0.32 - 4.25 s |
44277
+ * | `start()` -> 1st transcript | 1.37 s | 5.02 - 6.65 s |
44278
+ *
44279
+ * Chrome streams an interim result in the same tick as `speechstart`; Edge
44280
+ * buffers whole phrases against its cloud service and can take over six
44281
+ * seconds to hand back the first word. Edge also emits *placeholder* results
44282
+ * — `isFinal` with an empty transcript — when speech starts and again on
44283
+ * `stop()`, which Chrome never does. Any timing budget here has to hold for
44284
+ * the slow engine, and any result handler has to tolerate empty transcripts.
44285
+ */
44286
+
44287
+ /**
44288
+ * How long to wait after `start()` for the engine's first transcript before
44289
+ * giving up and telling the user nothing was heard.
44290
+ *
44291
+ * This has to cover the permission prompt (on first use the clock is already
44292
+ * running while the user hunts for the browser's "Allow" button), the
44293
+ * engine's connection to its speech service, the user pausing to collect
44294
+ * their thoughts, and then the engine's own recognition latency — 6.65 s of
44295
+ * it on Edge. The previous budget was 3 s counted from `start()`, so on Edge
44296
+ * recognition was routinely cancelled before it had produced a single word,
44297
+ * and the failure was silent (CGY-37417).
44298
+ */
44299
+ const FIRST_TRANSCRIPT_TIMEOUT_MS = 15000;
44300
+
44301
+ /**
44302
+ * How long to keep listening after the last transcript before auto-stopping,
44303
+ * so the user doesn't have to press the button a second time.
44304
+ *
44305
+ * Only armed once the engine has actually produced a transcript, which is
44306
+ * what makes 3 s safe: while speech is flowing, consecutive results arrive
44307
+ * ~0.2 - 0.7 s apart on both engines. Before the first transcript,
44308
+ * FIRST_TRANSCRIPT_TIMEOUT_MS applies instead.
44309
+ */
44310
+ const TRANSCRIPT_IDLE_TIMEOUT_MS = 3000;
44311
+
44312
+ /** Reasons recognition can fail, beyond the spec's own error codes. */
44313
+
44314
+ /**
44315
+ * Creates a recognizer, or `null` where the browser has no Web Speech API
44316
+ * (Firefox, and WebViews that drop it). Callers treat `null` as
44317
+ * "speech-to-text unsupported" and disable the button.
44318
+ */
44319
+ const createSpeechRecognition = () => {
44320
+ const Recognition = typeof SpeechRecognition !== "undefined" ? SpeechRecognition : typeof webkitSpeechRecognition !== "undefined" ? webkitSpeechRecognition : null;
44321
+ if (!Recognition) return null;
44322
+ try {
44323
+ return new Recognition();
44324
+ } catch {
44325
+ // Constructing can still throw where the API is present but disabled
44326
+ // by policy or an unsupported embedding context.
44327
+ return null;
44328
+ }
44329
+ };
44330
+
44331
+ /**
44332
+ * Maps a failure onto the message shown to the user, so a failed dictation
44333
+ * says what went wrong and what to do instead of failing silently
44334
+ * (SC 3.3.1 Error Identification).
44335
+ */
44336
+ const getSpeechRecognitionErrorMessage = (failure, customTranslations) => {
44337
+ switch (failure) {
44338
+ // The user (or a policy) blocked the microphone. Only they can undo
44339
+ // it, and only in browser settings — the prompt won't come back.
44340
+ // NOT `service-not-allowed`, which per the spec means the recognition
44341
+ // *service* was refused and says nothing about microphone access;
44342
+ // sending those users to their microphone settings would be a wrong
44343
+ // remedy, so it falls through to the generic message below.
44344
+ case "not-allowed":
44345
+ return customTranslations?.speech_recognition_not_allowed ?? "Microphone access is blocked. Allow it in your browser settings to use speech input.";
44346
+ case "audio-capture":
44347
+ return customTranslations?.speech_recognition_no_microphone ?? "No microphone was found. Connect one to use speech input.";
44348
+ case "no-speech":
44349
+ case "no-transcript":
44350
+ return customTranslations?.speech_recognition_no_speech ?? "No speech was detected. Please try again.";
44351
+
44352
+ // "network" is the engine's speech service being unreachable;
44353
+ // "service-not-allowed" is that service being refused to this page;
44354
+ // "language-not-supported" and "bad-grammar" are misconfiguration the
44355
+ // end user cannot act on (both are logged for the operator instead).
44356
+ // None of these have a remedy the user can apply beyond typing.
44357
+ default:
44358
+ return customTranslations?.speech_recognition_error ?? "Speech input is currently unavailable. Please type your message instead.";
44359
+ }
44360
+ };
44361
+
44362
+ /***/ },
44363
+
43539
44364
  /***/ 61395
43540
44365
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
43541
44366
 
@@ -43547,12 +44372,14 @@ function getSourceBackgroundColor(mappedValue, colors) {
43547
44372
  /* harmony import */ var _store_messages_message_middleware__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(20570);
43548
44373
  /* harmony import */ var _store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(55361);
43549
44374
  /* harmony import */ var _plugins_helper__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(59977);
43550
- /* harmony import */ var _store_connection_connection_middleware__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(12193);
44375
+ /* harmony import */ var _store_connection_connection_reducer__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(64789);
43551
44376
  /* harmony import */ var _store_rating_rating_reducer__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(69823);
43552
- /* harmony import */ var _store_previous_conversations_previous_conversations_middleware__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(92101);
44377
+ /* harmony import */ var _store_previous_conversations_previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(39801);
43553
44378
  /* harmony import */ var _store_input_input_reducer__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(16967);
43554
44379
  /* harmony import */ var _store_xapp_overlay_slice__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(97114);
43555
44380
  /* harmony import */ var _store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(22284);
44381
+ /* harmony import */ var _store_options_persisted_conversation__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(57589);
44382
+
43556
44383
 
43557
44384
 
43558
44385
 
@@ -43622,6 +44449,7 @@ const ConnectedWebchatUI = (0,react_redux__WEBPACK_IMPORTED_MODULE_1__/* .connec
43622
44449
  unseenMessages,
43623
44450
  prevConversations,
43624
44451
  hasRestoredPersistedHistory,
44452
+ willRestorePersistedConversation: (0,_store_options_persisted_conversation__WEBPACK_IMPORTED_MODULE_11__/* .hasPersistedConversationForInitialSession */ ._)(state),
43625
44453
  open,
43626
44454
  typingIndicator: typing,
43627
44455
  inputMode,
@@ -43663,14 +44491,14 @@ const ConnectedWebchatUI = (0,react_redux__WEBPACK_IMPORTED_MODULE_1__/* .connec
43663
44491
  onMinimize: () => dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__/* .setMinimize */ .R1)()),
43664
44492
  onToggle: () => dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__/* .toggleOpen */ .nL)()),
43665
44493
  onTriggerEngagementMessage: () => dispatch((0,_store_messages_message_middleware__WEBPACK_IMPORTED_MODULE_2__/* .triggerEngagementMessage */ .Nh)()),
43666
- onConnect: () => dispatch((0,_store_connection_connection_middleware__WEBPACK_IMPORTED_MODULE_5__/* .connect */ .Ng)()),
44494
+ onConnect: () => dispatch((0,_store_connection_connection_reducer__WEBPACK_IMPORTED_MODULE_5__/* .connect */ .Ng)()),
43667
44495
  onShowRatingScreen: show => dispatch((0,_store_rating_rating_reducer__WEBPACK_IMPORTED_MODULE_6__/* .showRatingScreen */ .xW)(show)),
43668
44496
  onSetHasGivenRating: () => dispatch((0,_store_rating_rating_reducer__WEBPACK_IMPORTED_MODULE_6__/* .setHasGivenRating */ .n_)()),
43669
44497
  onSetShowHomeScreen: show => dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__/* .setShowHomeScreen */ .zn)(show)),
43670
44498
  onSetShowPrevConversations: show => dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__/* .setShowPrevConversations */ .Rg)(show)),
43671
44499
  onSetShowChatOptionsScreen: show => dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__/* .setShowChatOptionsScreen */ .QE)(show)),
43672
44500
  onShowChatScreen: () => dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__/* .showChatScreen */ .YW)()),
43673
- onSwitchSession: (sessionId, conversation) => dispatch((0,_store_previous_conversations_previous_conversations_middleware__WEBPACK_IMPORTED_MODULE_7__/* .switchSession */ .r)(sessionId, conversation)),
44501
+ onSwitchSession: (sessionId, conversation) => dispatch((0,_store_previous_conversations_previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_7__/* .switchSession */ .rm)(sessionId, conversation)),
43674
44502
  onAcceptTerms: userId => dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__/* .setHasAcceptedTerms */ .Pk)(userId)),
43675
44503
  onSetStoredMessage: message => dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_3__/* .setStoredMessage */ .LK)(message)),
43676
44504
  onSetDropZoneVisible: isVisible => dispatch((0,_store_input_input_reducer__WEBPACK_IMPORTED_MODULE_8__/* .setDropZoneVisible */ .aJ)(isVisible)),
@@ -43712,19 +44540,20 @@ const ConnectedWebchatUI = (0,react_redux__WEBPACK_IMPORTED_MODULE_1__/* .connec
43712
44540
  /* harmony import */ var _store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(55361);
43713
44541
  /* harmony import */ var _store_config_config_middleware__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(56121);
43714
44542
  /* harmony import */ var _store_connection_connection_middleware__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(12193);
43715
- /* harmony import */ var events__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(98657);
43716
- /* harmony import */ var events__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(events__WEBPACK_IMPORTED_MODULE_8__);
43717
- /* harmony import */ var _cognigy_socket_client__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(72166);
43718
- /* harmony import */ var _cognigy_socket_client__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(_cognigy_socket_client__WEBPACK_IMPORTED_MODULE_9__);
43719
- /* harmony import */ var _helper_endpoint__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(11351);
43720
- /* harmony import */ var _store_config_config_reducer__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(46509);
43721
- /* harmony import */ var _store_messages_message_handler__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(59788);
43722
- /* harmony import */ var _webchat_ui_components_presentational_Notifications__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(82833);
43723
- /* harmony import */ var _helper_storage__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(62473);
43724
- /* harmony import */ var _helper_privacyPolicy__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(8470);
43725
- /* harmony import */ var _store_options_options_reducer__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(74327);
43726
- /* harmony import */ var _store_previous_conversations_previous_conversations_middleware__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(92101);
43727
- /* harmony import */ var _store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(22284);
44543
+ /* harmony import */ var _store_connection_connection_reducer__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(64789);
44544
+ /* harmony import */ var events__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(98657);
44545
+ /* harmony import */ var events__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(events__WEBPACK_IMPORTED_MODULE_9__);
44546
+ /* harmony import */ var _cognigy_socket_client__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(72166);
44547
+ /* harmony import */ var _cognigy_socket_client__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(_cognigy_socket_client__WEBPACK_IMPORTED_MODULE_10__);
44548
+ /* harmony import */ var _helper_endpoint__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(11351);
44549
+ /* harmony import */ var _store_config_config_reducer__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(46509);
44550
+ /* harmony import */ var _store_messages_message_handler__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(59788);
44551
+ /* harmony import */ var _webchat_ui_components_presentational_Notifications__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(82833);
44552
+ /* harmony import */ var _helper_storage__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(62473);
44553
+ /* harmony import */ var _helper_privacyPolicy__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(8470);
44554
+ /* harmony import */ var _store_options_options_reducer__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(74327);
44555
+ /* harmony import */ var _store_previous_conversations_previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(39801);
44556
+ /* harmony import */ var _store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(22284);
43728
44557
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
43729
44558
 
43730
44559
 
@@ -43745,8 +44574,9 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
43745
44574
 
43746
44575
 
43747
44576
 
44577
+
43748
44578
  class Webchat extends react__WEBPACK_IMPORTED_MODULE_0__.PureComponent {
43749
- analytics = new events__WEBPACK_IMPORTED_MODULE_8__.EventEmitter();
44579
+ analytics = new events__WEBPACK_IMPORTED_MODULE_9__.EventEmitter();
43750
44580
  // component lifecycle methods
43751
44581
  constructor(props) {
43752
44582
  super(props);
@@ -43755,17 +44585,17 @@ class Webchat extends react__WEBPACK_IMPORTED_MODULE_0__.PureComponent {
43755
44585
  options,
43756
44586
  settings
43757
44587
  } = props;
43758
- const baseUrl = (0,_helper_endpoint__WEBPACK_IMPORTED_MODULE_10__/* .getEndpointBaseUrl */ .Ul)(url);
43759
- const token = (0,_helper_endpoint__WEBPACK_IMPORTED_MODULE_10__/* .getEndpointUrlToken */ .a4)(url);
44588
+ const baseUrl = (0,_helper_endpoint__WEBPACK_IMPORTED_MODULE_11__/* .getEndpointBaseUrl */ .Ul)(url);
44589
+ const token = (0,_helper_endpoint__WEBPACK_IMPORTED_MODULE_11__/* .getEndpointUrlToken */ .a4)(url);
43760
44590
  const socketOptions = {
43761
44591
  channel: options?.channel || "webchat3",
43762
44592
  ...options
43763
44593
  };
43764
- const client = new _cognigy_socket_client__WEBPACK_IMPORTED_MODULE_9__.SocketClient(baseUrl, token, socketOptions);
44594
+ const client = new _cognigy_socket_client__WEBPACK_IMPORTED_MODULE_10__.SocketClient(baseUrl, token, socketOptions);
43765
44595
  this.client = client;
43766
44596
  const store = (0,_store_store__WEBPACK_IMPORTED_MODULE_1__/* .createWebchatStore */ .E7)(this, url, settings);
43767
44597
  this.store = store;
43768
- this._handleOutput = (0,_store_messages_message_handler__WEBPACK_IMPORTED_MODULE_12__/* .createOutputHandler */ .i0)(this.store);
44598
+ this._handleOutput = (0,_store_messages_message_handler__WEBPACK_IMPORTED_MODULE_13__/* .createOutputHandler */ .i0)(this.store);
43769
44599
  }
43770
44600
  UNSAFE_componentWillMount() {
43771
44601
  const {
@@ -43773,20 +44603,20 @@ class Webchat extends react__WEBPACK_IMPORTED_MODULE_0__.PureComponent {
43773
44603
  } = this.props;
43774
44604
  const disableLocalStorage = settings?.embeddingConfiguration?.disableLocalStorage ?? false;
43775
44605
  const useSessionStorage = settings?.embeddingConfiguration?.useSessionStorage ?? false;
43776
- const browserStorage = (0,_helper_storage__WEBPACK_IMPORTED_MODULE_14__/* .getStorage */ .c)({
44606
+ const browserStorage = (0,_helper_storage__WEBPACK_IMPORTED_MODULE_15__/* .getStorage */ .c)({
43777
44607
  disableLocalStorage,
43778
44608
  useSessionStorage
43779
44609
  });
43780
44610
  const userId = this.client.socketOptions.userId;
43781
- if ((0,_helper_privacyPolicy__WEBPACK_IMPORTED_MODULE_15__/* .hasAcceptedTermsInStorage */ .z)(browserStorage, userId)) {
44611
+ if ((0,_helper_privacyPolicy__WEBPACK_IMPORTED_MODULE_16__/* .hasAcceptedTermsInStorage */ .z)(browserStorage, userId)) {
43782
44612
  this.store.dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_5__/* .setHasAcceptedTerms */ .Pk)(userId));
43783
44613
  }
43784
44614
  this.store.dispatch((0,_store_config_config_middleware__WEBPACK_IMPORTED_MODULE_6__/* .loadConfig */ .Z)());
43785
44615
  if (this.props.options?.sessionId) {
43786
- this.store.dispatch((0,_store_config_config_reducer__WEBPACK_IMPORTED_MODULE_11__/* .setInitialSessionId */ .mD)(this.props.options.sessionId));
44616
+ this.store.dispatch((0,_store_config_config_reducer__WEBPACK_IMPORTED_MODULE_12__/* .setInitialSessionId */ .mD)(this.props.options.sessionId));
43787
44617
  }
43788
44618
  if (this.props.options?.userId) {
43789
- this.store.dispatch((0,_store_options_options_reducer__WEBPACK_IMPORTED_MODULE_16__/* .setUserId */ ["do"])(this.props.options?.userId));
44619
+ this.store.dispatch((0,_store_options_options_reducer__WEBPACK_IMPORTED_MODULE_17__/* .setUserId */ ["do"])(this.props.options?.userId));
43790
44620
  }
43791
44621
  }
43792
44622
  componentWillUnmount() {
@@ -43804,7 +44634,7 @@ class Webchat extends react__WEBPACK_IMPORTED_MODULE_0__.PureComponent {
43804
44634
 
43805
44635
  // component API (for usage via ref)
43806
44636
  connect = async () => {
43807
- this.store.dispatch((0,_store_connection_connection_middleware__WEBPACK_IMPORTED_MODULE_7__/* .connect */ .Ng)());
44637
+ this.store.dispatch((0,_store_connection_connection_reducer__WEBPACK_IMPORTED_MODULE_8__/* .connect */ .Ng)());
43808
44638
  };
43809
44639
 
43810
44640
  /**
@@ -43836,14 +44666,14 @@ class Webchat extends react__WEBPACK_IMPORTED_MODULE_0__.PureComponent {
43836
44666
  } = this.store.getState().config;
43837
44667
  const disableLocalStorage = settings?.embeddingConfiguration?.disableLocalStorage ?? false;
43838
44668
  const useSessionStorage = settings?.embeddingConfiguration?.useSessionStorage ?? false;
43839
- const browserStorage = (0,_helper_storage__WEBPACK_IMPORTED_MODULE_14__/* .getStorage */ .c)({
44669
+ const browserStorage = (0,_helper_storage__WEBPACK_IMPORTED_MODULE_15__/* .getStorage */ .c)({
43840
44670
  disableLocalStorage,
43841
44671
  useSessionStorage
43842
44672
  });
43843
44673
  const userId = this.client.socketOptions.userId;
43844
44674
  const homeScreenEnabled = settings?.homeScreen?.enabled === true;
43845
44675
  const privacyNoticeEnabled = settings?.privacyNotice?.enabled === true;
43846
- const skipPrivacyNotice = !privacyNoticeEnabled || (0,_helper_privacyPolicy__WEBPACK_IMPORTED_MODULE_15__/* .hasAcceptedTermsInStorage */ .z)(browserStorage, userId);
44676
+ const skipPrivacyNotice = !privacyNoticeEnabled || (0,_helper_privacyPolicy__WEBPACK_IMPORTED_MODULE_16__/* .hasAcceptedTermsInStorage */ .z)(browserStorage, userId);
43847
44677
  if (!homeScreenEnabled && skipPrivacyNotice) {
43848
44678
  this.store.dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_5__/* .setShowHomeScreen */ .zn)(false));
43849
44679
  this.store.dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_5__/* .setShowChatOptionsScreen */ .QE)(false));
@@ -43881,7 +44711,7 @@ class Webchat extends react__WEBPACK_IMPORTED_MODULE_0__.PureComponent {
43881
44711
  this.store.dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_5__/* .toggleOpen */ .nL)());
43882
44712
  };
43883
44713
  showNotification = message => {
43884
- (0,_webchat_ui_components_presentational_Notifications__WEBPACK_IMPORTED_MODULE_13__/* .createNotification */ .UI)(message);
44714
+ (0,_webchat_ui_components_presentational_Notifications__WEBPACK_IMPORTED_MODULE_14__/* .createNotification */ .UI)(message);
43885
44715
  };
43886
44716
  startConversation = () => {
43887
44717
  this.store.dispatch((0,_store_ui_ui_reducer__WEBPACK_IMPORTED_MODULE_5__/* .setShowHomeScreen */ .zn)(false));
@@ -43894,15 +44724,15 @@ class Webchat extends react__WEBPACK_IMPORTED_MODULE_0__.PureComponent {
43894
44724
  this.client.on("output", handler);
43895
44725
  };
43896
44726
  updateSettings = settings => {
43897
- this.store.dispatch((0,_store_config_config_reducer__WEBPACK_IMPORTED_MODULE_11__/* .updateSettings */ .Xx)(settings));
44727
+ this.store.dispatch((0,_store_config_config_reducer__WEBPACK_IMPORTED_MODULE_12__/* .updateSettings */ .Xx)(settings));
43898
44728
  };
43899
44729
 
43900
44730
  /**
43901
44731
  * This method will switch to a new session and clear the messages in the current session.
43902
44732
  */
43903
44733
  endSession = () => {
43904
- this.store.dispatch((0,_store_previous_conversations_previous_conversations_middleware__WEBPACK_IMPORTED_MODULE_17__/* .switchSession */ .r)());
43905
- this.store.dispatch((0,_store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_18__/* .clearMessages */ .oI)());
44734
+ this.store.dispatch((0,_store_previous_conversations_previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_18__/* .switchSession */ .rm)());
44735
+ this.store.dispatch((0,_store_messages_message_reducer__WEBPACK_IMPORTED_MODULE_19__/* .clearMessages */ .oI)());
43906
44736
  };
43907
44737
  render() {
43908
44738
  const {
@@ -44029,7 +44859,7 @@ const isInformingOutOfBusinessHours = businessHours => {
44029
44859
  /* harmony export */ R: () => (/* binding */ onNetworkOn),
44030
44860
  /* harmony export */ s: () => (/* binding */ shouldReestablishConnection)
44031
44861
  /* harmony export */ });
44032
- const shouldReestablishConnection = store => store?.autoInject?.isConnectedOnce;
44862
+ const shouldReestablishConnection = store => store?.connection?.hasAttemptedConnection;
44033
44863
  const onNetworkOn = handler => {
44034
44864
  window.addEventListener("online", handler, false);
44035
44865
  return () => {
@@ -44367,8 +45197,33 @@ function setHasAcceptedTermsInStorage(browserStorage, userId) {
44367
45197
  /* harmony import */ var _store_store__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6236);
44368
45198
 
44369
45199
 
44370
- const allowedHtmlTags = ["a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio", "b", "base", "basefont", "bdi", "bdo", "big", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "data", "datalist", "dd", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", "figure", "font", "footer", "form", "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "label", "legend", "li", "link", "main", "map", "mark", "meta", "meter", "nav", "noframes", "object", "ol", "optgroup", "option", "output", "p", "param", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "section", "select", "small", "source", "span", "strike", "strong", "style", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"];
44371
- const allowedHtmlAttributes = ["accept", "accept-charset", "accesskey", "action", "align", "alt", "autocomplete", "autofocus", "autoplay", "bgcolor", "border", "charset", "checked", "cite", "class", "color", "cols", "colspan", "content", "contenteditable", "controls", "coords", "data", "data-*", "datetime", "default", "dir", "dirname", "disabled", "download", "draggable", "dropzone", "enctype", "for", "form", "formaction", "headers", "height", "hidden", "high", "href", "hreflang", "http-equiv", "id", "ismap", "kind", "label", "lang", "list", "loop", "low", "max", "maxlength", "media", "method", "min", "multiple", "muted", "name", "novalidate", "open", "optimum", "pattern", "placeholder", "poster", "preload", "readonly", "rel", "required", "reversed", "rows", "rowspan", "sandbox", "scope", "selected", "shape", "size", "sizes", "span", "spellcheck", "src", "srcdoc", "srclang", "srcset", "start", "step", "style", "tabindex", "target", "title", "translate", "type", "usemap", "value", "width", "wrap"];
45200
+
45201
+ // Tags removed from the previous allow-list to align with DOMPurify's secure defaults
45202
+ // (WCH-SI10-001). Each tag enables a distinct attack vector:
45203
+ // applet — Java applet execution
45204
+ // base — rewrites all relative URLs on the host page
45205
+ // body / html / head — structural document elements; no legitimate use in sanitised fragments
45206
+ // embed — loads arbitrary external content / plugins
45207
+ // form — posts user data to attacker-controlled URLs
45208
+ // frame / frameset / noframes — clickjacking and legacy frame injection
45209
+ // iframe — inline HTML documents; srcdoc = direct XSS vector
45210
+ // link — loads external stylesheets
45211
+ // meta — HTTP redirects and CSP bypass via http-equiv
45212
+ // object — loads Flash, PDFs, and arbitrary external content
45213
+ // style — CSS injection and attribute-value exfiltration
45214
+ // These tags are blocked by default when no custom tag list is configured.
45215
+ // Tenants can supply a replacement list via widgetSettings.customAllowedHtmlTags,
45216
+ // but dangerous tags are always stripped from that list before it is applied (PR #309).
45217
+ const allowedHtmlTags = ["a", "abbr", "acronym", "address", "area", "article", "aside", "audio", "b", "basefont", "bdi", "bdo", "big", "blockquote", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "data", "datalist", "dd", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "em", "fieldset", "figcaption", "figure", "font", "footer", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hr", "i", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "map", "mark", "meter", "nav", "ol", "optgroup", "option", "output", "p", "param", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "section", "select", "small", "source", "span", "strike", "strong", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"];
45218
+
45219
+ // Attributes that are always blocked regardless of caller configuration (WCH-SI10-001).
45220
+ // Removed from the previous allow-list:
45221
+ // action / formaction — form submission to attacker-controlled URLs
45222
+ // sandbox — giving content control over its own sandbox policy
45223
+ // srcdoc — inline HTML document in an iframe (direct XSS vector)
45224
+ // style — inline CSS injection and attribute-value exfiltration
45225
+ // target — controls navigation target (_blank without rel is risky)
45226
+ const allowedHtmlAttributes = ["accept", "accept-charset", "accesskey", "align", "alt", "autocomplete", "autofocus", "autoplay", "bgcolor", "border", "charset", "checked", "cite", "class", "color", "cols", "colspan", "content", "contenteditable", "controls", "coords", "data", "data-*", "datetime", "default", "dir", "dirname", "disabled", "download", "draggable", "dropzone", "enctype", "for", "form", "headers", "height", "hidden", "high", "href", "hreflang", "http-equiv", "id", "ismap", "kind", "label", "lang", "list", "loop", "low", "max", "maxlength", "media", "method", "min", "multiple", "muted", "name", "novalidate", "open", "optimum", "pattern", "placeholder", "poster", "preload", "readonly", "rel", "required", "reversed", "rows", "rowspan", "scope", "selected", "shape", "size", "sizes", "span", "spellcheck", "src", "srclang", "srcset", "start", "step", "tabindex", "title", "translate", "type", "usemap", "value", "width", "wrap"];
44372
45227
  const config = {
44373
45228
  ALLOWED_TAGS: allowedHtmlTags,
44374
45229
  ALLOWED_ATTR: allowedHtmlAttributes
@@ -45058,7 +45913,6 @@ const registerConnectionHandler = (store, client) => {
45058
45913
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
45059
45914
 
45060
45915
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
45061
- /* harmony export */ Ng: () => (/* binding */ connect),
45062
45916
  /* harmony export */ PJ: () => (/* binding */ createConnectionMiddleware),
45063
45917
  /* harmony export */ Zf: () => (/* binding */ disconnect),
45064
45918
  /* harmony export */ vD: () => (/* binding */ announceNetworkOn)
@@ -45073,10 +45927,6 @@ const registerConnectionHandler = (store, client) => {
45073
45927
 
45074
45928
 
45075
45929
 
45076
- const CONNECT = "CONNECT";
45077
- const connect = () => ({
45078
- type: CONNECT
45079
- });
45080
45930
  const DISCONNECT = "DISCONNECT";
45081
45931
  const disconnect = () => ({
45082
45932
  type: DISCONNECT
@@ -45116,19 +45966,19 @@ const createConnectionMiddleware = client => store => next => action => {
45116
45966
  case "SHOW_CHAT_SCREEN":
45117
45967
  {
45118
45968
  if (!client.connected) {
45119
- store.dispatch(connect());
45969
+ store.dispatch((0,_connection_reducer__WEBPACK_IMPORTED_MODULE_3__/* .connect */ .Ng)());
45120
45970
  }
45121
45971
  break;
45122
45972
  }
45123
45973
  case "SEND_MESSAGE":
45124
45974
  {
45125
- store.dispatch(connect());
45975
+ store.dispatch((0,_connection_reducer__WEBPACK_IMPORTED_MODULE_3__/* .connect */ .Ng)());
45126
45976
  break;
45127
45977
  }
45128
45978
  case "SET_PAGE_VISIBLE":
45129
45979
  {
45130
45980
  if (action.visible && (0,_helper_connection_watchdog__WEBPACK_IMPORTED_MODULE_4__/* .shouldReestablishConnection */ .s)(store.getState())) {
45131
- store.dispatch(connect());
45981
+ store.dispatch((0,_connection_reducer__WEBPACK_IMPORTED_MODULE_3__/* .connect */ .Ng)());
45132
45982
  }
45133
45983
  break;
45134
45984
  }
@@ -45140,7 +45990,7 @@ const createConnectionMiddleware = client => store => next => action => {
45140
45990
  case "NETWORK_ON":
45141
45991
  {
45142
45992
  if ((0,_helper_connection_watchdog__WEBPACK_IMPORTED_MODULE_4__/* .shouldReestablishConnection */ .s)(store.getState())) {
45143
- store.dispatch(connect());
45993
+ store.dispatch((0,_connection_reducer__WEBPACK_IMPORTED_MODULE_3__/* .connect */ .Ng)());
45144
45994
  }
45145
45995
  break;
45146
45996
  }
@@ -45155,16 +46005,22 @@ const createConnectionMiddleware = client => store => next => action => {
45155
46005
 
45156
46006
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
45157
46007
  /* harmony export */ FI: () => (/* binding */ connection),
46008
+ /* harmony export */ Ng: () => (/* binding */ connect),
45158
46009
  /* harmony export */ Pr: () => (/* binding */ setReconnectionLimit),
45159
46010
  /* harmony export */ pE: () => (/* binding */ setConnecting),
45160
46011
  /* harmony export */ qJ: () => (/* binding */ setConnected)
45161
46012
  /* harmony export */ });
45162
- /* unused harmony exports SET_CONNECTING, SET_CONNECTED, SET_RECONNECTION_LIMIT */
46013
+ /* unused harmony exports CONNECT, SET_CONNECTING, SET_CONNECTED, SET_RECONNECTION_LIMIT */
45163
46014
  const initialState = {
45164
46015
  connected: false,
45165
46016
  connecting: false,
45166
- reconnectionLimit: false
46017
+ reconnectionLimit: false,
46018
+ hasAttemptedConnection: false
45167
46019
  };
46020
+ const CONNECT = "CONNECT";
46021
+ const connect = () => ({
46022
+ type: CONNECT
46023
+ });
45168
46024
  const SET_CONNECTING = "SET_CONNECTING";
45169
46025
  const setConnecting = connecting => ({
45170
46026
  type: SET_CONNECTING,
@@ -45186,7 +46042,10 @@ const connection = (state = initialState, action) => {
45186
46042
  {
45187
46043
  return {
45188
46044
  ...state,
45189
- connected: action.connected
46045
+ connected: action.connected,
46046
+ // Never reset once true: a past connection attempt is what gates
46047
+ // automatic reconnection, regardless of the current connected state.
46048
+ hasAttemptedConnection: state.hasAttemptedConnection || action.connected
45190
46049
  };
45191
46050
  }
45192
46051
  case "SET_CONNECTING":
@@ -45203,6 +46062,18 @@ const connection = (state = initialState, action) => {
45203
46062
  reconnectionLimit: action.reconnectionLimit
45204
46063
  };
45205
46064
  }
46065
+ case "CONNECT":
46066
+ case "SWITCH_SESSION":
46067
+ {
46068
+ // A session switch connects the socket directly, bypassing CONNECT.
46069
+ // It is still a deliberate connection request, so it must arm the
46070
+ // reconnect latch even if this first attempt fails (e.g. offline).
46071
+ if (state.hasAttemptedConnection) return state;
46072
+ return {
46073
+ ...state,
46074
+ hasAttemptedConnection: true
46075
+ };
46076
+ }
45206
46077
  default:
45207
46078
  {
45208
46079
  return state;
@@ -45583,8 +46454,10 @@ const input = (state = getInitialState(), action) => {
45583
46454
  /* harmony export */ mN: () => (/* binding */ isAnimatedRichBotMessage),
45584
46455
  /* harmony export */ oy: () => (/* binding */ isTextOnlyEscapeSequence)
45585
46456
  /* harmony export */ });
46457
+ /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55252);
46458
+
45586
46459
  function generateRandomId() {
45587
- return String(Math.random()).slice(2, 18);
46460
+ return crypto.randomUUID?.() ?? (0,uuid__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A)();
45588
46461
  }
45589
46462
  function isAnimatedRichBotMessage(message) {
45590
46463
  const {
@@ -45884,7 +46757,7 @@ const createMessageMiddleware = client => store => next => action => {
45884
46757
  if (text) {
45885
46758
  store.dispatch((0,_message_handler__WEBPACK_IMPORTED_MODULE_2__/* .receiveMessage */ .VI)({
45886
46759
  source: "engagement",
45887
- traceId: `engagement-${Math.random()}`,
46760
+ traceId: `engagement-${(0,_helper__WEBPACK_IMPORTED_MODULE_5__/* .generateRandomId */ .MZ)()}`,
45888
46761
  text
45889
46762
  }));
45890
46763
  }
@@ -46326,11 +47199,128 @@ const getOptionsKey = ({
46326
47199
 
46327
47200
  /***/ },
46328
47201
 
47202
+ /***/ 57589
47203
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
47204
+
47205
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
47206
+ /* harmony export */ _: () => (/* binding */ hasPersistedConversationForInitialSession)
47207
+ /* harmony export */ });
47208
+ /* harmony import */ var _options__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(48242);
47209
+ /* harmony import */ var _helper_storage__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(62473);
47210
+
47211
+
47212
+
47213
+ /**
47214
+ * Whether browser storage already holds a non-empty conversation for the
47215
+ * session this page load will connect with — i.e. whether the first
47216
+ * connect is going to restore a conversation rather than start one.
47217
+ *
47218
+ * This answers, BEFORE the socket connects, the question the AI-agent
47219
+ * notice needs answered (CGY-3519): a restored conversation is a
47220
+ * continuation and must not be announced. Waiting for the connect to
47221
+ * tell us instead is not an option — it can take longer than the
47222
+ * notice's 600ms announce delay, and an announcement cannot be taken
47223
+ * back.
47224
+ *
47225
+ * It deliberately mirrors the restore in `optionsMiddleware`'s
47226
+ * `SET_OPTIONS` handler: same `getStorage`, same `getOptionsKey`, same
47227
+ * "non-empty messages" condition that `RESET_STATE` uses to set
47228
+ * `hasRestoredPersistedHistory`. Reading the same inputs through the
47229
+ * same helpers is what keeps the prediction and the restore aligned —
47230
+ * including when they agree on "no": if the endpoint config (and with it
47231
+ * `URLToken`) has not loaded yet, the key misses here exactly as it
47232
+ * misses there, and nothing is restored either. The one case where they
47233
+ * part company is benign: a message sent before the first connect is
47234
+ * dispatched ahead of `setOptions`, so `RESET_STATE` finds a non-empty
47235
+ * history and skips the restore while this still says "continued" — the
47236
+ * session IS a continuation for the backend, so staying silent remains
47237
+ * the right outcome.
47238
+ *
47239
+ * `config.initialSessionId` is the pinned `sessionId` from the embedding
47240
+ * options. Without one, the socket client mints a fresh session id per
47241
+ * page load, which no stored entry can match, so there is nothing to
47242
+ * predict.
47243
+ */
47244
+ // mapStateToProps runs on every dispatch and a persisted conversation can
47245
+ // be sizeable, so this must not sit on the hot path: the parse is cached
47246
+ // against the raw string it was derived from, and the read stops
47247
+ // altogether once the answer is spent (see below). Until then `getItem`
47248
+ // runs on every call, which is what keeps the answer current — the key
47249
+ // changes once the endpoint config supplies its URLToken.
47250
+ let lastRead = null;
47251
+ const hasPersistedConversationForInitialSession = state => {
47252
+ const sessionId = state.config.initialSessionId;
47253
+ if (!sessionId) return false;
47254
+
47255
+ // This page load ended up on a session other than the pinned one, so
47256
+ // nothing stored under the pinned key is being restored into it and
47257
+ // there is nothing to predict. "Start new conversation" from the
47258
+ // conversations list does this before the first connect
47259
+ // (`SWITCH_SESSION` with no id mints a fresh session id), and without
47260
+ // this guard that brand-new conversation would inherit the pinned
47261
+ // session's "continued" verdict and never be announced — the mirror
47262
+ // image of the bug this predicate exists for. A REopened previous
47263
+ // conversation also lands here, and is correctly silenced by the
47264
+ // `prevConversations` snapshot instead.
47265
+ if (state.options.sessionId && state.options.sessionId !== sessionId) return false;
47266
+ const {
47267
+ disableLocalStorage,
47268
+ useSessionStorage
47269
+ } = state.config.settings.embeddingConfiguration;
47270
+ try {
47271
+ const browserStorage = (0,_helper_storage__WEBPACK_IMPORTED_MODULE_1__/* .getStorage */ .c)({
47272
+ disableLocalStorage,
47273
+ useSessionStorage
47274
+ });
47275
+ if (!browserStorage) return false;
47276
+
47277
+ // `channel` is not part of the storage key; it is only in the type.
47278
+ const key = (0,_options__WEBPACK_IMPORTED_MODULE_0__/* .getOptionsKey */ .W)({
47279
+ userId: state.options.userId,
47280
+ sessionId,
47281
+ channel: state.options.channel
47282
+ }, state.config);
47283
+
47284
+ // Once the first connect has assigned a session id the answer is
47285
+ // spent: `computeNoticeSession` consults it only while its own
47286
+ // `prev.id` is still "". The key is final well before that (userId
47287
+ // is dispatched on mount, URLToken with the config, and the connect
47288
+ // waits for the config), so the cache is populated by then and every
47289
+ // later dispatch is served without touching storage.
47290
+ if (state.options.sessionId && lastRead?.key === key) return lastRead.result;
47291
+ const persistedString = browserStorage.getItem(key);
47292
+ if (lastRead && lastRead.key === key && lastRead.raw === persistedString) {
47293
+ return lastRead.result;
47294
+ }
47295
+ let result = false;
47296
+ if (persistedString) {
47297
+ try {
47298
+ const messages = JSON.parse(persistedString)?.messages;
47299
+ result = Array.isArray(messages) && messages.length > 0;
47300
+ } catch {
47301
+ result = false;
47302
+ }
47303
+ }
47304
+ lastRead = {
47305
+ key,
47306
+ raw: persistedString,
47307
+ result
47308
+ };
47309
+ return result;
47310
+ } catch {
47311
+ // Restricted embeddings can throw on merely touching storage. The
47312
+ // restore reads it the same way, so nothing would be restored there
47313
+ // either — "no persisted conversation" is the truthful answer.
47314
+ return false;
47315
+ }
47316
+ };
47317
+
47318
+ /***/ },
47319
+
46329
47320
  /***/ 92101
46330
47321
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
46331
47322
 
46332
47323
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
46333
- /* harmony export */ r: () => (/* binding */ switchSession),
46334
47324
  /* harmony export */ w: () => (/* binding */ createPrevConversationsMiddleware)
46335
47325
  /* harmony export */ });
46336
47326
  /* harmony import */ var _previous_conversations_reducer__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(39801);
@@ -46345,12 +47335,6 @@ const getOptionsKey = ({
46345
47335
 
46346
47336
 
46347
47337
 
46348
- const SWITCH_SESSION = "SWITCH_SESSION";
46349
- const switchSession = (sessionId = self.crypto?.randomUUID?.(), conversation) => ({
46350
- type: SWITCH_SESSION,
46351
- sessionId,
46352
- conversation
46353
- });
46354
47338
  const createPrevConversationsMiddleware = client => store => next => action => {
46355
47339
  switch (action.type) {
46356
47340
  case "SWITCH_SESSION":
@@ -46407,9 +47391,16 @@ const createPrevConversationsMiddleware = client => store => next => action => {
46407
47391
  /* harmony export */ CK: () => (/* binding */ prevConversations),
46408
47392
  /* harmony export */ Wu: () => (/* binding */ upsertPrevConversation),
46409
47393
  /* harmony export */ YD: () => (/* binding */ deletePrevConversation),
46410
- /* harmony export */ dU: () => (/* binding */ setConversations)
47394
+ /* harmony export */ dU: () => (/* binding */ setConversations),
47395
+ /* harmony export */ rm: () => (/* binding */ switchSession)
46411
47396
  /* harmony export */ });
46412
47397
  const getInitialState = () => ({});
47398
+ const SWITCH_SESSION = "SWITCH_SESSION";
47399
+ const switchSession = (sessionId = self.crypto?.randomUUID?.(), conversation) => ({
47400
+ type: SWITCH_SESSION,
47401
+ sessionId,
47402
+ conversation
47403
+ });
46413
47404
  const SET_CONVERSATIONS = "SET_CONVERSATIONS";
46414
47405
  const setConversations = conversations => ({
46415
47406
  type: SET_CONVERSATIONS,
@@ -52246,7 +53237,7 @@ function deconstructPacket(packet) {
52246
53237
  buffers: buffers
52247
53238
  };
52248
53239
  }
52249
- function _deconstructPacket(data, buffers) {
53240
+ function _deconstructPacket(data, buffers, toJSON) {
52250
53241
  if (!data) return data;
52251
53242
  if ((0, is_binary_js_1.isBinary)(data)) {
52252
53243
  const placeholder = {
@@ -52262,6 +53253,9 @@ function _deconstructPacket(data, buffers) {
52262
53253
  }
52263
53254
  return newData;
52264
53255
  } else if (typeof data === "object" && !(data instanceof Date)) {
53256
+ if (data.toJSON && typeof data.toJSON === "function" && !toJSON) {
53257
+ return _deconstructPacket(data.toJSON(), buffers, true);
53258
+ }
52265
53259
  const newData = {};
52266
53260
  for (const key in data) {
52267
53261
  if (Object.prototype.hasOwnProperty.call(data, key)) {
@@ -52315,6 +53309,11 @@ function _reconstructPacket(data, buffers) {
52315
53309
 
52316
53310
 
52317
53311
 
53312
+ var __importDefault = this && this.__importDefault || function (mod) {
53313
+ return mod && mod.__esModule ? mod : {
53314
+ "default": mod
53315
+ };
53316
+ };
52318
53317
  Object.defineProperty(exports, "__esModule", ({
52319
53318
  value: true
52320
53319
  }));
@@ -52323,7 +53322,7 @@ exports.isPacketValid = isPacketValid;
52323
53322
  const component_emitter_1 = __webpack_require__(40368);
52324
53323
  const binary_js_1 = __webpack_require__(56156);
52325
53324
  const is_binary_js_1 = __webpack_require__(10003);
52326
- const debug_1 = __webpack_require__(30887); // debug()
53325
+ const debug_1 = __importDefault(__webpack_require__(30887)); // debug()
52327
53326
  const debug = (0, debug_1.default)("socket.io-parser"); // debug()
52328
53327
  /**
52329
53328
  * These strings must not be used as event names, as they have a special meaning.
@@ -52463,10 +53462,6 @@ class Decoder extends component_emitter_1.Emitter {
52463
53462
  packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;
52464
53463
  // binary packet's json
52465
53464
  this.reconstructor = new BinaryReconstructor(packet);
52466
- // no attachments, labeled binary but no binary data to follow
52467
- if (packet.attachments === 0) {
52468
- super.emitReserved("decoded", packet);
52469
- }
52470
53465
  } else {
52471
53466
  // non-binary full packet
52472
53467
  super.emitReserved("decoded", packet);
@@ -52511,7 +53506,7 @@ class Decoder extends component_emitter_1.Emitter {
52511
53506
  throw new Error("Illegal attachments");
52512
53507
  }
52513
53508
  const n = Number(buf);
52514
- if (!isInteger(n) || n < 0) {
53509
+ if (!isInteger(n) || n < 1) {
52515
53510
  throw new Error("Illegal attachments");
52516
53511
  } else if (n > this.opts.maxAttachments) {
52517
53512
  throw new Error("too many attachments");
@@ -56748,19 +57743,19 @@ article ._wrapper_zhv80_1 ._list_zhv80_8 ._listItemRoot_zhv80_8 {
56748
57743
  ._mainButtonWrapper_zhv80_144 {
56749
57744
  padding: 16px;
56750
57745
  }
56751
- ._slideItem_ldua9_1 {
57746
+ ._slideItem_fa7bu_1 {
56752
57747
  position: relative;
56753
57748
  width: 206px;
56754
57749
  /* height: 150px; */
56755
57750
  overflow: hidden;
56756
57751
  }
56757
57752
 
56758
- ._slideItem_ldua9_1 ._top_ldua9_8 {
57753
+ ._slideItem_fa7bu_1 ._top_fa7bu_8 {
56759
57754
  position: relative;
56760
57755
  border-radius: var(--cc-bubble-border-radius);
56761
57756
  }
56762
57757
 
56763
- ._slideItem_ldua9_1 ._bottom_ldua9_13 {
57758
+ ._slideItem_fa7bu_1 ._bottom_fa7bu_13 {
56764
57759
  border-bottom-left-radius: var(--cc-bubble-border-radius);
56765
57760
  border-bottom-right-radius: var(--cc-bubble-border-radius);
56766
57761
  border: 1px solid var(--cc-black-80);
@@ -56771,7 +57766,7 @@ article ._wrapper_zhv80_1 ._list_zhv80_8 ._listItemRoot_zhv80_8 {
56771
57766
  padding: 8px;
56772
57767
  }
56773
57768
 
56774
- ._slideItem_ldua9_1 ._top_ldua9_8 img {
57769
+ ._slideItem_fa7bu_1 ._top_fa7bu_8 img {
56775
57770
  aspect-ratio: 206/150;
56776
57771
  object-fit: cover;
56777
57772
  object-position: left;
@@ -56781,7 +57776,7 @@ article ._wrapper_zhv80_1 ._list_zhv80_8 ._listItemRoot_zhv80_8 {
56781
57776
  outline: none;
56782
57777
  }
56783
57778
 
56784
- ._slideItem_ldua9_1 ._brokenImage_ldua9_34 {
57779
+ ._slideItem_fa7bu_1 ._brokenImage_fa7bu_34 {
56785
57780
  aspect-ratio: 206/150;
56786
57781
  width: 100%;
56787
57782
  display: block;
@@ -56790,9 +57785,9 @@ article ._wrapper_zhv80_1 ._list_zhv80_8 ._listItemRoot_zhv80_8 {
56790
57785
  background-color: var(--cc-black-80);
56791
57786
  }
56792
57787
 
56793
- ._slideItem_ldua9_1 ._hasExtraInfo_ldua9_43,
56794
- ._slideItem_ldua9_1 ._hasExtraInfo_ldua9_43 img,
56795
- ._slideItem_ldua9_1 ._brokenImage_ldua9_34 {
57788
+ ._slideItem_fa7bu_1 ._hasExtraInfo_fa7bu_43,
57789
+ ._slideItem_fa7bu_1 ._hasExtraInfo_fa7bu_43 img,
57790
+ ._slideItem_fa7bu_1 ._brokenImage_fa7bu_34 {
56796
57791
  border-bottom-left-radius: 0px;
56797
57792
  border-bottom-right-radius: 0px;
56798
57793
  }
@@ -56801,7 +57796,7 @@ article ._wrapper_zhv80_1 ._list_zhv80_8 ._listItemRoot_zhv80_8 {
56801
57796
  ** Default (legacy) layout: the title overlays the bottom of the image.
56802
57797
  ** Used when \`galleryCardTitleBelowImage\` is not enabled.
56803
57798
  */
56804
- ._slideItem_ldua9_1 ._top_ldua9_8 h4 {
57799
+ ._slideItem_fa7bu_1 ._top_fa7bu_8 h4 {
56805
57800
  position: absolute;
56806
57801
  margin: 0px;
56807
57802
  margin-inline-start: 8px;
@@ -56809,32 +57804,69 @@ article ._wrapper_zhv80_1 ._list_zhv80_8 ._listItemRoot_zhv80_8 {
56809
57804
  color: var(--cc-white);
56810
57805
  }
56811
57806
 
57807
+ /*
57808
+ ** A card whose image is missing or failed to load shows the grey
57809
+ ** \`.brokenImage\` placeholder instead. White text on it is 1.6:1, so the
57810
+ ** overlaid title switches to dark text there (WCAG 1.4.3 Contrast Minimum,
57811
+ ** CGY-37634).
57812
+ */
57813
+ ._slideItem_fa7bu_1 ._top_fa7bu_8:has(._brokenImage_fa7bu_34) h4 {
57814
+ color: var(--cc-black-10);
57815
+ }
57816
+
56812
57817
  /*
56813
57818
  ** Opt-in layout (galleryCardTitleBelowImage): the title moves into the content
56814
57819
  ** block beneath the image, so it shares the subtitle's flush margins/padding.
56815
57820
  */
56816
- ._slideItem_ldua9_1 ._bottom_ldua9_13 p,
56817
- ._slideItem_ldua9_1 ._bottom_ldua9_13 h4 {
57821
+ ._slideItem_fa7bu_1 ._bottom_fa7bu_13 p,
57822
+ ._slideItem_fa7bu_1 ._bottom_fa7bu_13 h4 {
56818
57823
  padding: 0px;
56819
57824
  margin: 0px;
56820
57825
  }
56821
57826
 
56822
- ._slideItem_ldua9_1 ._bottom_ldua9_13 ._buttonListItem_ldua9_72 {
57827
+ ._slideItem_fa7bu_1 ._bottom_fa7bu_13 ._buttonListItem_fa7bu_82 {
56823
57828
  width: 100%;
56824
57829
  }
56825
57830
 
57831
+ /*
57832
+ ** default_action link (CGY-37634): wraps the card text inside the content
57833
+ ** block (keeping the block's column gap), or sits on the image area when the
57834
+ ** block has no text. Buttons are never inside it.
57835
+ */
57836
+ ._slideItem_fa7bu_1 ._link_fa7bu_91 {
57837
+ display: flex;
57838
+ flex-direction: column;
57839
+ gap: 8px;
57840
+ }
57841
+ ._slideItem_fa7bu_1 [role="link"] {
57842
+ cursor: pointer;
57843
+ }
57844
+ ._slideItem_fa7bu_1 [role="link"]:focus-visible {
57845
+ outline: 2px solid var(--cc-primary-color-focus);
57846
+ outline-offset: 2px;
57847
+ }
57848
+ /* .slideItem is overflow:hidden and the image area fills it edge to edge, so
57849
+ the focus ring is drawn inside the card; an outset ring there is clipped
57850
+ away entirely (WCAG 2.4.7 Focus Visible). The text link sits inside the
57851
+ content block's 8px padding, so its outset ring is never clipped. */
57852
+ ._slideItem_fa7bu_1 ._top_fa7bu_8[role="link"]:focus-visible {
57853
+ outline-offset: -2px;
57854
+ }
57855
+
56826
57856
  /*
56827
57857
  ** SWIPER MAIN
56828
57858
  ** The following styles are a porting from the original swiper/css and related modules.
56829
57859
  ** The idea is to integrate with modules CSS in order to increase the specificity
56830
57860
  ** and avoid conflicts on consumer apps
56831
57861
  */
56832
- article .swiper._wrapper_ldua9_82 {
57862
+ article .swiper._wrapper_fa7bu_117 {
56833
57863
  margin-left: -20px;
56834
57864
  margin-right: -20px;
56835
57865
  padding-left: 20px;
56836
57866
  padding-right: 20px;
56837
- padding-bottom: 22px;
57867
+ /* The pagination row is in normal flow below the slides (see
57868
+ .swiper-pagination); 2px clearance under it, matching the gap above it. */
57869
+ padding-bottom: 2px;
56838
57870
  padding-top: 0px;
56839
57871
  position: relative;
56840
57872
  overflow: hidden;
@@ -56843,7 +57875,7 @@ article .swiper._wrapper_ldua9_82 {
56843
57875
  z-index: 1;
56844
57876
  display: block;
56845
57877
  }
56846
- article .swiper._wrapper_ldua9_82 .swiper-wrapper {
57878
+ article .swiper._wrapper_fa7bu_117 .swiper-wrapper {
56847
57879
  position: relative;
56848
57880
  width: 100%;
56849
57881
  /* height: 100%; */
@@ -56853,15 +57885,15 @@ article .swiper._wrapper_ldua9_82 .swiper-wrapper {
56853
57885
  transition-timing-function: initial;
56854
57886
  box-sizing: content-box;
56855
57887
  }
56856
- article .swiper._wrapper_ldua9_82 .swiper-android .swiper-slide,
56857
- article .swiper._wrapper_ldua9_82 .swiper-ios .swiper-slide,
56858
- article .swiper._wrapper_ldua9_82 .swiper-wrapper {
57888
+ article .swiper._wrapper_fa7bu_117 .swiper-android .swiper-slide,
57889
+ article .swiper._wrapper_fa7bu_117 .swiper-ios .swiper-slide,
57890
+ article .swiper._wrapper_fa7bu_117 .swiper-wrapper {
56859
57891
  transform: translate3d(0px, 0, 0);
56860
57892
  }
56861
- article .swiper._wrapper_ldua9_82 .swiper-horizontal {
57893
+ article .swiper._wrapper_fa7bu_117 .swiper-horizontal {
56862
57894
  touch-action: pan-y;
56863
57895
  }
56864
- article .swiper._wrapper_ldua9_82 .swiper-slide {
57896
+ article .swiper._wrapper_fa7bu_117 .swiper-slide {
56865
57897
  flex-shrink: 0;
56866
57898
  width: 100%;
56867
57899
  height: 100%;
@@ -56869,15 +57901,15 @@ article .swiper._wrapper_ldua9_82 .swiper-slide {
56869
57901
  transition-property: transform;
56870
57902
  display: block;
56871
57903
  }
56872
- article .swiper._wrapper_ldua9_82 .swiper-slide-invisible-blank {
57904
+ article .swiper._wrapper_fa7bu_117 .swiper-slide-invisible-blank {
56873
57905
  visibility: hidden;
56874
57906
  }
56875
57907
 
56876
57908
  /*
56877
57909
  ** SWIPER PAGINATION
56878
57910
  */
56879
- article .swiper._wrapper_ldua9_82 .gallery-button-prev,
56880
- article .swiper._wrapper_ldua9_82 .gallery-button-next {
57911
+ article .swiper._wrapper_fa7bu_117 .gallery-button-prev,
57912
+ article .swiper._wrapper_fa7bu_117 .gallery-button-next {
56881
57913
  position: absolute;
56882
57914
  top: calc(150px / 2 - 8px);
56883
57915
  z-index: 10;
@@ -56890,68 +57922,104 @@ article .swiper._wrapper_ldua9_82 .gallery-button-next {
56890
57922
  display: flex;
56891
57923
  align-items: center;
56892
57924
  }
56893
- article .swiper._wrapper_ldua9_82 .gallery-button-prev {
57925
+ article .swiper._wrapper_fa7bu_117 .gallery-button-prev {
56894
57926
  left: 20px;
56895
57927
  }
56896
- article .swiper._wrapper_ldua9_82 .gallery-button-next {
57928
+ article .swiper._wrapper_fa7bu_117 .gallery-button-next {
56897
57929
  right: 20px;
56898
57930
  transform: rotate(180deg);
56899
57931
  }
56900
- article .swiper._wrapper_ldua9_82 .gallery-button-prev:dir(rtl) {
57932
+ article .swiper._wrapper_fa7bu_117 .gallery-button-prev:dir(rtl) {
56901
57933
  left: unset;
56902
57934
  right: 20px;
56903
57935
  transform: rotate(180deg);
56904
57936
  }
56905
- article .swiper._wrapper_ldua9_82 .gallery-button-next:dir(rtl) {
57937
+ article .swiper._wrapper_fa7bu_117 .gallery-button-next:dir(rtl) {
56906
57938
  right: unset;
56907
57939
  left: 20px;
56908
57940
  transform: rotate(0deg);
56909
57941
  }
56910
- article .swiper._wrapper_ldua9_82 .swiper-button-disabled {
57942
+ article .swiper._wrapper_fa7bu_117 .swiper-button-disabled {
56911
57943
  opacity: 0;
56912
57944
  }
56913
57945
 
56914
57946
  /*
56915
57947
  ** SWIPER NAVIGATION
56916
57948
  */
56917
- article .swiper._wrapper_ldua9_82 .swiper-pagination {
56918
- position: absolute;
57949
+ /*
57950
+ ** The pagination row is in normal flow beneath the slides. Bullets are fixed
57951
+ ** 24px targets (WCAG 2.5.8) and wrap onto further rows when more than fit in
57952
+ ** one; in flow, extra rows grow the gallery downwards rather than overlapping
57953
+ ** the cards. A single row adds 28px: 2px gap + 24px row + 2px container
57954
+ ** padding.
57955
+ */
57956
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination {
57957
+ position: relative;
56919
57958
  text-align: center;
56920
57959
  transition: 300ms opacity;
56921
57960
  transform: translate3d(0, 0, 0);
56922
57961
  z-index: 10;
56923
57962
  }
56924
- article .swiper._wrapper_ldua9_82 .swiper-pagination.swiper-pagination-hidden {
57963
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination.swiper-pagination-hidden {
56925
57964
  opacity: 0;
56926
57965
  }
56927
- article .swiper._wrapper_ldua9_82 .swiper-pagination-disabled > .swiper-pagination,
56928
- article .swiper._wrapper_ldua9_82 .swiper-pagination.swiper-pagination-disabled {
57966
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-disabled > .swiper-pagination,
57967
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination.swiper-pagination-disabled {
56929
57968
  display: none !important;
56930
57969
  }
56931
- article .swiper._wrapper_ldua9_82 .swiper-horizontal > .swiper-pagination-bullets,
56932
- article .swiper._wrapper_ldua9_82 .swiper-pagination-bullets.swiper-pagination-horizontal {
56933
- bottom: 4px;
56934
- left: 0;
57970
+ article .swiper._wrapper_fa7bu_117 .swiper-horizontal > .swiper-pagination-bullets,
57971
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-bullets.swiper-pagination-horizontal {
57972
+ margin-top: 2px;
56935
57973
  width: 100%;
57974
+ display: flex;
57975
+ flex-wrap: wrap;
57976
+ justify-content: center;
57977
+ align-items: center;
57978
+ }
57979
+ /*
57980
+ ** Each bullet is a 24×24px pointer/focus target (WCAG 2.5.8 Target Size
57981
+ ** Minimum, CGY-37634). The visible 6px dot is drawn by ::before, so the look
57982
+ ** is unchanged while the hit area grows around it; focus styling therefore
57983
+ ** targets ::before too.
57984
+ */
57985
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-bullet {
57986
+ /* Fixed-size flex item: the 24px target never shrinks when the row is
57987
+ full; overflowing bullets wrap (see .swiper-pagination). */
57988
+ flex: 0 0 24px;
57989
+ width: 24px;
57990
+ height: 24px;
57991
+ display: inline-flex;
57992
+ align-items: center;
57993
+ justify-content: center;
57994
+ /* No border-radius here: browsers clip pointer hit-testing to the rounded
57995
+ shape, which would shrink the target back below 24×24. */
57996
+ background: transparent;
57997
+ opacity: 1;
56936
57998
  }
56937
- article .swiper._wrapper_ldua9_82 .swiper-pagination-bullet {
57999
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-bullet::before {
58000
+ content: "";
56938
58001
  width: 6px;
56939
58002
  height: 6px;
56940
- display: inline-block;
56941
58003
  border-radius: 50%;
56942
- background: var(--cc-black-50);
56943
- opacity: 1;
58004
+ background-color: var(--cc-black-50);
56944
58005
  }
56945
- article .swiper._wrapper_ldua9_82 .swiper-pagination-bullet:focus {
58006
+ /* Declared before the focus rules (and lower in specificity) so a focused
58007
+ active bullet always shows the focus colour, not the active black. */
58008
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-bullet-active::before {
58009
+ background-color: black;
58010
+ }
58011
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-bullet:focus {
58012
+ outline: none;
58013
+ }
58014
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-bullet:focus::before {
56946
58015
  background-color: var(--cc-primary-color-focus);
56947
58016
  box-shadow: 0 0 0 4px var(--cc-primary-color-opacity-10);
56948
- outline: none;
56949
58017
  }
56950
- article .swiper._wrapper_ldua9_82 .swiper-pagination-bullet:focus-visible {
58018
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-bullet:focus-visible::before {
56951
58019
  outline: 2px solid var(--cc-primary-color-focus);
56952
58020
  outline-offset: 2px;
56953
58021
  }
56954
- article .swiper._wrapper_ldua9_82 button.swiper-pagination-bullet {
58022
+ article .swiper._wrapper_fa7bu_117 button.swiper-pagination-bullet {
56955
58023
  border: none;
56956
58024
  margin: 0;
56957
58025
  padding: 0;
@@ -56959,23 +58027,20 @@ article .swiper._wrapper_ldua9_82 button.swiper-pagination-bullet {
56959
58027
  -webkit-appearance: none;
56960
58028
  appearance: none;
56961
58029
  }
56962
- article .swiper._wrapper_ldua9_82 .swiper-pagination-clickable .swiper-pagination-bullet {
58030
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-clickable .swiper-pagination-bullet {
56963
58031
  cursor: pointer;
56964
58032
  }
56965
- article .swiper._wrapper_ldua9_82 .swiper-pagination-bullet:only-child {
58033
+ article .swiper._wrapper_fa7bu_117 .swiper-pagination-bullet:only-child {
56966
58034
  display: none !important;
56967
58035
  }
56968
- article .swiper._wrapper_ldua9_82 .swiper-pagination-bullet-active {
56969
- opacity: 1;
56970
- background-color: black;
56971
- }
56972
58036
  article
56973
- .swiper._wrapper_ldua9_82
58037
+ .swiper._wrapper_fa7bu_117
56974
58038
  .swiper-horizontal > .swiper-pagination-bullets .swiper-pagination-bullet,
56975
58039
  article
56976
- .swiper._wrapper_ldua9_82
58040
+ .swiper._wrapper_fa7bu_117
56977
58041
  .swiper-pagination-horizontal.swiper-pagination-bullets .swiper-pagination-bullet {
56978
- margin: 0 4px;
58042
+ /* Adjacent 24px targets touch but never overlap (WCAG 2.5.8). */
58043
+ margin: 0;
56979
58044
  }
56980
58045
  ._wrapper_1h4l4_1 {
56981
58046
  background-color: white;
@@ -59151,6 +60216,14 @@ const replaceUrlsWithHTMLanchorElem = text2 => {
59151
60216
  });
59152
60217
  return enhancedText;
59153
60218
  };
60219
+ const htmlToPlainText = html2 => {
60220
+ if (!html2) return "";
60221
+ if (typeof DOMParser !== "undefined") {
60222
+ const doc = new DOMParser().parseFromString(html2, "text/html");
60223
+ return (doc.body?.textContent ?? "").trim();
60224
+ }
60225
+ return html2.replace(/<[^>]*>/g, "").trim();
60226
+ };
59154
60227
  const getFocusableElements = element2 => {
59155
60228
  const interactiveEls = element2?.querySelectorAll('a[href], button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])');
59156
60229
  const interactiveElsArray = interactiveEls && Array.from(interactiveEls);
@@ -59715,7 +60788,7 @@ function createDOMPurify() {
59715
60788
  NodeFilter: NodeFilter2,
59716
60789
  NamedNodeMap = window2.NamedNodeMap || window2.MozNamedAttrMap,
59717
60790
  HTMLFormElement,
59718
- DOMParser,
60791
+ DOMParser: DOMParser2,
59719
60792
  trustedTypes: trustedTypes2
59720
60793
  } = window2;
59721
60794
  const ElementPrototype = Element2.prototype;
@@ -60077,7 +61150,7 @@ function createDOMPurify() {
60077
61150
  const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
60078
61151
  if (NAMESPACE === HTML_NAMESPACE) {
60079
61152
  try {
60080
- doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
61153
+ doc = new DOMParser2().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
60081
61154
  } catch (_) {}
60082
61155
  }
60083
61156
  if (!doc || !doc.documentElement) {
@@ -68806,7 +69879,7 @@ function linkReference$1(state, node2) {
68806
69879
  state.patch(node2, result);
68807
69880
  return state.applyData(node2, result);
68808
69881
  }
68809
- function link$1(state, node2) {
69882
+ function link$2(state, node2) {
68810
69883
  const properties = {
68811
69884
  href: normalizeUri(node2.url)
68812
69885
  };
@@ -69109,7 +70182,7 @@ const handlers = {
69109
70182
  image: image$1,
69110
70183
  inlineCode: inlineCode$1,
69111
70184
  linkReference: linkReference$1,
69112
- link: link$1,
70185
+ link: link$2,
69113
70186
  listItem: listItem$1,
69114
70187
  list: list$3,
69115
70188
  paragraph: paragraph$2,
@@ -82630,8 +83703,8 @@ function formatLinkAsAutolink(node2, state) {
82630
83703
  // references don’t work), space, or angle brackets…
82631
83704
  !/[\0- <>\u007F]/.test(node2.url));
82632
83705
  }
82633
- link.peek = linkPeek;
82634
- function link(node2, _, state, info) {
83706
+ link$1.peek = linkPeek;
83707
+ function link$1(node2, _, state, info) {
82635
83708
  const quote = checkQuote(state);
82636
83709
  const suffix = quote === '"' ? "Quote" : "Apostrophe";
82637
83710
  const tracker = state.createTracker(info);
@@ -82937,7 +84010,7 @@ const handle = {
82937
84010
  image,
82938
84011
  imageReference,
82939
84012
  inlineCode,
82940
- link,
84013
+ link: link$1,
82941
84014
  linkReference,
82942
84015
  list: list$2,
82943
84016
  listItem,
@@ -84804,25 +85877,15 @@ const LightboxHeader = () => {
84804
85877
  const {
84805
85878
  config: config2
84806
85879
  } = useMessageContext();
84807
- const firstButton = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null);
85880
+ const downloadButton2 = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null);
84808
85881
  (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
84809
85882
  setTimeout(() => {
84810
- firstButton.current?.focus();
85883
+ downloadButton2.current?.focus();
84811
85884
  }, 100);
84812
85885
  }, []);
84813
85886
  const handleDownload = () => {
84814
85887
  window.open(url, "_blank");
84815
85888
  };
84816
- const handleKeyDownload = event => {
84817
- event.key === "Enter" && handleDownload();
84818
- };
84819
- const handleKeyClose = event => {
84820
- if (event.key === "Tab" || event.shiftKey) {
84821
- firstButton.current?.focus();
84822
- event.preventDefault();
84823
- }
84824
- event.code === "Enter" && onClose && onClose();
84825
- };
84826
85889
  const downloadFullsizeImageLabel = config2?.settings.customTranslations?.ariaLabels?.downloadFullsizeImage || "Download full-size image";
84827
85890
  const closeFullsizeImageModalLabel = config2?.settings.customTranslations?.ariaLabels?.closeFullsizeImageModal || "Close full-size image viewer";
84828
85891
  return /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
@@ -84833,15 +85896,13 @@ const LightboxHeader = () => {
84833
85896
  }), /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
84834
85897
  className: classes$h.iconsGroup,
84835
85898
  children: [/* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
84836
- ref: firstButton,
85899
+ ref: downloadButton2,
84837
85900
  onClick: handleDownload,
84838
- onKeyDown: handleKeyDownload,
84839
85901
  "aria-label": downloadFullsizeImageLabel,
84840
85902
  className: classes$h.icon,
84841
85903
  children: /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(SvgDownload, {})
84842
85904
  }), /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
84843
85905
  onClick: onClose,
84844
- onKeyDown: handleKeyClose,
84845
85906
  "aria-label": closeFullsizeImageModalLabel,
84846
85907
  className: classes$h.icon,
84847
85908
  children: /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(SvgClose, {})
@@ -84858,12 +85919,34 @@ const Lightbox = () => {
84858
85919
  const {
84859
85920
  config: config2
84860
85921
  } = useMessageContext();
85922
+ const dialogRef = (0,react__WEBPACK_IMPORTED_MODULE_1__.useRef)(null);
84861
85923
  (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
84862
- const close = event => {
84863
- event.code === "Escape" && onClose && onClose();
85924
+ const handleKeyDown = event => {
85925
+ if (event.key === "Escape" || event.code === "Escape") {
85926
+ onClose && onClose();
85927
+ return;
85928
+ }
85929
+ if (event.key !== "Tab" || !dialogRef.current) return;
85930
+ const {
85931
+ firstFocusable,
85932
+ lastFocusable
85933
+ } = getFocusableElements(dialogRef.current);
85934
+ if (!firstFocusable || !lastFocusable) return;
85935
+ const active = document.activeElement;
85936
+ const focusInsideDialog = !!active && dialogRef.current.contains(active);
85937
+ if (!focusInsideDialog) {
85938
+ event.preventDefault();
85939
+ (event.shiftKey ? lastFocusable : firstFocusable).focus();
85940
+ } else if (event.shiftKey && active === firstFocusable) {
85941
+ event.preventDefault();
85942
+ lastFocusable.focus();
85943
+ } else if (!event.shiftKey && active === lastFocusable) {
85944
+ event.preventDefault();
85945
+ firstFocusable.focus();
85946
+ }
84864
85947
  };
84865
- window.addEventListener("keydown", close);
84866
- return () => window.removeEventListener("keydown", close);
85948
+ window.addEventListener("keydown", handleKeyDown);
85949
+ return () => window.removeEventListener("keydown", handleKeyDown);
84867
85950
  }, [onClose]);
84868
85951
  const handleOnClickBackdrop = event => {
84869
85952
  event.preventDefault();
@@ -84878,7 +85961,9 @@ const Lightbox = () => {
84878
85961
  };
84879
85962
  const lightboxLabel = config2?.settings.customTranslations?.ariaLabels?.fullSizeImageViewerTitle || "Full-size image viewer";
84880
85963
  return /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
85964
+ ref: dialogRef,
84881
85965
  role: "dialog",
85966
+ "aria-modal": "true",
84882
85967
  "aria-label": lightboxLabel,
84883
85968
  className: classes$h.wrapper,
84884
85969
  children: [/* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
@@ -84887,7 +85972,7 @@ const Lightbox = () => {
84887
85972
  children: /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", {
84888
85973
  className: classes$h.fullImage,
84889
85974
  "data-test": "image-lightbox",
84890
- alt: altText,
85975
+ alt: altText || "",
84891
85976
  src: url,
84892
85977
  onClick: handleOnClickImage,
84893
85978
  onTouchMove: handleOnSwipeImage
@@ -85376,9 +86461,11 @@ const ActionButtons = props2 => {
85376
86461
  }, index2) : actionButton2;
85377
86462
  });
85378
86463
  const Component = buttons2.length > 1 ? "ul" : "div";
86464
+ const singleButtonRole = Component === "div" && templateTextId ? "group" : void 0;
85379
86465
  return /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Component, {
85380
86466
  className: classnames$1(className, classes$d.buttons, containerClassName),
85381
86467
  style: containerStyle || {},
86468
+ role: singleButtonRole,
85382
86469
  "aria-labelledby": templateTextId,
85383
86470
  "data-testid": "action-buttons",
85384
86471
  children: buttonElements
@@ -92495,13 +93582,14 @@ const List = () => {
92495
93582
  })]
92496
93583
  });
92497
93584
  };
92498
- const slideItem = "_slideItem_ldua9_1";
92499
- const top = "_top_ldua9_8";
92500
- const bottom = "_bottom_ldua9_13";
92501
- const brokenImage = "_brokenImage_ldua9_34";
92502
- const hasExtraInfo = "_hasExtraInfo_ldua9_43";
92503
- const buttonListItem = "_buttonListItem_ldua9_72";
92504
- const wrapper$1 = "_wrapper_ldua9_82";
93585
+ const slideItem = "_slideItem_fa7bu_1";
93586
+ const top = "_top_fa7bu_8";
93587
+ const bottom = "_bottom_fa7bu_13";
93588
+ const brokenImage = "_brokenImage_fa7bu_34";
93589
+ const hasExtraInfo = "_hasExtraInfo_fa7bu_43";
93590
+ const buttonListItem = "_buttonListItem_fa7bu_82";
93591
+ const link = "_link_fa7bu_91";
93592
+ const wrapper$1 = "_wrapper_fa7bu_117";
92505
93593
  const classes$8 = {
92506
93594
  slideItem,
92507
93595
  top,
@@ -92509,6 +93597,7 @@ const classes$8 = {
92509
93597
  brokenImage,
92510
93598
  hasExtraInfo,
92511
93599
  buttonListItem,
93600
+ link,
92512
93601
  wrapper: wrapper$1
92513
93602
  };
92514
93603
  const getGalleryContent = (elements, isSanitizeEnabled, customAllowedHtmlTags) => {
@@ -98275,6 +99364,18 @@ const SwiperSlide = /* @__PURE__ */(0,react__WEBPACK_IMPORTED_MODULE_1__.forward
98275
99364
  })));
98276
99365
  });
98277
99366
  SwiperSlide.displayName = "SwiperSlide";
99367
+ const getHostname = url => {
99368
+ try {
99369
+ const {
99370
+ protocol,
99371
+ hostname
99372
+ } = new URL(url);
99373
+ return protocol === "http:" || protocol === "https:" ? hostname : "";
99374
+ } catch {
99375
+ return "";
99376
+ }
99377
+ };
99378
+ const NESTED_CONTROL_SELECTOR = "a[href], button, input, select, textarea, summary";
98278
99379
  const GalleryItem = props2 => {
98279
99380
  const {
98280
99381
  slide: slide2,
@@ -98295,7 +99396,6 @@ const GalleryItem = props2 => {
98295
99396
  messageParams,
98296
99397
  "data-message-id": dataMessageId
98297
99398
  } = useMessageContext();
98298
- const hasExtraInfo2 = subtitle || buttons2 && buttons2?.length > 0;
98299
99399
  const titleBelowImage = !!config2?.settings?.layout?.galleryCardTitleBelowImage;
98300
99400
  const [isImageBroken, setImageBroken] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
98301
99401
  const {
@@ -98303,22 +99403,25 @@ const GalleryItem = props2 => {
98303
99403
  } = useSanitize();
98304
99404
  const titleHtml = processHTML(title || "");
98305
99405
  const subtitleHtml = processHTML(subtitle || "");
98306
- const hasTitle = !!titleHtml;
99406
+ const hasTitle = !!titleHtml.trim();
99407
+ const hasSubtitle = !!subtitleHtml.trim();
99408
+ const hasButtons = !!buttons2 && buttons2.length > 0;
99409
+ const hasExtraInfo2 = hasSubtitle || hasButtons;
98307
99410
  const showContentBlock = titleBelowImage && hasTitle || hasExtraInfo2;
98308
99411
  const titleId = useRandomId("webchatCarouselTemplateTitle");
98309
99412
  const subtitleId = useRandomId("webchatCarouselTemplateSubtitle");
98310
99413
  const shouldBeDisabled = messageParams?.isConversationEnded;
98311
99414
  const opensInNewTab = config2?.settings.customTranslations?.ariaLabels?.opensInNewTab ?? "Opens in new tab";
98312
- const handleClick = () => {
98313
- if (!default_action?.url) return;
98314
- const url = config2?.settings?.layout?.disableUrlButtonSanitization ? default_action.url : distExports.sanitizeUrl(default_action.url);
98315
- if (url === "about:blank") return;
98316
- window.open(url);
98317
- return;
99415
+ const linkUrl = default_action?.url ? config2?.settings?.layout?.disableUrlButtonSanitization ? default_action.url : distExports.sanitizeUrl(default_action.url) : "";
99416
+ const handleClick = event => {
99417
+ const target = event.target;
99418
+ if (target !== event.currentTarget && target.closest(NESTED_CONTROL_SELECTOR)) return;
99419
+ if (!linkUrl || linkUrl === "about:blank") return;
99420
+ window.open(linkUrl);
98318
99421
  };
98319
99422
  const handleKeyDown = event => {
98320
99423
  if (default_action && event.key === "Enter") {
98321
- handleClick();
99424
+ handleClick(event);
98322
99425
  }
98323
99426
  };
98324
99427
  const titleElement = /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Typography, {
@@ -98330,35 +99433,54 @@ const GalleryItem = props2 => {
98330
99433
  className: "webchat-carousel-template-title",
98331
99434
  id: titleId
98332
99435
  });
99436
+ const subtitleElement = hasSubtitle && /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Typography, {
99437
+ variant: "body-regular",
99438
+ dangerouslySetInnerHTML: {
99439
+ __html: subtitleHtml
99440
+ },
99441
+ id: subtitleId,
99442
+ className: "webchat-carousel-template-subtitle"
99443
+ });
99444
+ const hasBlockText = hasSubtitle || titleBelowImage && hasTitle;
99445
+ const linkTarget = linkUrl && linkUrl !== "about:blank" ? hasBlockText ? "text" : "top" : null;
99446
+ const titleText = linkTarget ? htmlToPlainText(titleHtml) : "";
99447
+ const subtitleText = linkTarget ? htmlToPlainText(subtitleHtml) : "";
99448
+ const linkName = titleText || subtitleText || image_alt_text || getHostname(linkUrl);
99449
+ const linkLabel = [linkName, opensInNewTab].filter(Boolean).join(". ");
99450
+ const linkDescribedBy = hasSubtitle && linkName !== subtitleText ? subtitleId : void 0;
99451
+ const cardLink = (className, children) => /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
99452
+ className,
99453
+ role: "link",
99454
+ tabIndex: 0,
99455
+ onClick: handleClick,
99456
+ onKeyDown: handleKeyDown,
99457
+ "aria-label": linkLabel,
99458
+ "aria-describedby": linkDescribedBy,
99459
+ children
99460
+ });
99461
+ const topClassName = classnames$1(classes$8.top, showContentBlock && classes$8.hasExtraInfo);
99462
+ const imageArea = /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
99463
+ children: [!titleBelowImage && hasTitle && titleElement, isImageBroken ? /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
99464
+ className: classes$8.brokenImage
99465
+ }) : /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", {
99466
+ src: image_url,
99467
+ alt: image_alt_text || "",
99468
+ className: classes$8.slideImage,
99469
+ onError: () => setImageBroken(true)
99470
+ })]
99471
+ });
99472
+ const blockText = /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
99473
+ children: [titleBelowImage && hasTitle && titleElement, subtitleElement]
99474
+ });
98333
99475
  return /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
98334
99476
  className: classnames$1("webchat-carousel-template-frame", classes$8.slideItem),
98335
- children: [/* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
98336
- className: classnames$1(classes$8.top, showContentBlock && classes$8.hasExtraInfo),
98337
- children: [!titleBelowImage && hasTitle && titleElement, isImageBroken ? /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("span", {
98338
- className: classes$8.brokenImage
98339
- }) : /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("img", {
98340
- src: image_url,
98341
- alt: image_alt_text || "",
98342
- className: classes$8.slideImage,
98343
- onError: () => setImageBroken(true)
98344
- })]
99477
+ children: [linkTarget === "top" ? cardLink(topClassName, imageArea) : /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
99478
+ className: topClassName,
99479
+ children: imageArea
98345
99480
  }), showContentBlock && /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)("div", {
98346
99481
  className: classnames$1("webchat-carousel-template-content", classes$8.bottom),
98347
- onClick: handleClick,
98348
- onKeyDown: handleKeyDown,
98349
- role: default_action?.url ? "link" : void 0,
98350
99482
  id: contentId,
98351
- "aria-describedby": default_action?.url && subtitle ? subtitleId : void 0,
98352
- "aria-labelledby": default_action?.url && hasTitle ? titleId : void 0,
98353
- "aria-label": default_action?.url ? `${titleHtml}. ${opensInNewTab}` : void 0,
98354
- children: [titleBelowImage && hasTitle && titleElement, subtitle && /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(Typography, {
98355
- variant: "body-regular",
98356
- dangerouslySetInnerHTML: {
98357
- __html: subtitleHtml
98358
- },
98359
- id: subtitleId,
98360
- className: "webchat-carousel-template-subtitle"
98361
- }), buttons2 && buttons2?.length > 0 && /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ActionButtons, {
99483
+ children: [linkTarget === "text" ? cardLink(classnames$1("webchat-carousel-template-link", classes$8.link), blockText) : blockText, hasButtons && /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ActionButtons, {
98362
99484
  dataMessageId,
98363
99485
  buttonClassName: classnames$1(buttonClasses.primaryButton, buttonClasses.actionButton, "webchat-carousel-template-button"),
98364
99486
  buttonListItemClassName: classes$8.buttonListItem,
@@ -98390,22 +99512,24 @@ const Gallery = () => {
98390
99512
  const carouselContentId = useRandomId("webchatCarouselContentButton");
98391
99513
  (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
98392
99514
  const chatHistory = document.getElementById("webchatChatHistoryWrapperLiveLogPanel");
98393
- const firstCardContent = document.getElementById(`${carouselContentId}-0`);
98394
- const firstButton = firstCardContent?.getElementsByTagName("button")?.[0];
99515
+ const messageRoot = dataMessageId ? document.querySelector(`[data-message-id="${dataMessageId.replace(/["\\]/g, "\\$&")}"]`) : null;
99516
+ const firstCard = messageRoot?.querySelector(".webchat-carousel-template-frame") ?? document.getElementById(`${carouselContentId}-0`)?.closest(".webchat-carousel-template-frame");
99517
+ const firstLink = firstCard?.querySelector('[role="link"]');
99518
+ const firstButton = firstCard?.getElementsByTagName("button")?.[0];
98395
99519
  if (!config2?.settings?.widgetSettings?.enableAutoFocus) return;
98396
99520
  if (!chatHistory?.contains(document.activeElement)) return;
98397
- if (firstCardContent?.getAttribute("role") === "link") {
99521
+ if (firstLink) {
98398
99522
  setTimeout(() => {
98399
- firstCardContent?.focus();
99523
+ firstLink.focus();
98400
99524
  }, 200);
98401
99525
  } else if (firstButton) {
98402
99526
  setTimeout(() => {
98403
99527
  firstButton?.focus();
98404
99528
  }, 200);
98405
99529
  }
98406
- }, [carouselContentId, config2?.settings?.widgetSettings?.enableAutoFocus]);
99530
+ }, [carouselContentId, dataMessageId, config2?.settings?.widgetSettings?.enableAutoFocus]);
98407
99531
  (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
98408
- const galleryMessage = document.querySelector(`[data-message-id="${dataMessageId}"]`);
99532
+ const galleryMessage = dataMessageId ? document.querySelector(`[data-message-id="${dataMessageId.replace(/["\\]/g, "\\$&")}"]`) : null;
98409
99533
  const swiperWrapper = galleryMessage?.querySelector(".swiper-wrapper");
98410
99534
  if (swiperWrapper) {
98411
99535
  swiperWrapper.removeAttribute("aria-live");
@@ -98447,7 +99571,8 @@ const Gallery = () => {
98447
99571
  nextEl: ".gallery-button-next"
98448
99572
  },
98449
99573
  pagination: {
98450
- clickable: true
99574
+ clickable: true,
99575
+ el: ".gallery-pagination"
98451
99576
  },
98452
99577
  className: classnames$1("webchat-carousel-template-root", classes$8.wrapper),
98453
99578
  "data-testid": "gallery-message",
@@ -98468,6 +99593,8 @@ const Gallery = () => {
98468
99593
  }), /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("button", {
98469
99594
  className: "gallery-button-next",
98470
99595
  children: /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(SvgArrowBack, {})
99596
+ }), /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("div", {
99597
+ className: "gallery-pagination swiper-pagination"
98471
99598
  })]
98472
99599
  });
98473
99600
  };
@@ -117179,12 +118306,23 @@ function requireL10n() {
117179
118306
  }
117180
118307
  var l10nExports = requireL10n();
117181
118308
  const l10n = /* @__PURE__ */getDefaultExportFromCjs(l10nExports);
118309
+ let instanceSeq = 0;
118310
+ function visuallyHide(element2) {
118311
+ element2.style.position = "absolute";
118312
+ element2.style.width = "1px";
118313
+ element2.style.height = "1px";
118314
+ element2.style.overflow = "hidden";
118315
+ element2.style.clip = "rect(0, 0, 0, 0)";
118316
+ element2.style.whiteSpace = "nowrap";
118317
+ }
117182
118318
  function customElements(pluginConfig) {
117183
118319
  return function (fp) {
117184
118320
  const {
117185
118321
  arrowIcon: arrowIcon2,
117186
- customTranslations
118322
+ customTranslations,
118323
+ localeId
117187
118324
  } = pluginConfig;
118325
+ const instanceId = ++instanceSeq;
117188
118326
  const navKeydownHandlers = /* @__PURE__ */new WeakMap();
117189
118327
  const observers = [];
117190
118328
  const timeouts = [];
@@ -117196,12 +118334,7 @@ function customElements(pluginConfig) {
117196
118334
  liveRegion.setAttribute("aria-live", "assertive");
117197
118335
  liveRegion.setAttribute("aria-atomic", "true");
117198
118336
  liveRegion.setAttribute("role", "alert");
117199
- liveRegion.style.position = "absolute";
117200
- liveRegion.style.width = "1px";
117201
- liveRegion.style.height = "1px";
117202
- liveRegion.style.overflow = "hidden";
117203
- liveRegion.style.clip = "rect(0, 0, 0, 0)";
117204
- liveRegion.style.whiteSpace = "nowrap";
118337
+ visuallyHide(liveRegion);
117205
118338
  fp.calendarContainer.appendChild(liveRegion);
117206
118339
  }
117207
118340
  function announce(message2) {
@@ -117344,51 +118477,150 @@ function customElements(pluginConfig) {
117344
118477
  }
117345
118478
  }
117346
118479
  const GRID_COLS = 7;
118480
+ const hasWeekNumbers = () => !!fp?.config?.weekNumbers;
118481
+ const colOffset = () => hasWeekNumbers() ? 1 : 0;
118482
+ const weekHeaderId = rowIndex => `webchat-datepicker-${instanceId}-week-${rowIndex}`;
118483
+ const weekNumberLabel = () => customTranslations?.ariaLabels?.datePickerWeekNumber || "Week";
118484
+ const dayCellId = index2 => `webchat-datepicker-${instanceId}-day-${index2}`;
117347
118485
  function setDateSelectAlly() {
117348
118486
  fp?.calendarContainer?.setAttribute("tabindex", "-1");
117349
- const grid = fp?.calendarContainer?.querySelector(".flatpickr-rContainer");
118487
+ const rContainer = fp?.calendarContainer?.querySelector(".flatpickr-rContainer");
118488
+ const innerContainer = fp?.calendarContainer?.querySelector(".flatpickr-innerContainer");
118489
+ const grid = hasWeekNumbers() ? innerContainer : rContainer;
118490
+ const layoutWrapper = hasWeekNumbers() ? rContainer : innerContainer;
117350
118491
  if (grid) {
117351
118492
  grid.setAttribute("role", "grid");
117352
118493
  grid.setAttribute("aria-label", customTranslations?.ariaLabels?.datePickerGridLabel || "Calendar");
117353
118494
  grid.setAttribute("aria-description", customTranslations?.ariaLabels?.datePickerGridDescription || "Use arrow keys to navigate through dates");
117354
- grid.setAttribute("aria-colcount", String(GRID_COLS));
118495
+ grid.setAttribute("aria-colcount", String(GRID_COLS + colOffset()));
117355
118496
  grid.setAttribute("aria-rowcount", "7");
117356
118497
  }
117357
- const innerContainer = fp?.calendarContainer?.getElementsByClassName("flatpickr-innerContainer")[0];
117358
- innerContainer?.removeAttribute("tabindex");
117359
- innerContainer?.removeAttribute("role");
117360
- innerContainer?.removeAttribute("aria-activedescendant");
117361
- const weekdayContainer = fp?.calendarContainer?.querySelector(".flatpickr-weekdays");
117362
- if (weekdayContainer) {
117363
- weekdayContainer.setAttribute("role", "row");
117364
- weekdayContainer.setAttribute("aria-rowindex", "1");
117365
- }
117366
- const weekdaySpans = fp?.calendarContainer?.querySelectorAll(".flatpickr-weekday");
118498
+ layoutWrapper?.removeAttribute("tabindex");
118499
+ layoutWrapper?.removeAttribute("aria-activedescendant");
118500
+ layoutWrapper?.setAttribute("role", "presentation");
118501
+ if (hasWeekNumbers()) fp?.weekWrapper?.setAttribute("role", "presentation");
118502
+ const weekdayRow = fp?.calendarContainer?.querySelector(".flatpickr-weekdays");
118503
+ if (weekdayRow) {
118504
+ weekdayRow.setAttribute("role", "row");
118505
+ weekdayRow.setAttribute("aria-rowindex", "1");
118506
+ }
118507
+ weekdayRow?.querySelector(".flatpickr-weekdaycontainer")?.setAttribute("role", "presentation");
118508
+ const weekdaySpans = fp?.calendarContainer?.querySelectorAll(".flatpickr-weekdaycontainer .flatpickr-weekday");
117367
118509
  weekdaySpans?.forEach((span, index2) => {
117368
118510
  span.setAttribute("role", "columnheader");
117369
118511
  span.setAttribute("abbr", span.textContent?.trim() || "");
117370
- span.setAttribute("aria-colindex", String(index2 % GRID_COLS + 1));
118512
+ span.setAttribute("aria-colindex", String(index2 % GRID_COLS + 1 + colOffset()));
118513
+ });
118514
+ const visualWeekHeader = fp?.weekWrapper?.querySelector(".flatpickr-weekday");
118515
+ if (visualWeekHeader && weekdayRow) {
118516
+ visualWeekHeader.setAttribute("aria-hidden", "true");
118517
+ let weekHeader = weekdayRow.querySelector(":scope > [data-week-header]");
118518
+ if (!weekHeader) {
118519
+ weekHeader = document.createElement("span");
118520
+ weekHeader.dataset.weekHeader = "true";
118521
+ visuallyHide(weekHeader);
118522
+ weekdayRow.prepend(weekHeader);
118523
+ }
118524
+ weekHeader.id = weekHeaderId(1);
118525
+ weekHeader.setAttribute("role", "columnheader");
118526
+ weekHeader.setAttribute("abbr", visualWeekHeader.textContent?.trim() || "");
118527
+ weekHeader.setAttribute("aria-colindex", "1");
118528
+ weekHeader.textContent = weekNumberLabel();
118529
+ }
118530
+ }
118531
+ function syncWeekNumbers() {
118532
+ if (!hasWeekNumbers() || !fp?.weekNumbers) return;
118533
+ fp.weekNumbers.setAttribute("role", "presentation");
118534
+ const weekCells = Array.from(fp.weekNumbers.querySelectorAll(":scope > .flatpickr-day"));
118535
+ weekCells.forEach((cell, i) => {
118536
+ const rowIndex = i + 2;
118537
+ cell.id = weekHeaderId(rowIndex);
118538
+ cell.setAttribute("role", "rowheader");
118539
+ cell.setAttribute("aria-rowindex", String(rowIndex));
118540
+ cell.setAttribute("aria-colindex", "1");
118541
+ cell.setAttribute("aria-label", `${weekNumberLabel()} ${cell.textContent?.trim()}`);
117371
118542
  });
117372
118543
  }
117373
118544
  function applyDayGridIndices() {
117374
118545
  const dayContainer = fp?.calendarContainer?.querySelector(".dayContainer");
117375
118546
  if (!dayContainer) return;
117376
- dayContainer.setAttribute("role", "rowgroup");
118547
+ dayContainer.setAttribute("role", "presentation");
117377
118548
  const dayCells = Array.from(dayContainer.querySelectorAll(":scope > .flatpickr-day"));
117378
118549
  dayCells.forEach((cell, i) => {
117379
- cell.setAttribute("aria-rowindex", String(Math.floor(i / GRID_COLS) + 2));
117380
- cell.setAttribute("aria-colindex", String(i % GRID_COLS + 1));
117381
- });
117382
- }
117383
- function markSelectedCells() {
117384
- getDayCells().forEach(day => {
117385
- if (day.classList.contains("selected")) {
117386
- day.setAttribute("aria-selected", "true");
118550
+ cell.id = dayCellId(i);
118551
+ const rowIndex = Math.floor(i / GRID_COLS) + 2;
118552
+ cell.setAttribute("aria-rowindex", String(rowIndex));
118553
+ cell.setAttribute("aria-colindex", String(i % GRID_COLS + 1 + colOffset()));
118554
+ const weekHeader = hasWeekNumbers() ? fp?.weekNumbers?.querySelector(`[aria-rowindex="${rowIndex}"]`) : null;
118555
+ if (weekHeader?.id) {
118556
+ cell.setAttribute("aria-describedby", weekHeader.id);
117387
118557
  } else {
117388
- day.removeAttribute("aria-selected");
118558
+ cell.removeAttribute("aria-describedby");
117389
118559
  }
117390
118560
  });
117391
118561
  }
118562
+ function syncGridRows() {
118563
+ const daysContainer = fp?.calendarContainer?.querySelector(".flatpickr-days");
118564
+ const dayContainer = daysContainer?.querySelector(":scope > .dayContainer");
118565
+ if (!daysContainer || !dayContainer) return;
118566
+ daysContainer.setAttribute("role", "rowgroup");
118567
+ const dayCells = Array.from(dayContainer.querySelectorAll(":scope > .flatpickr-day"));
118568
+ const rowCount = Math.ceil(dayCells.length / GRID_COLS);
118569
+ for (let r = 0; r < rowCount; r++) {
118570
+ const rowIndex = r + 2;
118571
+ let row = daysContainer.querySelector(`:scope > [data-grid-row="${rowIndex}"]`);
118572
+ if (!row) {
118573
+ row = document.createElement("div");
118574
+ row.dataset.gridRow = String(rowIndex);
118575
+ row.setAttribute("role", "row");
118576
+ visuallyHide(row);
118577
+ daysContainer.appendChild(row);
118578
+ }
118579
+ row.setAttribute("aria-rowindex", String(rowIndex));
118580
+ const owned = dayCells.slice(r * GRID_COLS, (r + 1) * GRID_COLS).map(c => c.id);
118581
+ const weekHeader = hasWeekNumbers() ? fp?.weekNumbers?.querySelector(`[aria-rowindex="${rowIndex}"]`) : null;
118582
+ if (weekHeader?.id) owned.unshift(weekHeader.id);
118583
+ row.setAttribute("aria-owns", owned.join(" "));
118584
+ }
118585
+ }
118586
+ function isSelectedCell(cell) {
118587
+ return cell.classList.contains("selected") || cell.classList.contains("inRange") || cell.classList.contains("startRange") || cell.classList.contains("endRange");
118588
+ }
118589
+ const pendingLabelRestore = /* @__PURE__ */new Set();
118590
+ function syncDayCellState(cell) {
118591
+ if (isSelectedCell(cell)) {
118592
+ cell.setAttribute("aria-selected", "true");
118593
+ } else {
118594
+ cell.removeAttribute("aria-selected");
118595
+ }
118596
+ if (pendingLabelRestore.has(cell)) return;
118597
+ const date = cellDate(cell);
118598
+ if (date) cell.setAttribute("aria-label", getDayLabel(cell, date));
118599
+ }
118600
+ function syncAllDayCells() {
118601
+ getDayCells().forEach(syncDayCellState);
118602
+ }
118603
+ function observeDayCellClasses() {
118604
+ const daysContainer = fp?.calendarContainer?.querySelector(".flatpickr-days");
118605
+ if (!daysContainer || daysContainer.dataset.classObserved === "true") return;
118606
+ daysContainer.dataset.classObserved = "true";
118607
+ const observer = new MutationObserver(records => {
118608
+ const touched = /* @__PURE__ */new Set();
118609
+ records.forEach(record => {
118610
+ const cell = record.target;
118611
+ if (cell.classList?.contains("flatpickr-day") && cell.closest(".dayContainer")) {
118612
+ touched.add(cell);
118613
+ }
118614
+ });
118615
+ touched.forEach(syncDayCellState);
118616
+ });
118617
+ observer.observe(daysContainer, {
118618
+ attributes: true,
118619
+ attributeFilter: ["class"],
118620
+ subtree: true
118621
+ });
118622
+ observers.push(observer);
118623
+ }
117392
118624
  function restoreRovingDay() {
117393
118625
  const existing = fp?.calendarContainer?.querySelector(".dayContainer .flatpickr-day[tabindex='0']");
117394
118626
  setActiveDay(existing || getInitialActiveDay(), {
@@ -117396,8 +118628,10 @@ function customElements(pluginConfig) {
117396
118628
  });
117397
118629
  }
117398
118630
  function refreshGridAfterRebuild() {
118631
+ syncWeekNumbers();
117399
118632
  applyDayGridIndices();
117400
- markSelectedCells();
118633
+ syncGridRows();
118634
+ syncAllDayCells();
117401
118635
  restoreRovingDay();
117402
118636
  }
117403
118637
  function observeDayGrid() {
@@ -117480,6 +118714,10 @@ function customElements(pluginConfig) {
117480
118714
  yearInput.setAttribute("tabindex", "0");
117481
118715
  }
117482
118716
  }
118717
+ function setValueInputAlly() {
118718
+ const headingId = fp?.calendarContainer?.closest('[role="dialog"]')?.getAttribute("aria-labelledby");
118719
+ if (headingId) fp?.input?.setAttribute("aria-labelledby", headingId);
118720
+ }
117483
118721
  function setTimeAlly() {
117484
118722
  fp?.calendarContainer?.setAttribute("aria-labelledby", "webchatDatePickerHeaderLabel");
117485
118723
  if (fp?.config?.enableTime) {
@@ -117489,17 +118727,95 @@ function customElements(pluginConfig) {
117489
118727
  minutesField?.setAttribute("tabIndex", "0");
117490
118728
  const amPmField = fp?.timeContainer?.getElementsByClassName("flatpickr-am-pm")?.[0];
117491
118729
  amPmField?.setAttribute("tabIndex", "0");
117492
- amPmField?.setAttribute("role", "button");
117493
118730
  }
117494
118731
  }
118732
+ function getAmPmValue() {
118733
+ return Array.from(fp?.amPM?.childNodes || []).filter(node2 => node2.nodeType === Node.TEXT_NODE).map(node2 => node2.textContent || "").join("").trim();
118734
+ }
118735
+ function setAmPmAlly() {
118736
+ const amPm = fp?.amPM;
118737
+ if (!amPm || amPm.dataset.a11yBound === "true") return;
118738
+ amPm.dataset.a11yBound = "true";
118739
+ const [am, pm] = fp.l10n.amPM;
118740
+ amPm.setAttribute("role", "spinbutton");
118741
+ amPm.setAttribute("aria-label", customTranslations?.ariaLabels?.datePickerAmPm || "AM/PM");
118742
+ amPm.removeAttribute("title");
118743
+ amPm.setAttribute("aria-valuemin", "0");
118744
+ amPm.setAttribute("aria-valuemax", "1");
118745
+ const syncValue = () => {
118746
+ const value = getAmPmValue();
118747
+ if (!value) return;
118748
+ amPm.setAttribute("aria-valuenow", value === am ? "1" : "0");
118749
+ amPm.setAttribute("aria-valuetext", value);
118750
+ };
118751
+ syncValue();
118752
+ const toggle = () => {
118753
+ amPm.click();
118754
+ syncValue();
118755
+ };
118756
+ const setTo = target => {
118757
+ if (getAmPmValue() !== target) toggle();
118758
+ };
118759
+ amPm.addEventListener("keydown", event => {
118760
+ const actions = {
118761
+ ArrowUp: () => setTo(am),
118762
+ ArrowDown: () => setTo(pm),
118763
+ // APG spinbutton: Home = minimum (aria-valuenow 0 = PM), End = maximum (1 = AM).
118764
+ Home: () => setTo(pm),
118765
+ End: () => setTo(am),
118766
+ Enter: toggle,
118767
+ " ": toggle,
118768
+ Spacebar: toggle
118769
+ };
118770
+ const action = actions[event.key];
118771
+ if (!action) return;
118772
+ event.preventDefault();
118773
+ event.stopPropagation();
118774
+ action();
118775
+ });
118776
+ const observer = new MutationObserver(syncValue);
118777
+ observer.observe(amPm, {
118778
+ childList: true,
118779
+ characterData: true,
118780
+ subtree: true
118781
+ });
118782
+ observers.push(observer);
118783
+ }
117495
118784
  function getInMonthCells() {
117496
118785
  return getDayCells().filter(c => !c.classList.contains("prevMonthDay") && !c.classList.contains("nextMonthDay"));
117497
118786
  }
117498
118787
  function cellDate(cell) {
117499
118788
  return cell.dateObj;
117500
118789
  }
117501
- function getDayLabel(date) {
117502
- return `${fp.l10n.months.longhand[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
118790
+ const dateFormatter = (() => {
118791
+ if (!localeId) return null;
118792
+ try {
118793
+ return new Intl.DateTimeFormat(localeId.replace("_", "-"), {
118794
+ weekday: "long",
118795
+ year: "numeric",
118796
+ month: "long",
118797
+ day: "numeric"
118798
+ });
118799
+ } catch {
118800
+ return null;
118801
+ }
118802
+ })();
118803
+ function formatSpokenDate(date) {
118804
+ if (dateFormatter) return dateFormatter.format(date);
118805
+ const weekday = fp.l10n.weekdays.longhand[date.getDay()];
118806
+ const month = fp.l10n.months.longhand[date.getMonth()];
118807
+ return `${weekday}, ${month} ${date.getDate()}, ${date.getFullYear()}`;
118808
+ }
118809
+ function getDayLabel(cell, date) {
118810
+ const labels = customTranslations?.ariaLabels;
118811
+ const parts = [formatSpokenDate(date)];
118812
+ if (cell.classList.contains("startRange")) {
118813
+ parts.push(labels?.datePickerRangeStart || "start of range");
118814
+ }
118815
+ if (cell.classList.contains("endRange")) {
118816
+ parts.push(labels?.datePickerRangeEnd || "end of range");
118817
+ }
118818
+ return parts.join(", ");
117503
118819
  }
117504
118820
  function sameYMD(a, b) {
117505
118821
  return !!a && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
@@ -117652,11 +118968,12 @@ function customElements(pluginConfig) {
117652
118968
  day.setAttribute("tabindex", day === target ? "0" : "-1");
117653
118969
  });
117654
118970
  }
117655
- const dateLabel = target.getAttribute("aria-label");
117656
- if (dateLabel) {
118971
+ if (target.getAttribute("aria-label") && !pendingLabelRestore.has(target)) {
118972
+ pendingLabelRestore.add(target);
117657
118973
  target.setAttribute("aria-label", "");
117658
118974
  setTimeout(() => {
117659
- if (target.isConnected) target.setAttribute("aria-label", dateLabel);
118975
+ pendingLabelRestore.delete(target);
118976
+ if (target.isConnected) syncDayCellState(target);
117660
118977
  }, 0);
117661
118978
  }
117662
118979
  });
@@ -117670,7 +118987,7 @@ function customElements(pluginConfig) {
117670
118987
  liveRegion = null;
117671
118988
  }
117672
118989
  return {
117673
- onReady: [upsertTimeArrows, buildTimeArrows, setDateSelectAlly, setTimeAlly, setMonthSelectAlly, setYearSelectAlly, setNavButtonsAlly, observeNavButtons, observeMonthSelector, createLiveRegion, setGridKeyNavigation, syncRovingTabindex,
118990
+ onReady: [upsertTimeArrows, buildTimeArrows, setDateSelectAlly, setValueInputAlly, setTimeAlly, setMonthSelectAlly, setYearSelectAlly, setNavButtonsAlly, observeNavButtons, observeMonthSelector, createLiveRegion, setAmPmAlly, setGridKeyNavigation, syncRovingTabindex, observeDayCellClasses,
117674
118991
  // Apply grid row roles + the initial roving-focus day, and keep them correct
117675
118992
  // across every flatpickr rebuild. Does not steal focus — the dialog focuses its
117676
118993
  // heading on open; the first Tab into the grid lands on the focusable day.
@@ -117688,13 +119005,7 @@ function customElements(pluginConfig) {
117688
119005
  dayElem.innerHTML = `<span class='dayInner'>${dayElem.innerHTML}</span>`;
117689
119006
  dayElem.setAttribute("role", "gridcell");
117690
119007
  dayElem.setAttribute("tabindex", "-1");
117691
- if (dayElem.classList.contains("selected")) {
117692
- dayElem.setAttribute("aria-selected", "true");
117693
- } else {
117694
- dayElem.removeAttribute("aria-selected");
117695
- }
117696
- const date = cellDate(dayElem);
117697
- if (date) dayElem.setAttribute("aria-label", getDayLabel(date));
119008
+ syncDayCellState(dayElem);
117698
119009
  }, handleWeekNumbers],
117699
119010
  onValueUpdate: [upsertTimeArrows,
117700
119011
  // Selecting a date rebuilds the day grid synchronously (flatpickr calls buildDays()
@@ -117796,7 +119107,8 @@ const getOptionsFromMessage = (message2, customTranslations) => {
117796
119107
  formatDate: !data.dateFormat ? date => moment(date).locale(momentLocaleId).format(dateFormatLocalString) : void 0,
117797
119108
  plugins: [customElements({
117798
119109
  arrowIcon,
117799
- customTranslations: customTranslations || {}
119110
+ customTranslations: customTranslations || {},
119111
+ localeId: momentLocaleId
117800
119112
  })]
117801
119113
  };
117802
119114
  const enable_disable = Array.isArray(data?.enable_disable) && data.enable_disable.length > 0 ? data.enable_disable : null;
@@ -118091,7 +119403,7 @@ const TextWithButtons = props2 => {
118091
119403
  showUrlIcon: true,
118092
119404
  config: config2,
118093
119405
  onEmitAnalytics,
118094
- templateTextId: webchatButtonTemplateTextId,
119406
+ templateTextId: text2 ? webchatButtonTemplateTextId : void 0,
118095
119407
  openXAppOverlay
118096
119408
  })]
118097
119409
  });
@@ -133782,12 +135094,14 @@ const AdaptiveCards = () => {
133782
135094
  }
133783
135095
  case "Action.OpenUrl":
133784
135096
  {
133785
- const url = action._propertyBag?.url;
133786
- window.open(url, "_blank");
135097
+ const rawUrl = action._propertyBag?.url;
135098
+ const url = config2?.settings?.layout?.disableUrlButtonSanitization ? rawUrl : distExports.sanitizeUrl(rawUrl);
135099
+ if (!url || url === "about:blank") return;
135100
+ window.open(url, "_blank", "noopener");
133787
135101
  return;
133788
135102
  }
133789
135103
  }
133790
- }, [onSendMessage, shouldBeDisabled]);
135104
+ }, [onSendMessage, shouldBeDisabled, config2?.settings?.layout?.disableUrlButtonSanitization]);
133791
135105
  return /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(ChatBubble, {
133792
135106
  className: classnames$1(styles["adaptivecard-wrapper"], "adaptivecard-wrapper internal", shouldBeDisabled && styles.chatDisabled),
133793
135107
  children: /* @__PURE__ */(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(AdaptiveCard, {
@@ -138626,6 +139940,17 @@ function getAdapter(adapters, config) {
138626
139940
 
138627
139941
 
138628
139942
  const DEFAULT_CHUNK_SIZE = 64 * 1024;
139943
+ const DEFAULT_REQUEST_OPTIONS = {
139944
+ cache: 'default',
139945
+ redirect: 'follow',
139946
+ referrer: 'about:client',
139947
+ referrerPolicy: '',
139948
+ mode: 'cors',
139949
+ integrity: '',
139950
+ keepalive: false,
139951
+ priority: 'auto',
139952
+ window: null
139953
+ };
138629
139954
  const {
138630
139955
  isFunction
138631
139956
  } = _utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A;
@@ -138768,7 +140093,8 @@ const factory = env => {
138768
140093
  withCredentials = 'same-origin',
138769
140094
  fetchOptions,
138770
140095
  maxContentLength,
138771
- maxBodyLength
140096
+ maxBodyLength,
140097
+ maxRedirects
138772
140098
  } = (0,_helpers_resolveConfig_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)(config);
138773
140099
  const hasMaxContentLength = _utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.isNumber(maxContentLength) && maxContentLength > -1;
138774
140100
  const hasMaxBodyLength = _utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.isNumber(maxBodyLength) && maxBodyLength > -1;
@@ -138899,17 +140225,46 @@ const factory = env => {
138899
140225
 
138900
140226
  // Set User-Agent header if not already set (fetch defaults to 'node' in Node.js)
138901
140227
  headers.set('User-Agent', 'axios/' + _env_data_js__WEBPACK_IMPORTED_MODULE_10__/* .VERSION */ .x, false);
138902
- const resolvedOptions = {
138903
- ...fetchOptions,
140228
+ const safeFetchOptions = fetchOptions == null ? fetchOptions : Object.assign(Object.create(null), fetchOptions);
140229
+ if (safeFetchOptions) {
140230
+ // These options are owned by Axios and are already reflected in the
140231
+ // resolved Request passed to fetch.
140232
+ delete safeFetchOptions.body;
140233
+ delete safeFetchOptions.headers;
140234
+ delete safeFetchOptions.method;
140235
+ delete safeFetchOptions.signal;
140236
+ delete safeFetchOptions.duplex;
140237
+ delete safeFetchOptions.credentials;
140238
+ }
140239
+ const resolvedOptions = Object.assign(Object.create(null), safeFetchOptions, {
138904
140240
  signal: composedSignal,
138905
140241
  method: method.toUpperCase(),
138906
140242
  headers: (0,_helpers_sanitizeHeaderValue_js__WEBPACK_IMPORTED_MODULE_11__/* .toByteStringHeaderObject */ .$$)(headers.normalize()),
138907
140243
  body: data,
138908
140244
  duplex: 'half',
138909
140245
  credentials: isCredentialsSupported ? withCredentials : undefined
138910
- };
140246
+ });
140247
+ if (isRequestSupported) {
140248
+ _utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.forEach(DEFAULT_REQUEST_OPTIONS, (value, key) => {
140249
+ if (resolvedOptions[key] === undefined) {
140250
+ resolvedOptions[key] = value;
140251
+ }
140252
+ });
140253
+ if (resolvedOptions.signal === undefined) {
140254
+ resolvedOptions.signal = null;
140255
+ }
140256
+ if (resolvedOptions.body === undefined) {
140257
+ resolvedOptions.body = null;
140258
+ }
140259
+ }
140260
+ if (maxRedirects === 0) {
140261
+ resolvedOptions.redirect = 'manual';
140262
+ if (safeFetchOptions) {
140263
+ safeFetchOptions.redirect = 'manual';
140264
+ }
140265
+ }
138911
140266
  request = isRequestSupported && new Request(url, resolvedOptions);
138912
- let response = await (isRequestSupported ? _fetch(request, fetchOptions) : _fetch(url, resolvedOptions));
140267
+ let response = await (isRequestSupported ? _fetch(request, safeFetchOptions) : _fetch(url, resolvedOptions));
138913
140268
  const responseHeaders = _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A.from(response.headers);
138914
140269
 
138915
140270
  // Cheap pre-check: if the server honestly declares a content-length that
@@ -139070,12 +140425,14 @@ const adapter = getFetch();
139070
140425
  /* harmony import */ var _defaults_transitional_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(96458);
139071
140426
  /* harmony import */ var _core_AxiosError_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7996);
139072
140427
  /* harmony import */ var _cancel_CanceledError_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(62200);
139073
- /* harmony import */ var _helpers_parseProtocol_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(58177);
139074
- /* harmony import */ var _platform_index_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(75194);
139075
- /* harmony import */ var _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(88580);
139076
- /* harmony import */ var _helpers_progressEventReducer_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(41487);
139077
- /* harmony import */ var _helpers_resolveConfig_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(38652);
139078
- /* harmony import */ var _helpers_sanitizeHeaderValue_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(5681);
140428
+ /* harmony import */ var _helpers_normalizeURLForProtocolCheck_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(69893);
140429
+ /* harmony import */ var _helpers_parseProtocol_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(58177);
140430
+ /* harmony import */ var _platform_index_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(75194);
140431
+ /* harmony import */ var _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(88580);
140432
+ /* harmony import */ var _helpers_progressEventReducer_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(41487);
140433
+ /* harmony import */ var _helpers_resolveConfig_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(38652);
140434
+ /* harmony import */ var _helpers_sanitizeHeaderValue_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(5681);
140435
+
139079
140436
 
139080
140437
 
139081
140438
 
@@ -139090,9 +140447,9 @@ const adapter = getFetch();
139090
140447
  const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
139091
140448
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (isXHRAdapterSupported && function (config) {
139092
140449
  return new Promise(function dispatchXhrRequest(resolve, reject) {
139093
- const _config = (0,_helpers_resolveConfig_js__WEBPACK_IMPORTED_MODULE_9__/* ["default"] */ .A)(config);
140450
+ const _config = (0,_helpers_resolveConfig_js__WEBPACK_IMPORTED_MODULE_10__/* ["default"] */ .A)(config);
139094
140451
  let requestData = _config.data;
139095
- const requestHeaders = _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.from(_config.headers).normalize();
140452
+ const requestHeaders = _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_8__/* ["default"] */ .A.from(_config.headers).normalize();
139096
140453
  let {
139097
140454
  responseType,
139098
140455
  onUploadProgress,
@@ -139100,7 +140457,7 @@ const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
139100
140457
  } = _config;
139101
140458
  let onCanceled;
139102
140459
  let uploadThrottled, downloadThrottled;
139103
- let flushUpload, flushDownload;
140460
+ let flushUpload, flushDownload, flushDownloadWithEvent;
139104
140461
  function done() {
139105
140462
  flushUpload && flushUpload(); // flush events
139106
140463
  flushDownload && flushDownload(); // flush events
@@ -139113,12 +140470,52 @@ const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
139113
140470
 
139114
140471
  // Set the request timeout in MS
139115
140472
  request.timeout = _config.timeout;
139116
- function onloadend() {
140473
+ function onloadend(event) {
140474
+ if (!request) {
140475
+ return;
140476
+ }
140477
+
140478
+ // Status 0 means no response was received, which onerror and onabort normally
140479
+ // reject before this runs. Firefox 152 fires only readystatechange and loadend for
140480
+ // navigation-canceled requests (https://bugzilla.mozilla.org/show_bug.cgi?id=1505389),
140481
+ // leaving settle() to resolve them as an empty success. ECONNABORTED is the error
140482
+ // onabort raised on Firefox 151. Reads over file:, which some environments report as
140483
+ // status 0 on success, are excluded by the request URL's scheme after browser-style
140484
+ // preprocessing, by the page origin's scheme for relative URLs (which inherit it), or
140485
+ // by responseURL where implemented.
140486
+ if (request.status === 0 && ((0,_helpers_parseProtocol_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A)((0,_helpers_normalizeURLForProtocolCheck_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)(_config.url)) || (0,_helpers_parseProtocol_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A)(_platform_index_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.origin)) !== 'file' && !(request.responseURL && request.responseURL.startsWith('file:'))) {
140487
+ reject(new _core_AxiosError_js__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .A('Request aborted', _core_AxiosError_js__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .A.ECONNABORTED, config, request));
140488
+ done();
140489
+
140490
+ // Clean up request
140491
+ request = null;
140492
+ return;
140493
+ }
140494
+
140495
+ // When loadend is still dispatching, flushing with it gives progress
140496
+ // listeners a final delivery whose event has a live target. The legacy
140497
+ // ready-state fallback has no event, so replay its pending progress.
140498
+ // A throwing listener must not block settlement; rethrow asynchronously,
140499
+ // matching how listener errors surface on the throttle timer path.
140500
+ try {
140501
+ if (event) {
140502
+ flushDownloadWithEvent && flushDownloadWithEvent(event);
140503
+ } else {
140504
+ flushDownload && flushDownload();
140505
+ }
140506
+ } catch (err) {
140507
+ setTimeout(() => {
140508
+ throw err;
140509
+ });
140510
+ }
140511
+
140512
+ // A final progress callback can cancel the request synchronously.
139117
140513
  if (!request) {
139118
140514
  return;
139119
140515
  }
140516
+
139120
140517
  // Prepare the response
139121
- const responseHeaders = _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.from('getAllResponseHeaders' in request && request.getAllResponseHeaders());
140518
+ const responseHeaders = _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_8__/* ["default"] */ .A.from('getAllResponseHeaders' in request && request.getAllResponseHeaders());
139122
140519
  const responseData = !responseType || responseType === 'text' || responseType === 'json' ? request.responseText : request.response;
139123
140520
  const response = {
139124
140521
  data: responseData,
@@ -139207,7 +140604,7 @@ const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
139207
140604
 
139208
140605
  // Add headers to the request
139209
140606
  if ('setRequestHeader' in request) {
139210
- _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach((0,_helpers_sanitizeHeaderValue_js__WEBPACK_IMPORTED_MODULE_10__/* .toByteStringHeaderObject */ .$$)(requestHeaders), function setRequestHeader(val, key) {
140607
+ _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach((0,_helpers_sanitizeHeaderValue_js__WEBPACK_IMPORTED_MODULE_11__/* .toByteStringHeaderObject */ .$$)(requestHeaders), function setRequestHeader(val, key) {
139211
140608
  request.setRequestHeader(key, val);
139212
140609
  });
139213
140610
  }
@@ -139224,13 +140621,13 @@ const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
139224
140621
 
139225
140622
  // Handle progress if needed
139226
140623
  if (onDownloadProgress) {
139227
- [downloadThrottled, flushDownload] = (0,_helpers_progressEventReducer_js__WEBPACK_IMPORTED_MODULE_8__/* .progressEventReducer */ .C1)(onDownloadProgress, true);
140624
+ [downloadThrottled, flushDownload, flushDownloadWithEvent] = (0,_helpers_progressEventReducer_js__WEBPACK_IMPORTED_MODULE_9__/* .progressEventReducer */ .C1)(onDownloadProgress, true);
139228
140625
  request.addEventListener('progress', downloadThrottled);
139229
140626
  }
139230
140627
 
139231
140628
  // Not all browsers support upload events
139232
140629
  if (onUploadProgress && request.upload) {
139233
- [uploadThrottled, flushUpload] = (0,_helpers_progressEventReducer_js__WEBPACK_IMPORTED_MODULE_8__/* .progressEventReducer */ .C1)(onUploadProgress);
140630
+ [uploadThrottled, flushUpload] = (0,_helpers_progressEventReducer_js__WEBPACK_IMPORTED_MODULE_9__/* .progressEventReducer */ .C1)(onUploadProgress);
139234
140631
  request.upload.addEventListener('progress', uploadThrottled);
139235
140632
  request.upload.addEventListener('loadend', flushUpload);
139236
140633
  }
@@ -139251,8 +140648,8 @@ const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
139251
140648
  _config.signal.aborted ? onCanceled() : _config.signal.addEventListener('abort', onCanceled);
139252
140649
  }
139253
140650
  }
139254
- const protocol = (0,_helpers_parseProtocol_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)(_config.url);
139255
- if (protocol && !_platform_index_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A.protocols.includes(protocol)) {
140651
+ const protocol = (0,_helpers_parseProtocol_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A)(_config.url);
140652
+ if (protocol && !_platform_index_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.protocols.includes(protocol)) {
139256
140653
  reject(new _core_AxiosError_js__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .A('Unsupported protocol ' + protocol + ':', _core_AxiosError_js__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .A.ERR_BAD_REQUEST, config));
139257
140654
  done();
139258
140655
  return;
@@ -139562,9 +140959,10 @@ function isCancel(value) {
139562
140959
  /* harmony import */ var _dispatchRequest_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11669);
139563
140960
  /* harmony import */ var _mergeConfig_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6068);
139564
140961
  /* harmony import */ var _buildFullPath_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1216);
139565
- /* harmony import */ var _helpers_validator_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(83092);
139566
- /* harmony import */ var _AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(88580);
139567
- /* harmony import */ var _defaults_transitional_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(96458);
140962
+ /* harmony import */ var _methodList_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(31109);
140963
+ /* harmony import */ var _helpers_validator_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(83092);
140964
+ /* harmony import */ var _AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(88580);
140965
+ /* harmony import */ var _defaults_transitional_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(96458);
139568
140966
 
139569
140967
 
139570
140968
 
@@ -139576,7 +140974,8 @@ function isCancel(value) {
139576
140974
 
139577
140975
 
139578
140976
 
139579
- const validators = _helpers_validator_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A.validators;
140977
+
140978
+ const validators = _helpers_validator_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.validators;
139580
140979
 
139581
140980
  /**
139582
140981
  * Create a new instance of Axios
@@ -139607,18 +141006,17 @@ class Axios {
139607
141006
  return await this._request(configOrUrl, config);
139608
141007
  } catch (err) {
139609
141008
  if (err instanceof Error) {
139610
- let dummy = {};
139611
- Error.captureStackTrace ? Error.captureStackTrace(dummy) : dummy = new Error();
141009
+ try {
141010
+ let dummy = {};
141011
+ Error.captureStackTrace ? Error.captureStackTrace(dummy) : dummy = new Error();
141012
+ const dummyStack = dummy.stack;
141013
+ let stack = '';
139612
141014
 
139613
- // slice off the Error: ... line
139614
- const stack = (() => {
139615
- if (!dummy.stack) {
139616
- return '';
141015
+ // slice off the Error: ... line
141016
+ if (typeof dummyStack === 'string') {
141017
+ const firstNewlineIndex = dummyStack.indexOf('\n');
141018
+ stack = firstNewlineIndex === -1 ? '' : dummyStack.slice(firstNewlineIndex + 1);
139617
141019
  }
139618
- const firstNewlineIndex = dummy.stack.indexOf('\n');
139619
- return firstNewlineIndex === -1 ? '' : dummy.stack.slice(firstNewlineIndex + 1);
139620
- })();
139621
- try {
139622
141020
  if (!err.stack) {
139623
141021
  err.stack = stack;
139624
141022
  // match without the 2 top stack lines
@@ -139631,7 +141029,7 @@ class Axios {
139631
141029
  }
139632
141030
  }
139633
141031
  } catch (e) {
139634
- // ignore the case where "stack" is an un-writable property
141032
+ // Ignore failures from custom stack hooks or un-writable stack properties.
139635
141033
  }
139636
141034
  }
139637
141035
  throw err;
@@ -139653,7 +141051,7 @@ class Axios {
139653
141051
  headers
139654
141052
  } = config;
139655
141053
  if (transitional !== undefined) {
139656
- _helpers_validator_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A.assertOptions(transitional, {
141054
+ _helpers_validator_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.assertOptions(transitional, {
139657
141055
  silentJSONParsing: validators.transitional(validators.boolean),
139658
141056
  forcedJSONParsing: validators.transitional(validators.boolean),
139659
141057
  clarifyTimeoutError: validators.transitional(validators.boolean),
@@ -139668,7 +141066,7 @@ class Axios {
139668
141066
  serialize: paramsSerializer
139669
141067
  };
139670
141068
  } else {
139671
- _helpers_validator_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A.assertOptions(paramsSerializer, {
141069
+ _helpers_validator_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.assertOptions(paramsSerializer, {
139672
141070
  encode: validators.function,
139673
141071
  serialize: validators.function
139674
141072
  }, true);
@@ -139683,20 +141081,20 @@ class Axios {
139683
141081
  } else {
139684
141082
  config.allowAbsoluteUrls = true;
139685
141083
  }
139686
- _helpers_validator_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A.assertOptions(config, {
141084
+ _helpers_validator_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.assertOptions(config, {
139687
141085
  baseUrl: validators.spelling('baseURL'),
139688
141086
  withXsrfToken: validators.spelling('withXSRFToken')
139689
141087
  }, true);
139690
141088
 
139691
141089
  // Set config.method
139692
- config.method = (config.method || this.defaults.method || 'get').toLowerCase();
141090
+ config.method = (_utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.getSafeProp(config, 'method') || _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.getSafeProp(this.defaults, 'method') || 'get').toLowerCase();
139693
141091
 
139694
141092
  // Flatten headers
139695
141093
  let contextHeaders = headers && _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.merge(headers.common, headers[config.method]);
139696
- headers && _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'query', 'common'], method => {
141094
+ headers && _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach(_methodList_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A.concat('common'), method => {
139697
141095
  delete headers[method];
139698
141096
  });
139699
- config.headers = _AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A.concat(contextHeaders, headers);
141097
+ config.headers = _AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_8__/* ["default"] */ .A.concat(contextHeaders, headers);
139700
141098
 
139701
141099
  // filter out skipped interceptors
139702
141100
  const requestInterceptorChain = [];
@@ -139706,7 +141104,7 @@ class Axios {
139706
141104
  return;
139707
141105
  }
139708
141106
  synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
139709
- const transitional = config.transitional || _defaults_transitional_js__WEBPACK_IMPORTED_MODULE_8__/* ["default"] */ .A;
141107
+ const transitional = config.transitional || _defaults_transitional_js__WEBPACK_IMPORTED_MODULE_9__/* ["default"] */ .A;
139710
141108
  const legacyInterceptorReqResOrdering = transitional && transitional.legacyInterceptorReqResOrdering;
139711
141109
  if (legacyInterceptorReqResOrdering) {
139712
141110
  requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
@@ -140371,9 +141769,51 @@ _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.freezeMethods(AxiosHe
140371
141769
 
140372
141770
 
140373
141771
 
141772
+ const $internals = Symbol('internals');
141773
+
141774
+ // `handlers` is public and may be replaced with a nullish value by user code;
141775
+ // `clear()` has always tolerated that. Treat it as an empty stack rather than
141776
+ // dereferencing it.
141777
+ function countHandlers(handlers) {
141778
+ return handlers ? handlers.length : 0;
141779
+ }
141780
+ function trimHandlers(handlers) {
141781
+ if (!handlers) {
141782
+ return;
141783
+ }
141784
+ while (handlers.length && handlers[handlers.length - 1] === null) {
141785
+ handlers.pop();
141786
+ }
141787
+ }
141788
+ function syncHandlerEntries(manager, internals) {
141789
+ const handlers = manager.handlers;
141790
+ const length = countHandlers(handlers);
141791
+ if (handlers !== internals.handlersRef) {
141792
+ internals.handlersRef = handlers;
141793
+ internals.handlerEntries.clear();
141794
+ } else if (length !== internals.handlersLength) {
141795
+ if (!length) {
141796
+ internals.handlerEntries.clear();
141797
+ } else {
141798
+ internals.handlerEntries.forEach(function removeStaleEntry(entry, id) {
141799
+ if (handlers[entry.index] !== entry.handler) {
141800
+ internals.handlerEntries.delete(id);
141801
+ }
141802
+ });
141803
+ }
141804
+ }
141805
+ internals.handlersLength = length;
141806
+ }
140374
141807
  class InterceptorManager {
140375
141808
  constructor() {
140376
141809
  this.handlers = [];
141810
+ this[$internals] = {
141811
+ handlersRef: this.handlers,
141812
+ handlersLength: this.handlers.length,
141813
+ handlerEntries: new Map(),
141814
+ iterationDepth: 0,
141815
+ nextId: 0
141816
+ };
140377
141817
  }
140378
141818
 
140379
141819
  /**
@@ -140386,13 +141826,25 @@ class InterceptorManager {
140386
141826
  * @return {Number} An ID used to remove interceptor later
140387
141827
  */
140388
141828
  use(fulfilled, rejected, options) {
140389
- this.handlers.push({
141829
+ const handler = {
140390
141830
  fulfilled,
140391
141831
  rejected,
140392
141832
  synchronous: options ? options.synchronous : false,
140393
141833
  runWhen: options ? options.runWhen : null
141834
+ };
141835
+ const internals = this[$internals];
141836
+ if (this.handlers == null) {
141837
+ this.handlers = [];
141838
+ }
141839
+ syncHandlerEntries(this, internals);
141840
+ const id = internals.nextId++;
141841
+ this.handlers.push(handler);
141842
+ internals.handlerEntries.set(id, {
141843
+ handler,
141844
+ index: this.handlers.length - 1
140394
141845
  });
140395
- return this.handlers.length - 1;
141846
+ internals.handlersLength = this.handlers.length;
141847
+ return id;
140396
141848
  }
140397
141849
 
140398
141850
  /**
@@ -140403,8 +141855,23 @@ class InterceptorManager {
140403
141855
  * @returns {void}
140404
141856
  */
140405
141857
  eject(id) {
140406
- if (this.handlers[id]) {
140407
- this.handlers[id] = null;
141858
+ const internals = this[$internals];
141859
+ syncHandlerEntries(this, internals);
141860
+ const entry = internals.handlerEntries.get(id);
141861
+ if (entry) {
141862
+ internals.handlerEntries.delete(id);
141863
+
141864
+ // Ignore IDs invalidated by clear or direct replacement of handlers.
141865
+ if (this.handlers[entry.index] !== entry.handler) {
141866
+ return;
141867
+ }
141868
+ this.handlers[entry.index] = null;
141869
+
141870
+ // Do not reuse an index while forEach is walking its length snapshot.
141871
+ if (!internals.iterationDepth) {
141872
+ trimHandlers(this.handlers);
141873
+ internals.handlersLength = this.handlers.length;
141874
+ }
140408
141875
  }
140409
141876
  }
140410
141877
 
@@ -140416,6 +141883,7 @@ class InterceptorManager {
140416
141883
  clear() {
140417
141884
  if (this.handlers) {
140418
141885
  this.handlers = [];
141886
+ syncHandlerEntries(this, this[$internals]);
140419
141887
  }
140420
141888
  }
140421
141889
 
@@ -140430,11 +141898,22 @@ class InterceptorManager {
140430
141898
  * @returns {void}
140431
141899
  */
140432
141900
  forEach(fn) {
140433
- _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach(this.handlers, function forEachHandler(h) {
140434
- if (h !== null) {
140435
- fn(h);
141901
+ const internals = this[$internals];
141902
+ syncHandlerEntries(this, internals);
141903
+ internals.iterationDepth++;
141904
+ try {
141905
+ _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach(this.handlers, function forEachHandler(h) {
141906
+ if (h !== null) {
141907
+ fn(h);
141908
+ }
141909
+ });
141910
+ } finally {
141911
+ if (! --internals.iterationDepth) {
141912
+ syncHandlerEntries(this, internals);
141913
+ trimHandlers(this.handlers);
141914
+ internals.handlersLength = countHandlers(this.handlers);
140436
141915
  }
140437
- });
141916
+ }
140438
141917
  }
140439
141918
  }
140440
141919
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (InterceptorManager);
@@ -140450,23 +141929,14 @@ class InterceptorManager {
140450
141929
  /* harmony import */ var _AxiosError_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7996);
140451
141930
  /* harmony import */ var _helpers_isAbsoluteURL_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6392);
140452
141931
  /* harmony import */ var _helpers_combineURLs_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(64133);
141932
+ /* harmony import */ var _helpers_normalizeURLForProtocolCheck_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69893);
141933
+
140453
141934
 
140454
141935
 
140455
141936
 
140456
141937
 
140457
141938
 
140458
141939
  const malformedHttpProtocol = /^https?:(?!\/\/)/i;
140459
- const httpProtocolControlCharacters = /[\t\n\r]/g;
140460
- function stripLeadingC0ControlOrSpace(url) {
140461
- let i = 0;
140462
- while (i < url.length && url.charCodeAt(i) <= 0x20) {
140463
- i++;
140464
- }
140465
- return url.slice(i);
140466
- }
140467
- function normalizeURLForProtocolCheck(url) {
140468
- return stripLeadingC0ControlOrSpace(url).replace(httpProtocolControlCharacters, '');
140469
- }
140470
141940
 
140471
141941
  // Redact the parts of a URL that can carry secrets before it is embedded in an
140472
141942
  // error message. AxiosError.toJSON() serializes `message` verbatim and errors
@@ -140496,7 +141966,7 @@ function redactSensitiveURLParts(url) {
140496
141966
  }
140497
141967
  function assertValidHttpProtocolURL(url, config) {
140498
141968
  if (typeof url === 'string') {
140499
- const normalizedURL = normalizeURLForProtocolCheck(url);
141969
+ const normalizedURL = (0,_helpers_normalizeURLForProtocolCheck_js__WEBPACK_IMPORTED_MODULE_3__/* ["default"] */ .A)(url);
140500
141970
  if (malformedHttpProtocol.test(normalizedURL)) {
140501
141971
  throw new _AxiosError_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A(`Invalid URL ${JSON.stringify(redactSensitiveURLParts(normalizedURL))}: missing "//" after protocol`, _AxiosError_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.ERR_INVALID_URL, config);
140502
141972
  }
@@ -140537,6 +142007,8 @@ function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls, config) {
140537
142007
  /* harmony import */ var _cancel_CanceledError_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(62200);
140538
142008
  /* harmony import */ var _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(88580);
140539
142009
  /* harmony import */ var _adapters_adapters_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(93129);
142010
+ /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(21285);
142011
+
140540
142012
 
140541
142013
 
140542
142014
 
@@ -140569,9 +142041,13 @@ function throwIfCancellationRequested(config) {
140569
142041
  *
140570
142042
  * @returns {Promise} The Promise to be fulfilled
140571
142043
  */
140572
- function dispatchRequest(config) {
142044
+ function dispatchRequest(_config) {
142045
+ // Interceptors may replace the merged config with an ordinary object. Flatten
142046
+ // it at the dispatch boundary so shared prototype members cannot become
142047
+ // request behavior, while preserving intentional template/class members.
142048
+ const config = _utils_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A.toSafeFlatObject(_config);
140573
142049
  throwIfCancellationRequested(config);
140574
- config.headers = _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_4__/* ["default"] */ .A.from(config.headers);
142050
+ config.headers = _core_AxiosHeaders_js__WEBPACK_IMPORTED_MODULE_4__/* ["default"] */ .A.from(_utils_js__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */ .A.getSafeProp(config, 'headers'));
140575
142051
 
140576
142052
  // Transform request data
140577
142053
  config.data = _transformData_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.call(config, config.transformRequest);
@@ -140734,7 +142210,7 @@ function mergeConfig(config1, config2) {
140734
142210
  transformResponse: defaultToConfig2,
140735
142211
  paramsSerializer: defaultToConfig2,
140736
142212
  timeout: defaultToConfig2,
140737
- timeoutMessage: defaultToConfig2,
142213
+ timeoutErrorMessage: defaultToConfig2,
140738
142214
  withCredentials: defaultToConfig2,
140739
142215
  withXSRFToken: defaultToConfig2,
140740
142216
  adapter: defaultToConfig2,
@@ -140780,6 +142256,19 @@ function mergeConfig(config1, config2) {
140780
142256
 
140781
142257
  /***/ },
140782
142258
 
142259
+ /***/ 31109
142260
+ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
142261
+
142262
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
142263
+ /* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__)
142264
+ /* harmony export */ });
142265
+
142266
+
142267
+ const methodList = Object.freeze(['get', 'delete', 'head', 'options', 'post', 'put', 'patch', 'purge', 'link', 'unlink', 'query']);
142268
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (methodList);
142269
+
142270
+ /***/ },
142271
+
140783
142272
  /***/ 19524
140784
142273
  (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
140785
142274
 
@@ -140896,6 +142385,8 @@ function transformData(fns, response) {
140896
142385
  /* harmony import */ var _helpers_toURLEncodedForm_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(88898);
140897
142386
  /* harmony import */ var _platform_index_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(75194);
140898
142387
  /* harmony import */ var _helpers_formDataToJSON_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(17757);
142388
+ /* harmony import */ var _core_methodList_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(31109);
142389
+
140899
142390
 
140900
142391
 
140901
142392
 
@@ -141021,7 +142512,7 @@ const defaults = {
141021
142512
  }
141022
142513
  }
141023
142514
  };
141024
- _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'query'], method => {
142515
+ _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach(_core_methodList_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A, method => {
141025
142516
  defaults.headers[method] = {};
141026
142517
  });
141027
142518
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (defaults);
@@ -141053,7 +142544,7 @@ _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.forEach(['delete', 'g
141053
142544
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
141054
142545
  /* harmony export */ x: () => (/* binding */ VERSION)
141055
142546
  /* harmony export */ });
141056
- const VERSION = "1.19.0";
142547
+ const VERSION = "1.20.0";
141057
142548
 
141058
142549
  /***/ },
141059
142550
 
@@ -141159,14 +142650,22 @@ const HttpStatusCode = {
141159
142650
  Gone: 410,
141160
142651
  LengthRequired: 411,
141161
142652
  PreconditionFailed: 412,
142653
+ /**
142654
+ * @deprecated Use `ContentTooLarge` instead.
142655
+ */
141162
142656
  PayloadTooLarge: 413,
142657
+ ContentTooLarge: 413,
141163
142658
  UriTooLong: 414,
141164
142659
  UnsupportedMediaType: 415,
141165
142660
  RangeNotSatisfiable: 416,
141166
142661
  ExpectationFailed: 417,
141167
142662
  ImATeapot: 418,
141168
142663
  MisdirectedRequest: 421,
142664
+ /**
142665
+ * @deprecated Use `UnprocessableContent` instead.
142666
+ */
141169
142667
  UnprocessableEntity: 422,
142668
+ UnprocessableContent: 422,
141170
142669
  Locked: 423,
141171
142670
  FailedDependency: 424,
141172
142671
  TooEarly: 425,
@@ -141195,7 +142694,9 @@ const HttpStatusCode = {
141195
142694
  InvalidSslCertificate: 526
141196
142695
  };
141197
142696
  Object.entries(HttpStatusCode).forEach(([key, value]) => {
141198
- HttpStatusCode[value] = key;
142697
+ if (HttpStatusCode[value] === undefined) {
142698
+ HttpStatusCode[value] = key;
142699
+ }
141199
142700
  });
141200
142701
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (HttpStatusCode);
141201
142702
 
@@ -141781,6 +143282,36 @@ function isAxiosError(payload) {
141781
143282
 
141782
143283
  /***/ },
141783
143284
 
143285
+ /***/ 69893
143286
+ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
143287
+
143288
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
143289
+ /* harmony export */ A: () => (/* binding */ normalizeURLForProtocolCheck)
143290
+ /* harmony export */ });
143291
+
143292
+
143293
+ const urlParserControlCharacters = /[\t\n\r]/g;
143294
+
143295
+ /**
143296
+ * Match WHATWG URL preprocessing before checking a URL's protocol.
143297
+ *
143298
+ * @param {string} url
143299
+ *
143300
+ * @returns {string}
143301
+ */
143302
+ function normalizeURLForProtocolCheck(url) {
143303
+ if (typeof url !== 'string') {
143304
+ return url;
143305
+ }
143306
+ let start = 0;
143307
+ while (start < url.length && url.charCodeAt(start) <= 0x20) {
143308
+ start++;
143309
+ }
143310
+ return url.slice(start).replace(urlParserControlCharacters, '');
143311
+ }
143312
+
143313
+ /***/ },
143314
+
141784
143315
  /***/ 65265
141785
143316
  (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
141786
143317
 
@@ -141883,7 +143414,7 @@ const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
141883
143414
  let bytesNotified = 0;
141884
143415
  const _speedometer = (0,_speedometer_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A)(50, 250);
141885
143416
  return (0,_throttle_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A)(e => {
141886
- if (!e || typeof e.loaded !== 'number') {
143417
+ if (!e || !_utils_js__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .A.isNumber(e.loaded)) {
141887
143418
  return;
141888
143419
  }
141889
143420
  const rawLoaded = e.loaded;
@@ -141983,11 +143514,12 @@ function resolveConfig(config) {
141983
143514
  }
141984
143515
  }
141985
143516
  if (_utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.isFormData(data)) {
143517
+ const getHeaders = _utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.getSafeProp(data, 'getHeaders');
141986
143518
  if (_platform_index_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.hasStandardBrowserEnv || _platform_index_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.hasStandardBrowserWebWorkerEnv || _utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.isReactNative(data)) {
141987
143519
  headers.setContentType(undefined); // browser/web worker/RN handles it
141988
- } else if (_utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.isFunction(data.getHeaders)) {
143520
+ } else if (_utils_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.isFunction(getHeaders)) {
141989
143521
  // Node.js FormData (like form-data package)
141990
- (0,_core_setFormDataHeaders_js__WEBPACK_IMPORTED_MODULE_8__/* ["default"] */ .A)(headers, data.getHeaders(), own('formDataHeaderPolicy'));
143522
+ (0,_core_setFormDataHeaders_js__WEBPACK_IMPORTED_MODULE_8__/* ["default"] */ .A)(headers, getHeaders.call(data), own('formDataHeaderPolicy'));
141991
143523
  }
141992
143524
  }
141993
143525
 
@@ -142170,7 +143702,7 @@ function spread(callback) {
142170
143702
  * Throttle decorator
142171
143703
  * @param {Function} fn
142172
143704
  * @param {Number} freq
142173
- * @return {Function}
143705
+ * @return {Array<Function>}
142174
143706
  */
142175
143707
  function throttle(fn, freq) {
142176
143708
  let timestamp = 0;
@@ -142202,7 +143734,8 @@ function throttle(fn, freq) {
142202
143734
  }
142203
143735
  };
142204
143736
  const flush = () => lastArgs && invoke(lastArgs);
142205
- return [throttled, flush];
143737
+ const flushWith = (...args) => invoke(args);
143738
+ return [throttled, flush, flushWith];
142206
143739
  }
142207
143740
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (throttle);
142208
143741
 
@@ -142314,23 +143847,17 @@ function toFormData(obj, formData, options) {
142314
143847
 
142315
143848
  // eslint-disable-next-line no-param-reassign
142316
143849
  formData = formData || new (_platform_node_classes_FormData_js__WEBPACK_IMPORTED_MODULE_2__/* ["default"] */ .A || FormData)();
142317
-
142318
- // eslint-disable-next-line no-param-reassign
142319
- options = _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.toFlatObject(options, {
142320
- metaTokens: true,
142321
- dots: false,
142322
- indexes: false
142323
- }, false, function defined(option, source) {
142324
- // eslint-disable-next-line no-eq-null,eqeqeq
142325
- return !_utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.isUndefined(source[option]);
142326
- });
142327
- const metaTokens = options.metaTokens;
143850
+ const option = (name, fallback) => {
143851
+ const value = _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.getSafeProp(options, name);
143852
+ return _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.isUndefined(value) ? fallback : value;
143853
+ };
143854
+ const metaTokens = option('metaTokens', true);
142328
143855
  // eslint-disable-next-line no-use-before-define
142329
- const visitor = options.visitor || defaultVisitor;
142330
- const dots = options.dots;
142331
- const indexes = options.indexes;
142332
- const _Blob = options.Blob || typeof Blob !== 'undefined' && Blob;
142333
- const maxDepth = options.maxDepth === undefined ? DEFAULT_FORM_DATA_MAX_DEPTH : options.maxDepth;
143856
+ const visitor = option('visitor') || defaultVisitor;
143857
+ const dots = option('dots', false);
143858
+ const indexes = option('indexes', false);
143859
+ const _Blob = option('Blob') || typeof Blob !== 'undefined' && Blob;
143860
+ const maxDepth = option('maxDepth', DEFAULT_FORM_DATA_MAX_DEPTH);
142334
143861
  const useBlob = _Blob && _utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.isSpecCompliantForm(formData);
142335
143862
  const stack = [];
142336
143863
  if (!_utils_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.isFunction(visitor)) {
@@ -142827,13 +144354,57 @@ const {
142827
144354
  const hasOwnProperty = (({
142828
144355
  hasOwnProperty
142829
144356
  }) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype);
144357
+ const isUnsafeObjectKey = prop => typeof prop === 'string' && (prop === '__proto__' || prop === 'constructor' || prop === 'prototype');
144358
+
144359
+ /**
144360
+ * Determine whether an inherited object must be treated as a shared-prototype
144361
+ * boundary. Cross-realm Object.prototype objects cannot be distinguished
144362
+ * reliably from application-created null-prototype objects because their
144363
+ * properties are mutable, so all inherited terminal prototypes are excluded
144364
+ * as a fail-closed boundary. A null-prototype source still keeps its own
144365
+ * properties, as produced by mergeConfig and other safe materialization paths.
144366
+ *
144367
+ * @param {*} obj The object to inspect
144368
+ * @param {*} prototype The object's prototype
144369
+ * @param {boolean} source Whether obj is the original traversal source
144370
+ *
144371
+ * @returns {boolean} True when obj is a safe prototype traversal boundary
144372
+ */
144373
+ const isPrototypeBoundary = (obj, prototype, source) => obj === Object.prototype || !source && prototype === null;
144374
+
144375
+ /**
144376
+ * Determine whether an object can retain its identity through code paths that
144377
+ * add, replace, and remove config properties without bypassing unsafe-key
144378
+ * filtering. Immutable objects, unsafe-key-bearing objects, and objects with
144379
+ * accessor or restricted data properties must be materialized instead.
144380
+ *
144381
+ * @param {*} obj The object to inspect
144382
+ *
144383
+ * @returns {boolean} True when every own property is safe and fully mutable
144384
+ */
144385
+ const isSafeAndFullyMutable = obj => {
144386
+ if (!Object.isExtensible(obj)) {
144387
+ return false;
144388
+ }
144389
+ const props = Object.getOwnPropertyNames(obj);
144390
+ if (Object.getOwnPropertySymbols) {
144391
+ props.push(...Object.getOwnPropertySymbols(obj));
144392
+ }
144393
+ return props.every(prop => {
144394
+ if (isUnsafeObjectKey(prop)) {
144395
+ return false;
144396
+ }
144397
+ const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
144398
+ return !!descriptor && descriptor.configurable && descriptor.writable === true;
144399
+ });
144400
+ };
142830
144401
 
142831
144402
  /**
142832
- * Walk the prototype chain (excluding the shared Object.prototype) looking for
142833
- * an own `prop`. This distinguishes genuine own/inherited members — including
142834
- * class accessors and template prototypes — from members injected via
142835
- * Object.prototype pollution (e.g. `Object.prototype.username = '...'`), which
142836
- * live on Object.prototype itself and are therefore never matched.
144403
+ * Walk the prototype chain (excluding the source realm's Object.prototype)
144404
+ * looking for an own `prop`. This distinguishes genuine own/inherited members
144405
+ * — including class accessors and template prototypes — from members injected
144406
+ * via Object.prototype pollution (e.g. `Object.prototype.username = '...'`),
144407
+ * which live on Object.prototype itself and are therefore never matched.
142837
144408
  *
142838
144409
  * @param {*} thing The value whose chain to inspect
142839
144410
  * @param {string|symbol} prop The property key to look for
@@ -142843,15 +144414,19 @@ const hasOwnProperty = (({
142843
144414
  const hasOwnInPrototypeChain = (thing, prop) => {
142844
144415
  let obj = thing;
142845
144416
  const seen = [];
142846
- while (obj != null && obj !== Object.prototype) {
144417
+ while (obj != null) {
142847
144418
  if (seen.indexOf(obj) !== -1) {
142848
144419
  return false;
142849
144420
  }
142850
144421
  seen.push(obj);
144422
+ const prototype = getPrototypeOf(obj);
144423
+ if (isPrototypeBoundary(obj, prototype, obj === thing)) {
144424
+ return false;
144425
+ }
142851
144426
  if (hasOwnProperty(obj, prop)) {
142852
144427
  return true;
142853
144428
  }
142854
- obj = getPrototypeOf(obj);
144429
+ obj = prototype;
142855
144430
  }
142856
144431
  return false;
142857
144432
  };
@@ -142868,6 +144443,56 @@ const hasOwnInPrototypeChain = (thing, prop) => {
142868
144443
  * @returns {*} The resolved value, or undefined when unsafe/absent
142869
144444
  */
142870
144445
  const getSafeProp = (obj, prop) => obj != null && hasOwnInPrototypeChain(obj, prop) ? obj[prop] : undefined;
144446
+
144447
+ /**
144448
+ * Flatten an object and its application-defined prototype chain into a
144449
+ * null-prototype object. Members inherited only from the source realm's
144450
+ * Object.prototype are deliberately excluded, while class/template members
144451
+ * below that boundary are preserved.
144452
+ *
144453
+ * @param {*} thing The value to flatten
144454
+ *
144455
+ * @returns {*} A null-prototype copy, or the original value when it is already
144456
+ * structurally safe or is not an object
144457
+ */
144458
+ const toSafeFlatObject = thing => {
144459
+ if (thing == null || typeof thing !== 'object' && typeof thing !== 'function') {
144460
+ return thing;
144461
+ }
144462
+ const sourcePrototype = getPrototypeOf(thing);
144463
+ if (sourcePrototype === null && isSafeAndFullyMutable(thing)) {
144464
+ return thing;
144465
+ }
144466
+ const result = Object.create(null);
144467
+ const merged = Object.create(null);
144468
+ const seen = [];
144469
+ let current = thing;
144470
+ while (current != null) {
144471
+ if (seen.indexOf(current) !== -1) {
144472
+ break;
144473
+ }
144474
+ seen.push(current);
144475
+ const prototype = current === thing ? sourcePrototype : getPrototypeOf(current);
144476
+ if (isPrototypeBoundary(current, prototype, current === thing)) {
144477
+ break;
144478
+ }
144479
+ const props = Object.getOwnPropertyNames(current);
144480
+ if (Object.getOwnPropertySymbols) {
144481
+ props.push(...Object.getOwnPropertySymbols(current));
144482
+ }
144483
+ for (const prop of props) {
144484
+ if (isUnsafeObjectKey(prop)) {
144485
+ continue;
144486
+ }
144487
+ if (!hasOwnProperty(merged, prop)) {
144488
+ result[prop] = thing[prop];
144489
+ merged[prop] = true;
144490
+ }
144491
+ }
144492
+ current = prototype;
144493
+ }
144494
+ return result;
144495
+ };
142871
144496
  const kindOf = (cache => thing => {
142872
144497
  const str = toString.call(thing);
142873
144498
  return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
@@ -142991,9 +144616,9 @@ const isPlainObject = val => {
142991
144616
  }
142992
144617
  const prototype = getPrototypeOf(val);
142993
144618
  return (prototype === null || prototype === Object.prototype || getPrototypeOf(prototype) === null) &&
142994
- // Treat any genuine (non-Object.prototype-polluted) Symbol.toStringTag or
142995
- // Symbol.iterator as evidence the value is a tagged/iterable type rather
142996
- // than a plain object, while ignoring keys injected onto Object.prototype.
144619
+ // Treat safe own/inherited Symbol.toStringTag or Symbol.iterator members as
144620
+ // evidence the value is tagged/iterable, while ignoring members reachable
144621
+ // only through shared or terminal prototype boundaries.
142997
144622
  !hasOwnInPrototypeChain(val, toStringTag) && !hasOwnInPrototypeChain(val, iterator);
142998
144623
  };
142999
144624
 
@@ -143741,6 +145366,7 @@ const isSafeIterable = thing => thing != null && hasOwnInPrototypeChain(thing, i
143741
145366
  // an alias to avoid ESLint no-prototype-builtins detection
143742
145367
  hasOwnInPrototypeChain,
143743
145368
  getSafeProp,
145369
+ toSafeFlatObject,
143744
145370
  reduceDescriptors,
143745
145371
  freezeMethods,
143746
145372
  toObjectSet,