@seamly/web-ui 22.1.0 → 22.3.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/build/dist/lib/components.js +698 -318
  2. package/build/dist/lib/components.js.map +1 -1
  3. package/build/dist/lib/components.min.js +1 -1
  4. package/build/dist/lib/components.min.js.LICENSE.txt +2 -2
  5. package/build/dist/lib/components.min.js.map +1 -1
  6. package/build/dist/lib/hooks.js +301 -60
  7. package/build/dist/lib/hooks.js.map +1 -1
  8. package/build/dist/lib/hooks.min.js +1 -1
  9. package/build/dist/lib/hooks.min.js.map +1 -1
  10. package/build/dist/lib/index.debug.js +80 -58
  11. package/build/dist/lib/index.debug.js.map +1 -1
  12. package/build/dist/lib/index.debug.min.js +1 -1
  13. package/build/dist/lib/index.debug.min.js.LICENSE.txt +12 -4
  14. package/build/dist/lib/index.debug.min.js.map +1 -1
  15. package/build/dist/lib/index.js +718 -325
  16. package/build/dist/lib/index.js.map +1 -1
  17. package/build/dist/lib/index.min.js +1 -1
  18. package/build/dist/lib/index.min.js.LICENSE.txt +2 -2
  19. package/build/dist/lib/index.min.js.map +1 -1
  20. package/build/dist/lib/standalone.js +803 -348
  21. package/build/dist/lib/standalone.js.map +1 -1
  22. package/build/dist/lib/standalone.min.js +1 -1
  23. package/build/dist/lib/standalone.min.js.LICENSE.txt +1 -1
  24. package/build/dist/lib/standalone.min.js.map +1 -1
  25. package/build/dist/lib/style-guide.js +830 -323
  26. package/build/dist/lib/style-guide.js.map +1 -1
  27. package/build/dist/lib/style-guide.min.js +1 -1
  28. package/build/dist/lib/style-guide.min.js.LICENSE.txt +2 -2
  29. package/build/dist/lib/style-guide.min.js.map +1 -1
  30. package/build/dist/lib/styles-default-implementation.js +1 -1
  31. package/build/dist/lib/styles.css +1 -1
  32. package/build/dist/lib/styles.js +1 -1
  33. package/build/dist/lib/utils.js +783 -360
  34. package/build/dist/lib/utils.js.map +1 -1
  35. package/build/dist/lib/utils.min.js +1 -1
  36. package/build/dist/lib/utils.min.js.LICENSE.txt +1 -1
  37. package/build/dist/lib/utils.min.js.map +1 -1
  38. package/package.json +28 -28
  39. package/src/javascripts/api/errors/seamly-api-error.ts +0 -1
  40. package/src/javascripts/api/index.ts +29 -9
  41. package/src/javascripts/domains/app/actions.ts +8 -3
  42. package/src/javascripts/domains/config/slice.ts +2 -1
  43. package/src/javascripts/domains/forms/selectors.ts +6 -8
  44. package/src/javascripts/domains/forms/slice.ts +1 -1
  45. package/src/javascripts/domains/interrupt/selectors.ts +3 -2
  46. package/src/javascripts/domains/interrupt/slice.ts +2 -0
  47. package/src/javascripts/domains/redux/create-debounced-async-thunk.ts +109 -0
  48. package/src/javascripts/domains/redux/redux.types.ts +2 -1
  49. package/src/javascripts/domains/store/actions.ts +38 -0
  50. package/src/javascripts/domains/translations/components/options-dialog/translation-option.tsx +3 -1
  51. package/src/javascripts/domains/translations/components/options-dialog/translation-options.tsx +62 -35
  52. package/src/javascripts/domains/translations/slice.ts +8 -1
  53. package/src/javascripts/domains/visibility/actions.ts +4 -1
  54. package/src/javascripts/lib/engine/index.tsx +3 -1
  55. package/src/javascripts/style-guide/states.js +65 -1
  56. package/src/javascripts/ui/components/conversation/event/{card-component.js → card-component.tsx} +6 -4
  57. package/src/javascripts/ui/components/conversation/event/event-participant.js +1 -1
  58. package/src/javascripts/ui/components/core/seamly-event-subscriber.ts +14 -30
  59. package/src/javascripts/ui/components/entry/text-entry/hooks.ts +2 -2
  60. package/src/javascripts/ui/components/form-controls/wrapper.tsx +13 -3
  61. package/src/javascripts/ui/components/view/window-view/window-open-button.js +8 -3
  62. package/src/javascripts/ui/hooks/use-session-expired-command.ts +31 -2
  63. package/src/stylesheets/5-components/_input.scss +0 -5
  64. package/src/stylesheets/5-components/_message-count.scss +11 -9
  65. package/src/stylesheets/5-components/_options.scss +2 -2
  66. package/src/stylesheets/5-components/_translation-options.scss +23 -3
@@ -1331,10 +1331,10 @@ var store = __webpack_require__(5465);
1331
1331
  (module.exports = function (key, value) {
1332
1332
  return store[key] || (store[key] = value !== undefined ? value : {});
1333
1333
  })('versions', []).push({
1334
- version: '3.30.2',
1334
+ version: '3.31.1',
1335
1335
  mode: IS_PURE ? 'pure' : 'global',
1336
1336
  copyright: '© 2014-2023 Denis Pushkarev (zloirock.ru)',
1337
- license: 'https://github.com/zloirock/core-js/blob/v3.30.2/LICENSE',
1337
+ license: 'https://github.com/zloirock/core-js/blob/v3.31.1/LICENSE',
1338
1338
  source: 'https://github.com/zloirock/core-js'
1339
1339
  });
1340
1340
 
@@ -1609,7 +1609,7 @@ var toIntegerOrInfinity = __webpack_require__(9303);
1609
1609
  var addToUnscopables = __webpack_require__(1223);
1610
1610
 
1611
1611
  // `Array.prototype.at` method
1612
- // https://github.com/tc39/proposal-relative-indexing-method
1612
+ // https://tc39.es/ecma262/#sec-array.prototype.at
1613
1613
  $({ target: 'Array', proto: true }, {
1614
1614
  at: function at(index) {
1615
1615
  var O = toObject(this);
@@ -3762,6 +3762,7 @@ _ConversationConnector_connectionListeners = new WeakMap(), _ConversationConnect
3762
3762
  return !complete;
3763
3763
  }), "f");
3764
3764
  };
3765
+ /* harmony default export */ const conversation_connector = (ConversationConnector);
3765
3766
  ;// CONCATENATED MODULE: ./src/javascripts/api/index.ts
3766
3767
  var api_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
3767
3768
  function adopt(value) {
@@ -3801,6 +3802,14 @@ var api_classPrivateFieldGet = undefined && undefined.__classPrivateFieldGet ||
3801
3802
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
3802
3803
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
3803
3804
  };
3805
+ var __rest = undefined && undefined.__rest || function (s, e) {
3806
+ var t = {};
3807
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
3808
+ if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
3809
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
3810
+ }
3811
+ return t;
3812
+ };
3804
3813
  var _API_instances, _API_ready, _API_externalId, _API_conversationAuthToken, _API_layoutMode, _API_config, _API_getAccessToken, _API_setAccessToken, _API_setConversationUrl, _API_getChannelTopic, _API_setChannelTopic, _API_getLocale, _API_getUrlPrefix, _API_updateUrls, _API_createConversation, _API_getEnvironment;
3805
3814
 
3806
3815
 
@@ -3888,7 +3897,7 @@ class API {
3888
3897
  _API_conversationAuthToken.set(this, void 0);
3889
3898
  _API_layoutMode.set(this, void 0);
3890
3899
  _API_config.set(this, void 0);
3891
- this.conversation = new ConversationConnector();
3900
+ this.conversation = new conversation_connector();
3892
3901
  _API_getLocale.set(this, locale => locale || this.locale);
3893
3902
  this.store = objectStore(`${namespace}.connection${context.locale ? `.${context.locale}` : ''}`, config.storageProvider || store);
3894
3903
  this.connectionInfo = {
@@ -3918,7 +3927,8 @@ class API {
3918
3927
  });
3919
3928
  }
3920
3929
  getConversationUrl() {
3921
- return this.store.get('conversationUrl');
3930
+ const conversationUrl = this.store.get('conversationUrl');
3931
+ return conversationUrl;
3922
3932
  }
3923
3933
  hasConversation() {
3924
3934
  return !!this.getConversationUrl();
@@ -4026,7 +4036,7 @@ class API {
4026
4036
  if (error.status >= 500) {
4027
4037
  throw new SeamlyGeneralError(error);
4028
4038
  }
4029
- throw error;
4039
+ throw new ApiError(error);
4030
4040
  }
4031
4041
  });
4032
4042
  }
@@ -4135,7 +4145,7 @@ class API {
4135
4145
  if (error.status >= 500) {
4136
4146
  throw new SeamlyGeneralError(error);
4137
4147
  }
4138
- throw error;
4148
+ throw new ApiError(error);
4139
4149
  }
4140
4150
  });
4141
4151
  }
@@ -4161,6 +4171,7 @@ class API {
4161
4171
  this.conversation.pushToChannel(command, buildPayload(command, payload), 10000);
4162
4172
  }
4163
4173
  sendContext(context) {
4174
+ var _a;
4164
4175
  const {
4165
4176
  locale,
4166
4177
  variables
@@ -4182,19 +4193,29 @@ class API {
4182
4193
  if (Object.keys(payload).length === 0 && payload.constructor === Object) {
4183
4194
  return;
4184
4195
  }
4185
- this.send('context', payload, false);
4196
+ // Destructure the server locale from the payload
4197
+ const {
4198
+ locale: _
4199
+ } = payload,
4200
+ restPayload = __rest(payload, ["locale"]);
4201
+ const configLocale = (_a = api_classPrivateFieldGet(this, _API_config, "f").context) === null || _a === void 0 ? void 0 : _a.locale;
4202
+ this.send('context', Object.assign(Object.assign({}, configLocale ? {
4203
+ locale: configLocale
4204
+ } : {}), restPayload), false);
4186
4205
  }
4187
4206
  }
4188
4207
  _API_ready = new WeakMap(), _API_externalId = new WeakMap(), _API_conversationAuthToken = new WeakMap(), _API_layoutMode = new WeakMap(), _API_config = new WeakMap(), _API_getLocale = new WeakMap(), _API_instances = new WeakSet(), _API_getAccessToken = function _API_getAccessToken() {
4189
- return this.store.get('accessToken');
4208
+ const accessToken = this.store.get('accessToken');
4209
+ return accessToken;
4190
4210
  }, _API_setAccessToken = function _API_setAccessToken(accessToken) {
4191
4211
  this.store.set('accessToken', accessToken);
4192
4212
  }, _API_setConversationUrl = function _API_setConversationUrl(url) {
4193
4213
  this.store.set('conversationUrl', url);
4194
4214
  }, _API_getChannelTopic = function _API_getChannelTopic() {
4215
+ const channelTopic = this.store.get('channelTopic') || this.store.get('channelName');
4195
4216
  // The `channelName` fallback is needed for seamless client upgrades.
4196
4217
  // TODO: Remove when all clients have been upgraded past v20.
4197
- return this.store.get('channelTopic') || this.store.get('channelName');
4218
+ return channelTopic;
4198
4219
  }, _API_setChannelTopic = function _API_setChannelTopic(topic) {
4199
4220
  this.store.set('channelTopic', topic);
4200
4221
  }, _API_getUrlPrefix = function _API_getUrlPrefix(protocol) {
@@ -4259,7 +4280,7 @@ _API_ready = new WeakMap(), _API_externalId = new WeakMap(), _API_conversationAu
4259
4280
  return {
4260
4281
  clientName: "@seamly/web-ui",
4261
4282
  clientVariant: api_classPrivateFieldGet(this, _API_layoutMode, "f"),
4262
- clientVersion: "22.1.0",
4283
+ clientVersion: "22.3.0-beta.1",
4263
4284
  currentUrl: window.location.toString(),
4264
4285
  screenResolution: `${window.screen.width}x${window.screen.height}`,
4265
4286
  timezone: getTimeZone(),
@@ -4295,15 +4316,52 @@ const setBatch = newBatch => batch = newBatch; // Supply a getter just to skip d
4295
4316
  const getBatch = () => batch;
4296
4317
  ;// CONCATENATED MODULE: ./node_modules/react-redux/es/components/Context.js
4297
4318
 
4298
- const Context_ReactReduxContext = /*#__PURE__*/(0,compat_module.createContext)(null);
4319
+ const ContextKey = Symbol.for(`react-redux-context-${compat_module.version}`);
4320
+ const gT = globalThis;
4299
4321
 
4300
- if (false) {}
4322
+ function getContext() {
4323
+ let realContext = gT[ContextKey];
4301
4324
 
4325
+ if (!realContext) {
4326
+ realContext = (0,compat_module.createContext)(null);
4327
+
4328
+ if (false) {}
4329
+
4330
+ gT[ContextKey] = realContext;
4331
+ }
4332
+
4333
+ return realContext;
4334
+ }
4335
+
4336
+ const Context_ReactReduxContext = /*#__PURE__*/new Proxy({}, /*#__PURE__*/new Proxy({}, {
4337
+ get(_, handler) {
4338
+ const target = getContext(); // @ts-ignore
4339
+
4340
+ return (_target, ...args) => Reflect[handler](target, ...args);
4341
+ }
4342
+
4343
+ }));
4302
4344
  /* harmony default export */ const Context = ((/* unused pure expression or super */ null && (Context_ReactReduxContext)));
4303
4345
  ;// CONCATENATED MODULE: ./node_modules/react-redux/es/hooks/useReduxContext.js
4304
4346
 
4305
4347
 
4306
4348
 
4349
+ /**
4350
+ * Hook factory, which creates a `useReduxContext` hook bound to a given context. This is a low-level
4351
+ * hook that you should usually not need to call directly.
4352
+ *
4353
+ * @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
4354
+ * @returns {Function} A `useReduxContext` hook bound to the specified context.
4355
+ */
4356
+ function createReduxContextHook(context = Context_ReactReduxContext) {
4357
+ return function useReduxContext() {
4358
+ const contextValue = (0,compat_module.useContext)(context);
4359
+
4360
+ if (false) {}
4361
+
4362
+ return contextValue;
4363
+ };
4364
+ }
4307
4365
  /**
4308
4366
  * A hook to access the value of the `ReactReduxContext`. This is a low-level
4309
4367
  * hook that you should usually not need to call directly.
@@ -4320,13 +4378,8 @@ if (false) {}
4320
4378
  * return <div>{store.getState()}</div>
4321
4379
  * }
4322
4380
  */
4323
- function useReduxContext_useReduxContext() {
4324
- const contextValue = (0,compat_module.useContext)(Context_ReactReduxContext);
4325
4381
 
4326
- if (false) {}
4327
-
4328
- return contextValue;
4329
- }
4382
+ const useReduxContext_useReduxContext = /*#__PURE__*/createReduxContextHook();
4330
4383
  ;// CONCATENATED MODULE: ./node_modules/react-redux/es/utils/useSyncExternalStore.js
4331
4384
  const useSyncExternalStore_notInitialized = () => {
4332
4385
  throw new Error('uSES not initialized!');
@@ -4351,16 +4404,37 @@ const refEquality = (a, b) => a === b;
4351
4404
 
4352
4405
 
4353
4406
  function createSelectorHook(context = Context_ReactReduxContext) {
4354
- const useReduxContext = context === Context_ReactReduxContext ? useReduxContext_useReduxContext : () => (0,compat_module.useContext)(context);
4355
- return function useSelector(selector, equalityFn = refEquality) {
4407
+ const useReduxContext = context === Context_ReactReduxContext ? useReduxContext_useReduxContext : createReduxContextHook(context);
4408
+ return function useSelector(selector, equalityFnOrOptions = {}) {
4409
+ const {
4410
+ equalityFn = refEquality,
4411
+ stabilityCheck = undefined,
4412
+ noopCheck = undefined
4413
+ } = typeof equalityFnOrOptions === 'function' ? {
4414
+ equalityFn: equalityFnOrOptions
4415
+ } : equalityFnOrOptions;
4416
+
4356
4417
  if (false) {}
4357
4418
 
4358
4419
  const {
4359
4420
  store,
4360
4421
  subscription,
4361
- getServerState
4422
+ getServerState,
4423
+ stabilityCheck: globalStabilityCheck,
4424
+ noopCheck: globalNoopCheck
4362
4425
  } = useReduxContext();
4363
- const selectedState = useSyncExternalStoreWithSelector(subscription.addNestedSub, store.getState, getServerState || store.getState, selector, equalityFn);
4426
+ const firstRun = (0,compat_module.useRef)(true);
4427
+ const wrappedSelector = (0,compat_module.useCallback)({
4428
+ [selector.name](state) {
4429
+ const selected = selector(state);
4430
+
4431
+ if (false) {}
4432
+
4433
+ return selected;
4434
+ }
4435
+
4436
+ }[selector.name], [selector, globalStabilityCheck, stabilityCheck]);
4437
+ const selectedState = useSyncExternalStoreWithSelector(subscription.addNestedSub, store.getState, getServerState || store.getState, wrappedSelector, equalityFn);
4364
4438
  (0,compat_module.useDebugValue)(selectedState);
4365
4439
  return selectedState;
4366
4440
  };
@@ -4947,16 +5021,20 @@ function Provider({
4947
5021
  store,
4948
5022
  context,
4949
5023
  children,
4950
- serverState
5024
+ serverState,
5025
+ stabilityCheck = 'once',
5026
+ noopCheck = 'once'
4951
5027
  }) {
4952
5028
  const contextValue = (0,compat_module.useMemo)(() => {
4953
5029
  const subscription = Subscription_createSubscription(store);
4954
5030
  return {
4955
5031
  store,
4956
5032
  subscription,
4957
- getServerState: serverState ? () => serverState : undefined
5033
+ getServerState: serverState ? () => serverState : undefined,
5034
+ stabilityCheck,
5035
+ noopCheck
4958
5036
  };
4959
- }, [store, serverState]);
5037
+ }, [store, serverState, stabilityCheck, noopCheck]);
4960
5038
  const previousState = (0,compat_module.useMemo)(() => store.getState(), [store]);
4961
5039
  useIsomorphicLayoutEffect_useIsomorphicLayoutEffect(() => {
4962
5040
  const {
@@ -4985,7 +5063,6 @@ function Provider({
4985
5063
  ;// CONCATENATED MODULE: ./node_modules/react-redux/es/hooks/useStore.js
4986
5064
 
4987
5065
 
4988
-
4989
5066
  /**
4990
5067
  * Hook factory, which creates a `useStore` hook bound to a given context.
4991
5068
  *
@@ -4995,7 +5072,8 @@ function Provider({
4995
5072
 
4996
5073
  function createStoreHook(context = Context_ReactReduxContext) {
4997
5074
  const useReduxContext = // @ts-ignore
4998
- context === Context_ReactReduxContext ? useReduxContext_useReduxContext : () => (0,compat_module.useContext)(context);
5075
+ context === Context_ReactReduxContext ? useReduxContext_useReduxContext : // @ts-ignore
5076
+ createReduxContextHook(context);
4999
5077
  return function useStore() {
5000
5078
  const {
5001
5079
  store
@@ -8036,6 +8114,62 @@ const setLocale = createAsyncThunk('setLocale', (locale, {
8036
8114
  return true;
8037
8115
  }
8038
8116
  });
8117
+ ;// CONCATENATED MODULE: ./src/javascripts/domains/redux/create-debounced-async-thunk.ts
8118
+
8119
+ /**
8120
+ * A debounced analogue of the `createAsyncThunk` from `@reduxjs/toolkit`
8121
+ * @param typePrefix - a string action type value
8122
+ * @param payloadCreator - a callback function that should return a promise containing the result of some asynchronous logic
8123
+ * @param debounceOptions - the debounce options object
8124
+ */
8125
+ const createDebouncedAsyncThunk = (typePrefix, payloadCreator, debounceOptions) => {
8126
+ const {
8127
+ wait = 300,
8128
+ maxWait = 0,
8129
+ leading = false
8130
+ } = debounceOptions !== null && debounceOptions !== void 0 ? debounceOptions : {};
8131
+ let debounceTimer = null;
8132
+ let maxWaitTimer = null;
8133
+ let resolve;
8134
+ const cancel = () => {
8135
+ if (resolve) {
8136
+ resolve(false);
8137
+ resolve = undefined;
8138
+ }
8139
+ };
8140
+ const invoke = () => {
8141
+ clearTimeout(maxWaitTimer);
8142
+ maxWaitTimer = undefined;
8143
+ if (resolve) {
8144
+ resolve(true);
8145
+ resolve = undefined;
8146
+ }
8147
+ };
8148
+ const debounceExecutionCondition = () => {
8149
+ const immediate = leading && !debounceTimer;
8150
+ // Start debounced condition resolution
8151
+ clearTimeout(debounceTimer);
8152
+ debounceTimer = setTimeout(() => {
8153
+ invoke();
8154
+ debounceTimer = null;
8155
+ }, wait);
8156
+ if (immediate) {
8157
+ return true;
8158
+ }
8159
+ cancel();
8160
+ // Start max wait condition resolution
8161
+ if (maxWait && !maxWaitTimer) {
8162
+ maxWaitTimer = setTimeout(invoke, maxWait);
8163
+ }
8164
+ return new Promise(res => {
8165
+ resolve = res;
8166
+ });
8167
+ };
8168
+ return createAsyncThunk(typePrefix, payloadCreator, {
8169
+ condition: debounceExecutionCondition
8170
+ });
8171
+ };
8172
+ /* harmony default export */ const create_debounced_async_thunk = (createDebouncedAsyncThunk);
8039
8173
  ;// CONCATENATED MODULE: ./node_modules/reselect/es/defaultMemoize.js
8040
8174
  // Cache implementation based on Erik Rasmussen's `lru-memoize`:
8041
8175
  // https://github.com/erikras/lru-memoize
@@ -8592,8 +8726,9 @@ const setVisibility = createAsyncThunk('setVisibility', (requestedVisibility, {
8592
8726
  if (previousVisibility === calculatedVisibility) {
8593
8727
  return undefined;
8594
8728
  }
8729
+ const visibility = api.store.get(StoreKey);
8595
8730
  // Store the user-requested visibility in order to reinitialize after refresh
8596
- api.store.set(StoreKey, Object.assign(Object.assign({}, api.store.get(StoreKey) || {}), {
8731
+ api.store.set(StoreKey, Object.assign(Object.assign({}, visibility || {}), {
8597
8732
  [layoutMode]: requestedVisibility
8598
8733
  }));
8599
8734
  if (requestedVisibility) {
@@ -8657,6 +8792,7 @@ var app_actions_awaiter = undefined && undefined.__awaiter || function (thisArg,
8657
8792
 
8658
8793
 
8659
8794
 
8795
+
8660
8796
  const initializeApp = createAsyncThunk('initializeApp', (_, {
8661
8797
  extra: {
8662
8798
  api,
@@ -8722,14 +8858,14 @@ const initializeApp = createAsyncThunk('initializeApp', (_, {
8722
8858
  });
8723
8859
  }
8724
8860
  }));
8725
- const resetApp = createAsyncThunk('resetApp', (_, {
8861
+ const resetApp = create_debounced_async_thunk('resetApp', (_, {
8726
8862
  dispatch,
8727
8863
  extra: {
8728
8864
  api
8729
8865
  }
8730
8866
  }) => app_actions_awaiter(void 0, void 0, void 0, function* () {
8731
8867
  yield api.disconnect();
8732
- yield api.clearStore();
8868
+ api.clearStore();
8733
8869
  dispatch(resetConfig());
8734
8870
  yield dispatch(initializeConfig());
8735
8871
  try {
@@ -8737,11 +8873,14 @@ const resetApp = createAsyncThunk('resetApp', (_, {
8737
8873
  locale
8738
8874
  } = yield dispatch(initializeApp()).unwrap();
8739
8875
  yield dispatch(setLocale(locale));
8740
- } catch (rejectedValueOrSerializedError) {
8876
+ } catch (e) {
8741
8877
  // nothing to do
8742
8878
  }
8743
8879
  dispatch(initializeVisibility());
8744
- }));
8880
+ }), {
8881
+ wait: 2000,
8882
+ leading: true
8883
+ });
8745
8884
  ;// CONCATENATED MODULE: ./src/javascripts/domains/app/hooks.js
8746
8885
 
8747
8886
 
@@ -8777,12 +8916,75 @@ const {
8777
8916
  setHasResponded
8778
8917
  } = appSlice.actions;
8779
8918
  /* harmony default export */ const slice = (appSlice.reducer);
8919
+ ;// CONCATENATED MODULE: ./src/javascripts/domains/store/actions.ts
8920
+ var store_actions_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
8921
+ function adopt(value) {
8922
+ return value instanceof P ? value : new P(function (resolve) {
8923
+ resolve(value);
8924
+ });
8925
+ }
8926
+ return new (P || (P = Promise))(function (resolve, reject) {
8927
+ function fulfilled(value) {
8928
+ try {
8929
+ step(generator.next(value));
8930
+ } catch (e) {
8931
+ reject(e);
8932
+ }
8933
+ }
8934
+ function rejected(value) {
8935
+ try {
8936
+ step(generator["throw"](value));
8937
+ } catch (e) {
8938
+ reject(e);
8939
+ }
8940
+ }
8941
+ function step(result) {
8942
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
8943
+ }
8944
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8945
+ });
8946
+ };
8947
+
8948
+ const getConversation = createAsyncThunk('getConversation', (_, {
8949
+ extra: {
8950
+ api
8951
+ },
8952
+ rejectWithValue
8953
+ }) => store_actions_awaiter(void 0, void 0, void 0, function* () {
8954
+ try {
8955
+ return api.getConversation();
8956
+ } catch (error) {
8957
+ return rejectWithValue({
8958
+ name: error === null || error === void 0 ? void 0 : error.name,
8959
+ message: error === null || error === void 0 ? void 0 : error.message,
8960
+ langKey: error === null || error === void 0 ? void 0 : error.langKey,
8961
+ action: error === null || error === void 0 ? void 0 : error.action,
8962
+ originalEvent: error === null || error === void 0 ? void 0 : error.originalEvent,
8963
+ originalError: error === null || error === void 0 ? void 0 : error.originalError
8964
+ });
8965
+ }
8966
+ }), {
8967
+ condition(payload, {
8968
+ getState
8969
+ }) {
8970
+ var _a;
8971
+ const {
8972
+ state: {
8973
+ events
8974
+ }
8975
+ } = getState();
8976
+ const lastEvent = events[events.length - 1];
8977
+ const payloadLastEventId = (_a = payload === null || payload === void 0 ? void 0 : payload.lastEvent) === null || _a === void 0 ? void 0 : _a.id;
8978
+ return lastEvent && payloadLastEventId !== lastEvent.payload.id;
8979
+ }
8980
+ });
8780
8981
  ;// CONCATENATED MODULE: ./src/javascripts/domains/interrupt/slice.ts
8781
8982
 
8782
8983
 
8783
8984
 
8784
8985
 
8785
8986
 
8987
+
8786
8988
  const slice_initialState = {
8787
8989
  error: undefined
8788
8990
  };
@@ -8796,7 +8998,7 @@ const interruptSlice = createSlice({
8796
8998
  clearInterrupt: () => slice_initialState
8797
8999
  },
8798
9000
  extraReducers: builder => {
8799
- builder.addCase(initializeConfig.pending, () => slice_initialState).addMatcher(isAnyOf(initializeApp.rejected, initializeConfig.rejected, setLocale.rejected, setVisibility.rejected, initializeVisibility.rejected), (state, {
9001
+ builder.addCase(initializeConfig.pending, () => slice_initialState).addMatcher(isAnyOf(initializeApp.rejected, initializeConfig.rejected, setLocale.rejected, setVisibility.rejected, initializeVisibility.rejected, getConversation.rejected), (state, {
8800
9002
  payload
8801
9003
  }) => {
8802
9004
  state.error = payload;
@@ -9433,7 +9635,7 @@ const {
9433
9635
  } = storeSlice.actions;
9434
9636
  /* harmony default export */ const store_slice = (storeSlice.reducer);
9435
9637
  ;// CONCATENATED MODULE: ./src/javascripts/domains/config/slice.ts
9436
- var __rest = undefined && undefined.__rest || function (s, e) {
9638
+ var slice_rest = undefined && undefined.__rest || function (s, e) {
9437
9639
  var t = {};
9438
9640
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
9439
9641
  if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
@@ -9476,7 +9678,7 @@ const updateState = (state, config) => {
9476
9678
  {
9477
9679
  messages
9478
9680
  } = _a,
9479
- partialConfig = __rest(_a, ["messages"]);
9681
+ partialConfig = slice_rest(_a, ["messages"]);
9480
9682
  let newState = state;
9481
9683
  if (Object.keys(partialConfig).length > 0) {
9482
9684
  newState = Object.assign(Object.assign({}, newState), partialConfig);
@@ -9510,13 +9712,15 @@ const configSlice = createSlice({
9510
9712
  preChat,
9511
9713
  agentParticipant,
9512
9714
  userParticipant,
9513
- startChatIcon
9715
+ startChatIcon,
9716
+ locale
9514
9717
  }
9515
9718
  }) => {
9516
9719
  state.preChatEvents = preChat.map(payload => ({
9517
9720
  type: 'message',
9518
9721
  payload
9519
9722
  }));
9723
+ state.context.locale = locale;
9520
9724
  state.agentParticipant = agentParticipant;
9521
9725
  state.userParticipant = userParticipant;
9522
9726
  state.startChatIcon = startChatIcon;
@@ -9958,7 +10162,13 @@ const translationSlice = createSlice({
9958
10162
  const feature = (_a = payload === null || payload === void 0 ? void 0 : payload.features) === null || _a === void 0 ? void 0 : _a.translation;
9959
10163
  if (!feature) return;
9960
10164
  state.isAvailable = feature.enabled === true;
9961
- state.languages = feature.languages;
10165
+ state.languages = [...feature.languages].sort((a, b) => {
10166
+ if (a.locale === payload.locale) return -1;
10167
+ if (b.locale === payload.locale) return 1;
10168
+ return a.nativeName.localeCompare(b.nativeName, undefined, {
10169
+ sensitivity: 'base'
10170
+ });
10171
+ });
9962
10172
  }).addCase(setHistory, (state, {
9963
10173
  payload
9964
10174
  }) => {
@@ -11194,6 +11404,9 @@ function useInterrupt() {
11194
11404
 
11195
11405
 
11196
11406
 
11407
+
11408
+
11409
+
11197
11410
  function useSessionExpiredCommand() {
11198
11411
  const {
11199
11412
  meta: {
@@ -11201,13 +11414,35 @@ function useSessionExpiredCommand() {
11201
11414
  action
11202
11415
  }
11203
11416
  } = useInterrupt();
11417
+ const dispatch = useAppDispatch();
11204
11418
  const seamlyCommands = use_seamly_commands();
11205
11419
  const isExpiredError = (originalError === null || originalError === void 0 ? void 0 : originalError.name) === 'SeamlySessionExpiredError';
11420
+ const limit = (0,hooks_.useRef)(0);
11421
+ const limitTimer = (0,hooks_.useRef)(null);
11206
11422
  (0,hooks_.useEffect)(() => {
11207
11423
  if (isExpiredError && seamlyCommands[action]) {
11424
+ if (limit.current >= 10) {
11425
+ limitTimer.current = setTimeout(() => {
11426
+ limit.current = 0;
11427
+ }, 10000);
11428
+ const error = new SeamlyGeneralError();
11429
+ dispatch(setInterrupt({
11430
+ name: error.name,
11431
+ message: error.message,
11432
+ langKey: error.langKey,
11433
+ originalEvent: error.originalEvent,
11434
+ originalError: error.originalError,
11435
+ action: error.action
11436
+ }));
11437
+ return () => {};
11438
+ }
11439
+ limit.current += 1;
11208
11440
  seamlyCommands[action]();
11209
11441
  }
11210
- }, [action, seamlyCommands, isExpiredError]);
11442
+ return () => {
11443
+ if (limitTimer.current) clearTimeout(limitTimer.current);
11444
+ };
11445
+ }, [action, seamlyCommands, isExpiredError, dispatch]);
11211
11446
  }
11212
11447
  ;// CONCATENATED MODULE: ./src/javascripts/ui/hooks/use-seamly-chat.ts
11213
11448
  var use_seamly_chat_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
@@ -12035,7 +12270,7 @@ const EventParticipant = ({
12035
12270
  })
12036
12271
  }));
12037
12272
  }
12038
- if (showName) {
12273
+ if (showName && participantName) {
12039
12274
  authorInfo.push((0,jsx_runtime_namespaceObject.jsx)("span", {
12040
12275
  className: css_className('message__author-name'),
12041
12276
  children: participantName
@@ -12115,108 +12350,61 @@ function MessageContainer({
12115
12350
  });
12116
12351
  }
12117
12352
  /* harmony default export */ const message_container = (MessageContainer);
12118
- ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-component.js
12119
-
12353
+ ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-component.tsx
12120
12354
 
12121
12355
 
12122
12356
 
12123
12357
 
12124
12358
 
12125
- const CardComponent = ({
12126
- id,
12127
- action,
12128
- buttonText,
12129
- description,
12130
- hasFocus,
12131
- image,
12132
- title,
12133
- isCarouselItem
12134
- }) => {
12135
- const cardRef = (0,hooks_.useRef)(null);
12136
- const {
12137
- sendMessage,
12138
- sendAction,
12139
- emitEvent
12140
- } = use_seamly_commands();
12141
- const descriptionId = useGeneratedId();
12142
- const isMounted = (0,hooks_.useRef)();
12143
- const CardActionComponent = action.type === cardTypes.navigate ? 'a' : 'button';
12144
- const emitCardEvent = (0,hooks_.useCallback)(() => emitEvent(`action.${actionTypes.clickCard}`, {
12145
- type: actionTypes.clickCta,
12146
- originMessage: id,
12147
- action
12148
- }), [emitEvent, id, action]);
12149
- const handleClick = (0,hooks_.useCallback)(() => {
12150
- emitCardEvent();
12151
- if (action.type === cardTypes.ask) {
12152
- sendMessage({
12153
- body: action.ask
12154
- });
12155
- } else if (action.type === cardTypes.topic) {
12156
- const {
12157
- topic: name,
12158
- fallbackMessage
12159
- } = action;
12160
- sendAction({
12161
- type: actionTypes.setTopic,
12162
- body: {
12163
- name,
12164
- fallbackMessage
12359
+ const CardComponent = ({ id, action, buttonText, description, hasFocus, image, title, isCarouselItem, }) => {
12360
+ const cardRef = (0,hooks_.useRef)(null);
12361
+ const { sendMessage, sendAction, emitEvent } = use_seamly_commands();
12362
+ const descriptionId = useGeneratedId();
12363
+ const isMounted = (0,hooks_.useRef)(false);
12364
+ const CardActionComponent = action.type === cardTypes.navigate ? 'a' : 'button';
12365
+ const emitCardEvent = (0,hooks_.useCallback)(() => emitEvent(`action.${actionTypes.clickCard}`, {
12366
+ type: actionTypes.clickCta,
12367
+ originMessage: id,
12368
+ action,
12369
+ }), [emitEvent, id, action]);
12370
+ const handleClick = (0,hooks_.useCallback)(() => {
12371
+ emitCardEvent();
12372
+ if (action.type === cardTypes.ask) {
12373
+ sendMessage({ body: action.ask });
12165
12374
  }
12166
- });
12167
- }
12168
- }, [sendMessage, action, sendAction, emitCardEvent]);
12169
- const actionProps = (0,hooks_.useMemo)(() => action.type === cardTypes.navigate ? {
12170
- href: action.link,
12171
- rel: 'noopener noreferrer',
12172
- target: action.newTab ? '_blank' : '_self',
12173
- onClick: emitCardEvent
12174
- } : {
12175
- onClick: handleClick
12176
- }, [action, handleClick, emitCardEvent]);
12177
- (0,hooks_.useEffect)(() => {
12178
- if (isCarouselItem) {
12179
- if (hasFocus && isMounted.current) {
12180
- window.requestAnimationFrame(() => cardRef.current.focus());
12181
- } else {
12182
- cardRef.current.blur();
12183
- }
12184
- }
12185
- isMounted.current = true;
12186
- }, [hasFocus, isCarouselItem]);
12187
- return (0,jsx_runtime_namespaceObject.jsxs)("div", {
12188
- className: css_className('card__wrapper'),
12189
- id: id,
12190
- tabIndex: "-1" // set tabIndex of -1 so card can be focussed
12191
- ,
12192
- ref: cardRef,
12193
- children: [(0,jsx_runtime_namespaceObject.jsx)("img", {
12194
- className: css_className('card__image'),
12195
- src: image,
12196
- alt: ""
12197
- }), (0,jsx_runtime_namespaceObject.jsxs)("div", {
12198
- className: css_className('card__content'),
12199
- id: id,
12200
- children: [title && (0,jsx_runtime_namespaceObject.jsx)("h2", {
12201
- className: css_className('card__title'),
12202
- children: title
12203
- }), description && (0,jsx_runtime_namespaceObject.jsx)("div", {
12204
- className: css_className('card__description'),
12205
- dangerouslySetInnerHTML: {
12206
- __html: description
12375
+ else if (action.type === cardTypes.topic) {
12376
+ const { topic: name, fallbackMessage } = action;
12377
+ sendAction({
12378
+ type: actionTypes.setTopic,
12379
+ body: { name, fallbackMessage },
12380
+ });
12207
12381
  }
12208
- }), (0,jsx_runtime_namespaceObject.jsx)(CardActionComponent, {
12209
- tabIndex: isCarouselItem && !hasFocus ? '-1' : undefined // disable to prevent tabbing through cards
12210
- ,
12211
- className: css_className('button', 'button--primary'),
12212
- "aria-describedby": descriptionId,
12213
- ...actionProps,
12214
- children: buttonText
12215
- })]
12216
- })]
12217
- });
12382
+ }, [sendMessage, action, sendAction, emitCardEvent]);
12383
+ const actionProps = (0,hooks_.useMemo)(() => action.type === cardTypes.navigate
12384
+ ? {
12385
+ href: action.link,
12386
+ rel: 'noopener noreferrer',
12387
+ target: action.newTab ? '_blank' : '_self',
12388
+ onClick: emitCardEvent,
12389
+ }
12390
+ : {
12391
+ onClick: handleClick,
12392
+ }, [action, handleClick, emitCardEvent]);
12393
+ (0,hooks_.useEffect)(() => {
12394
+ if (isCarouselItem) {
12395
+ if (hasFocus && isMounted.current) {
12396
+ window.requestAnimationFrame(() => cardRef.current.focus());
12397
+ }
12398
+ else {
12399
+ cardRef.current.blur();
12400
+ }
12401
+ }
12402
+ isMounted.current = true;
12403
+ }, [hasFocus, isCarouselItem]);
12404
+ return ((0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('card__wrapper'), id: id, tabIndex: -1, ref: cardRef, children: [image ? ((0,jsx_runtime_namespaceObject.jsx)("img", { className: css_className('card__image'), src: image, alt: "" })) : null, (0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('card__content'), id: id, children: [title && (0,jsx_runtime_namespaceObject.jsx)("h2", { className: css_className('card__title'), children: title }), description && ((0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('card__description'), dangerouslySetInnerHTML: { __html: description } })), (0,jsx_runtime_namespaceObject.jsx)(CardActionComponent, Object.assign({ tabIndex: isCarouselItem && !hasFocus ? -1 : undefined, className: css_className('button', 'button--primary'), "aria-describedby": descriptionId }, actionProps, { children: buttonText }))] })] }));
12218
12405
  };
12219
12406
  /* harmony default export */ const card_component = (CardComponent);
12407
+
12220
12408
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-message.js
12221
12409
 
12222
12410
 
@@ -13236,7 +13424,7 @@ const TimeIndicator = ({
13236
13424
  /* harmony default export */ const time_indicator = (TimeIndicator);
13237
13425
  ;// CONCATENATED MODULE: ./node_modules/tabbable/dist/index.esm.js
13238
13426
  /*!
13239
- * tabbable 6.1.2
13427
+ * tabbable 6.2.0
13240
13428
  * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
13241
13429
  */
13242
13430
  // NOTE: separate `:not()` selectors has broader browser support than the newer
@@ -13416,7 +13604,27 @@ var getCandidatesIteratively = function getCandidatesIteratively(elements, inclu
13416
13604
  }
13417
13605
  return candidates;
13418
13606
  };
13419
- var getTabindex = function getTabindex(node, isScope) {
13607
+
13608
+ /**
13609
+ * @private
13610
+ * Determines if the node has an explicitly specified `tabindex` attribute.
13611
+ * @param {HTMLElement} node
13612
+ * @returns {boolean} True if so; false if not.
13613
+ */
13614
+ var hasTabIndex = function hasTabIndex(node) {
13615
+ return !isNaN(parseInt(node.getAttribute('tabindex'), 10));
13616
+ };
13617
+
13618
+ /**
13619
+ * Determine the tab index of a given node.
13620
+ * @param {HTMLElement} node
13621
+ * @returns {number} Tab order (negative, 0, or positive number).
13622
+ * @throws {Error} If `node` is falsy.
13623
+ */
13624
+ var getTabIndex = function getTabIndex(node) {
13625
+ if (!node) {
13626
+ throw new Error('No node provided');
13627
+ }
13420
13628
  if (node.tabIndex < 0) {
13421
13629
  // in Chrome, <details/>, <audio controls/> and <video controls/> elements get a default
13422
13630
  // `tabIndex` of -1 when the 'tabindex' attribute isn't specified in the DOM,
@@ -13425,16 +13633,28 @@ var getTabindex = function getTabindex(node, isScope) {
13425
13633
  // order, consider their tab index to be 0.
13426
13634
  // Also browsers do not return `tabIndex` correctly for contentEditable nodes;
13427
13635
  // so if they don't have a tabindex attribute specifically set, assume it's 0.
13428
- //
13429
- // isScope is positive for custom element with shadow root or slot that by default
13430
- // have tabIndex -1, but need to be sorted by document order in order for their
13431
- // content to be inserted in the correct position
13432
- if ((isScope || /^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || isContentEditable(node)) && isNaN(parseInt(node.getAttribute('tabindex'), 10))) {
13636
+ if ((/^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || isContentEditable(node)) && !hasTabIndex(node)) {
13433
13637
  return 0;
13434
13638
  }
13435
13639
  }
13436
13640
  return node.tabIndex;
13437
13641
  };
13642
+
13643
+ /**
13644
+ * Determine the tab index of a given node __for sort order purposes__.
13645
+ * @param {HTMLElement} node
13646
+ * @param {boolean} [isScope] True for a custom element with shadow root or slot that, by default,
13647
+ * has tabIndex -1, but needs to be sorted by document order in order for its content to be
13648
+ * inserted into the correct sort position.
13649
+ * @returns {number} Tab order (negative, 0, or positive number).
13650
+ */
13651
+ var getSortOrderTabIndex = function getSortOrderTabIndex(node, isScope) {
13652
+ var tabIndex = getTabIndex(node);
13653
+ if (tabIndex < 0 && isScope && !hasTabIndex(node)) {
13654
+ return 0;
13655
+ }
13656
+ return tabIndex;
13657
+ };
13438
13658
  var sortOrderedTabbables = function sortOrderedTabbables(a, b) {
13439
13659
  return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex;
13440
13660
  };
@@ -13677,7 +13897,7 @@ var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable(o
13677
13897
  return true;
13678
13898
  };
13679
13899
  var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable(options, node) {
13680
- if (isNonTabbableRadio(node) || getTabindex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) {
13900
+ if (isNonTabbableRadio(node) || getTabIndex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) {
13681
13901
  return false;
13682
13902
  }
13683
13903
  return true;
@@ -13702,7 +13922,7 @@ var sortByOrder = function sortByOrder(candidates) {
13702
13922
  candidates.forEach(function (item, i) {
13703
13923
  var isScope = !!item.scopeParent;
13704
13924
  var element = isScope ? item.scopeParent : item;
13705
- var candidateTabindex = getTabindex(element, isScope);
13925
+ var candidateTabindex = getSortOrderTabIndex(element, isScope);
13706
13926
  var elements = isScope ? sortByOrder(item.candidates) : element;
13707
13927
  if (candidateTabindex === 0) {
13708
13928
  isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element);
@@ -13721,32 +13941,32 @@ var sortByOrder = function sortByOrder(candidates) {
13721
13941
  return acc;
13722
13942
  }, []).concat(regularTabbables);
13723
13943
  };
13724
- var tabbable = function tabbable(el, options) {
13944
+ var tabbable = function tabbable(container, options) {
13725
13945
  options = options || {};
13726
13946
  var candidates;
13727
13947
  if (options.getShadowRoot) {
13728
- candidates = getCandidatesIteratively([el], options.includeContainer, {
13948
+ candidates = getCandidatesIteratively([container], options.includeContainer, {
13729
13949
  filter: isNodeMatchingSelectorTabbable.bind(null, options),
13730
13950
  flatten: false,
13731
13951
  getShadowRoot: options.getShadowRoot,
13732
13952
  shadowRootFilter: isValidShadowRootTabbable
13733
13953
  });
13734
13954
  } else {
13735
- candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
13955
+ candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
13736
13956
  }
13737
13957
  return sortByOrder(candidates);
13738
13958
  };
13739
- var focusable = function focusable(el, options) {
13959
+ var focusable = function focusable(container, options) {
13740
13960
  options = options || {};
13741
13961
  var candidates;
13742
13962
  if (options.getShadowRoot) {
13743
- candidates = getCandidatesIteratively([el], options.includeContainer, {
13963
+ candidates = getCandidatesIteratively([container], options.includeContainer, {
13744
13964
  filter: isNodeMatchingSelectorFocusable.bind(null, options),
13745
13965
  flatten: true,
13746
13966
  getShadowRoot: options.getShadowRoot
13747
13967
  });
13748
13968
  } else {
13749
- candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
13969
+ candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
13750
13970
  }
13751
13971
  return candidates;
13752
13972
  };
@@ -13777,7 +13997,7 @@ var isFocusable = function isFocusable(node, options) {
13777
13997
 
13778
13998
  ;// CONCATENATED MODULE: ./node_modules/focus-trap/dist/focus-trap.esm.js
13779
13999
  /*!
13780
- * focus-trap 7.4.3
14000
+ * focus-trap 7.5.2
13781
14001
  * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
13782
14002
  */
13783
14003
 
@@ -13863,10 +14083,10 @@ var isSelectableInput = function isSelectableInput(node) {
13863
14083
  return node.tagName && node.tagName.toLowerCase() === 'input' && typeof node.select === 'function';
13864
14084
  };
13865
14085
  var isEscapeEvent = function isEscapeEvent(e) {
13866
- return e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27;
14086
+ return (e === null || e === void 0 ? void 0 : e.key) === 'Escape' || (e === null || e === void 0 ? void 0 : e.key) === 'Esc' || (e === null || e === void 0 ? void 0 : e.keyCode) === 27;
13867
14087
  };
13868
14088
  var isTabEvent = function isTabEvent(e) {
13869
- return e.key === 'Tab' || e.keyCode === 9;
14089
+ return (e === null || e === void 0 ? void 0 : e.key) === 'Tab' || (e === null || e === void 0 ? void 0 : e.keyCode) === 9;
13870
14090
  };
13871
14091
 
13872
14092
  // checks for TAB by default
@@ -13950,8 +14170,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
13950
14170
  // container: HTMLElement,
13951
14171
  // tabbableNodes: Array<HTMLElement>, // empty if none
13952
14172
  // focusableNodes: Array<HTMLElement>, // empty if none
13953
- // firstTabbableNode: HTMLElement|null,
13954
- // lastTabbableNode: HTMLElement|null,
14173
+ // posTabIndexesFound: boolean,
14174
+ // firstTabbableNode: HTMLElement|undefined,
14175
+ // lastTabbableNode: HTMLElement|undefined,
14176
+ // firstDomTabbableNode: HTMLElement|undefined,
14177
+ // lastDomTabbableNode: HTMLElement|undefined,
13955
14178
  // nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined
13956
14179
  // }>}
13957
14180
  containerGroups: [],
@@ -13968,7 +14191,9 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
13968
14191
  paused: false,
13969
14192
  // timer ID for when delayInitialFocus is true and initial focus in this trap
13970
14193
  // has been delayed during activation
13971
- delayInitialFocusTimer: undefined
14194
+ delayInitialFocusTimer: undefined,
14195
+ // the most recent KeyboardEvent for the configured nav key (typically [SHIFT+]TAB), if any
14196
+ recentNavEvent: undefined
13972
14197
  };
13973
14198
  var trap; // eslint-disable-line prefer-const -- some private functions reference it, and its methods reference private functions, so we must declare here and define later
13974
14199
 
@@ -13987,7 +14212,9 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
13987
14212
  /**
13988
14213
  * Finds the index of the container that contains the element.
13989
14214
  * @param {HTMLElement} element
13990
- * @param {Event} [event]
14215
+ * @param {Event} [event] If available, and `element` isn't directly found in any container,
14216
+ * the event's composed path is used to see if includes any known trap containers in the
14217
+ * case where the element is inside a Shadow DOM.
13991
14218
  * @returns {number} Index of the container in either `state.containers` or
13992
14219
  * `state.containerGroups` (the order/length of these lists are the same); -1
13993
14220
  * if the element isn't found.
@@ -14082,14 +14309,41 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14082
14309
  var tabbableNodes = tabbable(container, config.tabbableOptions);
14083
14310
 
14084
14311
  // NOTE: if we have tabbable nodes, we must have focusable nodes; focusable nodes
14085
- // are a superset of tabbable nodes
14312
+ // are a superset of tabbable nodes since nodes with negative `tabindex` attributes
14313
+ // are focusable but not tabbable
14086
14314
  var focusableNodes = focusable(container, config.tabbableOptions);
14315
+ var firstTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[0] : undefined;
14316
+ var lastTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : undefined;
14317
+ var firstDomTabbableNode = focusableNodes.find(function (node) {
14318
+ return isTabbable(node);
14319
+ });
14320
+ var lastDomTabbableNode = focusableNodes.slice().reverse().find(function (node) {
14321
+ return isTabbable(node);
14322
+ });
14323
+ var posTabIndexesFound = !!tabbableNodes.find(function (node) {
14324
+ return getTabIndex(node) > 0;
14325
+ });
14087
14326
  return {
14088
14327
  container: container,
14089
14328
  tabbableNodes: tabbableNodes,
14090
14329
  focusableNodes: focusableNodes,
14091
- firstTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[0] : null,
14092
- lastTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : null,
14330
+ /** True if at least one node with positive `tabindex` was found in this container. */
14331
+ posTabIndexesFound: posTabIndexesFound,
14332
+ /** First tabbable node in container, __tabindex__ order; `undefined` if none. */
14333
+ firstTabbableNode: firstTabbableNode,
14334
+ /** Last tabbable node in container, __tabindex__ order; `undefined` if none. */
14335
+ lastTabbableNode: lastTabbableNode,
14336
+ // NOTE: DOM order is NOT NECESSARILY "document position" order, but figuring that out
14337
+ // would require more than just https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition
14338
+ // because that API doesn't work with Shadow DOM as well as it should (@see
14339
+ // https://github.com/whatwg/dom/issues/320) and since this first/last is only needed, so far,
14340
+ // to address an edge case related to positive tabindex support, this seems like a much easier,
14341
+ // "close enough most of the time" alternative for positive tabindexes which should generally
14342
+ // be avoided anyway...
14343
+ /** First tabbable node in container, __DOM__ order; `undefined` if none. */
14344
+ firstDomTabbableNode: firstDomTabbableNode,
14345
+ /** Last tabbable node in container, __DOM__ order; `undefined` if none. */
14346
+ lastDomTabbableNode: lastDomTabbableNode,
14093
14347
  /**
14094
14348
  * Finds the __tabbable__ node that follows the given node in the specified direction,
14095
14349
  * in this container, if any.
@@ -14100,30 +14354,24 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14100
14354
  */
14101
14355
  nextTabbableNode: function nextTabbableNode(node) {
14102
14356
  var forward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
14103
- // NOTE: If tabindex is positive (in order to manipulate the tab order separate
14104
- // from the DOM order), this __will not work__ because the list of focusableNodes,
14105
- // while it contains tabbable nodes, does not sort its nodes in any order other
14106
- // than DOM order, because it can't: Where would you place focusable (but not
14107
- // tabbable) nodes in that order? They have no order, because they aren't tabbale...
14108
- // Support for positive tabindex is already broken and hard to manage (possibly
14109
- // not supportable, TBD), so this isn't going to make things worse than they
14110
- // already are, and at least makes things better for the majority of cases where
14111
- // tabindex is either 0/unset or negative.
14112
- // FYI, positive tabindex issue: https://github.com/focus-trap/focus-trap/issues/375
14113
- var nodeIdx = focusableNodes.findIndex(function (n) {
14114
- return n === node;
14115
- });
14357
+ var nodeIdx = tabbableNodes.indexOf(node);
14116
14358
  if (nodeIdx < 0) {
14117
- return undefined;
14118
- }
14119
- if (forward) {
14120
- return focusableNodes.slice(nodeIdx + 1).find(function (n) {
14121
- return isTabbable(n, config.tabbableOptions);
14359
+ // either not tabbable nor focusable, or was focused but not tabbable (negative tabindex):
14360
+ // since `node` should at least have been focusable, we assume that's the case and mimic
14361
+ // what browsers do, which is set focus to the next node in __document position order__,
14362
+ // regardless of positive tabindexes, if any -- and for reasons explained in the NOTE
14363
+ // above related to `firstDomTabbable` and `lastDomTabbable` properties, we fall back to
14364
+ // basic DOM order
14365
+ if (forward) {
14366
+ return focusableNodes.slice(focusableNodes.indexOf(node) + 1).find(function (el) {
14367
+ return isTabbable(el);
14368
+ });
14369
+ }
14370
+ return focusableNodes.slice(0, focusableNodes.indexOf(node)).reverse().find(function (el) {
14371
+ return isTabbable(el);
14122
14372
  });
14123
14373
  }
14124
- return focusableNodes.slice(0, nodeIdx).reverse().find(function (n) {
14125
- return isTabbable(n, config.tabbableOptions);
14126
- });
14374
+ return tabbableNodes[nodeIdx + (forward ? 1 : -1)];
14127
14375
  }
14128
14376
  };
14129
14377
  });
@@ -14136,6 +14384,19 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14136
14384
  ) {
14137
14385
  throw new Error('Your focus-trap must have at least one container with at least one tabbable node in it at all times');
14138
14386
  }
14387
+
14388
+ // NOTE: Positive tabindexes are only properly supported in single-container traps because
14389
+ // doing it across multiple containers where tabindexes could be all over the place
14390
+ // would require Tabbable to support multiple containers, would require additional
14391
+ // specialized Shadow DOM support, and would require Tabbable's multi-container support
14392
+ // to look at those containers in document position order rather than user-provided
14393
+ // order (as they are treated in Focus-trap, for legacy reasons). See discussion on
14394
+ // https://github.com/focus-trap/focus-trap/issues/375 for more details.
14395
+ if (state.containerGroups.find(function (g) {
14396
+ return g.posTabIndexesFound;
14397
+ }) && state.containerGroups.length > 1) {
14398
+ throw new Error("At least one node with a positive tabindex was found in one of your focus-trap's multiple containers. Positive tabindexes are only supported in single-container focus-traps.");
14399
+ }
14139
14400
  };
14140
14401
  var tryFocus = function tryFocus(node) {
14141
14402
  if (node === false) {
@@ -14151,6 +14412,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14151
14412
  node.focus({
14152
14413
  preventScroll: !!config.preventScroll
14153
14414
  });
14415
+ // NOTE: focus() API does not trigger focusIn event so set MRU node manually
14154
14416
  state.mostRecentlyFocusedNode = node;
14155
14417
  if (isSelectableInput(node)) {
14156
14418
  node.select();
@@ -14161,64 +14423,23 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14161
14423
  return node ? node : node === false ? false : previousActiveElement;
14162
14424
  };
14163
14425
 
14164
- // This needs to be done on mousedown and touchstart instead of click
14165
- // so that it precedes the focus event.
14166
- var checkPointerDown = function checkPointerDown(e) {
14167
- var target = getActualTarget(e);
14168
- if (findContainerIndex(target, e) >= 0) {
14169
- // allow the click since it ocurred inside the trap
14170
- return;
14171
- }
14172
- if (valueOrHandler(config.clickOutsideDeactivates, e)) {
14173
- // immediately deactivate the trap
14174
- trap.deactivate({
14175
- // NOTE: by setting `returnFocus: false`, deactivate() will do nothing,
14176
- // which will result in the outside click setting focus to the node
14177
- // that was clicked (and if not focusable, to "nothing"); by setting
14178
- // `returnFocus: true`, we'll attempt to re-focus the node originally-focused
14179
- // on activation (or the configured `setReturnFocus` node), whether the
14180
- // outside click was on a focusable node or not
14181
- returnFocus: config.returnFocusOnDeactivate
14182
- });
14183
- return;
14184
- }
14185
-
14186
- // This is needed for mobile devices.
14187
- // (If we'll only let `click` events through,
14188
- // then on mobile they will be blocked anyways if `touchstart` is blocked.)
14189
- if (valueOrHandler(config.allowOutsideClick, e)) {
14190
- // allow the click outside the trap to take place
14191
- return;
14192
- }
14193
-
14194
- // otherwise, prevent the click
14195
- e.preventDefault();
14196
- };
14197
-
14198
- // In case focus escapes the trap for some strange reason, pull it back in.
14199
- var checkFocusIn = function checkFocusIn(e) {
14200
- var target = getActualTarget(e);
14201
- var targetContained = findContainerIndex(target, e) >= 0;
14202
-
14203
- // In Firefox when you Tab out of an iframe the Document is briefly focused.
14204
- if (targetContained || target instanceof Document) {
14205
- if (targetContained) {
14206
- state.mostRecentlyFocusedNode = target;
14207
- }
14208
- } else {
14209
- // escaped! pull it back in to where it just left
14210
- e.stopImmediatePropagation();
14211
- tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
14212
- }
14213
- };
14214
-
14215
- // Hijack key nav events on the first and last focusable nodes of the trap,
14216
- // in order to prevent focus from escaping. If it escapes for even a
14217
- // moment it can end up scrolling the page and causing confusion so we
14218
- // kind of need to capture the action at the keydown phase.
14219
- var checkKeyNav = function checkKeyNav(event) {
14220
- var isBackward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
14221
- var target = getActualTarget(event);
14426
+ /**
14427
+ * Finds the next node (in either direction) where focus should move according to a
14428
+ * keyboard focus-in event.
14429
+ * @param {Object} params
14430
+ * @param {Node} [params.target] Known target __from which__ to navigate, if any.
14431
+ * @param {KeyboardEvent|FocusEvent} [params.event] Event to use if `target` isn't known (event
14432
+ * will be used to determine the `target`). Ignored if `target` is specified.
14433
+ * @param {boolean} [params.isBackward] True if focus should move backward.
14434
+ * @returns {Node|undefined} The next node, or `undefined` if a next node couldn't be
14435
+ * determined given the current state of the trap.
14436
+ */
14437
+ var findNextNavNode = function findNextNavNode(_ref2) {
14438
+ var target = _ref2.target,
14439
+ event = _ref2.event,
14440
+ _ref2$isBackward = _ref2.isBackward,
14441
+ isBackward = _ref2$isBackward === void 0 ? false : _ref2$isBackward;
14442
+ target = target || getActualTarget(event);
14222
14443
  updateTabbableNodes();
14223
14444
  var destinationNode = null;
14224
14445
  if (state.tabbableGroups.length > 0) {
@@ -14241,8 +14462,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14241
14462
  // REVERSE
14242
14463
 
14243
14464
  // is the target the first tabbable node in a group?
14244
- var startOfGroupIndex = findIndex(state.tabbableGroups, function (_ref2) {
14245
- var firstTabbableNode = _ref2.firstTabbableNode;
14465
+ var startOfGroupIndex = findIndex(state.tabbableGroups, function (_ref3) {
14466
+ var firstTabbableNode = _ref3.firstTabbableNode;
14246
14467
  return target === firstTabbableNode;
14247
14468
  });
14248
14469
  if (startOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) {
@@ -14260,7 +14481,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14260
14481
  // the LAST group if it's the first tabbable node of the FIRST group)
14261
14482
  var destinationGroupIndex = startOfGroupIndex === 0 ? state.tabbableGroups.length - 1 : startOfGroupIndex - 1;
14262
14483
  var destinationGroup = state.tabbableGroups[destinationGroupIndex];
14263
- destinationNode = destinationGroup.lastTabbableNode;
14484
+ destinationNode = getTabIndex(target) >= 0 ? destinationGroup.lastTabbableNode : destinationGroup.lastDomTabbableNode;
14264
14485
  } else if (!isTabEvent(event)) {
14265
14486
  // user must have customized the nav keys so we have to move focus manually _within_
14266
14487
  // the active group: do this based on the order determined by tabbable()
@@ -14270,8 +14491,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14270
14491
  // FORWARD
14271
14492
 
14272
14493
  // is the target the last tabbable node in a group?
14273
- var lastOfGroupIndex = findIndex(state.tabbableGroups, function (_ref3) {
14274
- var lastTabbableNode = _ref3.lastTabbableNode;
14494
+ var lastOfGroupIndex = findIndex(state.tabbableGroups, function (_ref4) {
14495
+ var lastTabbableNode = _ref4.lastTabbableNode;
14275
14496
  return target === lastTabbableNode;
14276
14497
  });
14277
14498
  if (lastOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) {
@@ -14289,7 +14510,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14289
14510
  // group if it's the last tabbable node of the LAST group)
14290
14511
  var _destinationGroupIndex = lastOfGroupIndex === state.tabbableGroups.length - 1 ? 0 : lastOfGroupIndex + 1;
14291
14512
  var _destinationGroup = state.tabbableGroups[_destinationGroupIndex];
14292
- destinationNode = _destinationGroup.firstTabbableNode;
14513
+ destinationNode = getTabIndex(target) >= 0 ? _destinationGroup.firstTabbableNode : _destinationGroup.firstDomTabbableNode;
14293
14514
  } else if (!isTabEvent(event)) {
14294
14515
  // user must have customized the nav keys so we have to move focus manually _within_
14295
14516
  // the active group: do this based on the order determined by tabbable()
@@ -14301,6 +14522,153 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
14301
14522
  // NOTE: the fallbackFocus option does not support returning false to opt-out
14302
14523
  destinationNode = getNodeForOption('fallbackFocus');
14303
14524
  }
14525
+ return destinationNode;
14526
+ };
14527
+
14528
+ // This needs to be done on mousedown and touchstart instead of click
14529
+ // so that it precedes the focus event.
14530
+ var checkPointerDown = function checkPointerDown(e) {
14531
+ var target = getActualTarget(e);
14532
+ if (findContainerIndex(target, e) >= 0) {
14533
+ // allow the click since it ocurred inside the trap
14534
+ return;
14535
+ }
14536
+ if (valueOrHandler(config.clickOutsideDeactivates, e)) {
14537
+ // immediately deactivate the trap
14538
+ trap.deactivate({
14539
+ // NOTE: by setting `returnFocus: false`, deactivate() will do nothing,
14540
+ // which will result in the outside click setting focus to the node
14541
+ // that was clicked (and if not focusable, to "nothing"); by setting
14542
+ // `returnFocus: true`, we'll attempt to re-focus the node originally-focused
14543
+ // on activation (or the configured `setReturnFocus` node), whether the
14544
+ // outside click was on a focusable node or not
14545
+ returnFocus: config.returnFocusOnDeactivate
14546
+ });
14547
+ return;
14548
+ }
14549
+
14550
+ // This is needed for mobile devices.
14551
+ // (If we'll only let `click` events through,
14552
+ // then on mobile they will be blocked anyways if `touchstart` is blocked.)
14553
+ if (valueOrHandler(config.allowOutsideClick, e)) {
14554
+ // allow the click outside the trap to take place
14555
+ return;
14556
+ }
14557
+
14558
+ // otherwise, prevent the click
14559
+ e.preventDefault();
14560
+ };
14561
+
14562
+ // In case focus escapes the trap for some strange reason, pull it back in.
14563
+ // NOTE: the focusIn event is NOT cancelable, so if focus escapes, it may cause unexpected
14564
+ // scrolling if the node that got focused was out of view; there's nothing we can do to
14565
+ // prevent that from happening by the time we discover that focus escaped
14566
+ var checkFocusIn = function checkFocusIn(event) {
14567
+ var target = getActualTarget(event);
14568
+ var targetContained = findContainerIndex(target, event) >= 0;
14569
+
14570
+ // In Firefox when you Tab out of an iframe the Document is briefly focused.
14571
+ if (targetContained || target instanceof Document) {
14572
+ if (targetContained) {
14573
+ state.mostRecentlyFocusedNode = target;
14574
+ }
14575
+ } else {
14576
+ // escaped! pull it back in to where it just left
14577
+ event.stopImmediatePropagation();
14578
+
14579
+ // focus will escape if the MRU node had a positive tab index and user tried to nav forward;
14580
+ // it will also escape if the MRU node had a 0 tab index and user tried to nav backward
14581
+ // toward a node with a positive tab index
14582
+ var nextNode; // next node to focus, if we find one
14583
+ var navAcrossContainers = true;
14584
+ if (state.mostRecentlyFocusedNode) {
14585
+ if (getTabIndex(state.mostRecentlyFocusedNode) > 0) {
14586
+ // MRU container index must be >=0 otherwise we wouldn't have it as an MRU node...
14587
+ var mruContainerIdx = findContainerIndex(state.mostRecentlyFocusedNode);
14588
+ // there MAY not be any tabbable nodes in the container if there are at least 2 containers
14589
+ // and the MRU node is focusable but not tabbable (focus-trap requires at least 1 container
14590
+ // with at least one tabbable node in order to function, so this could be the other container
14591
+ // with nothing tabbable in it)
14592
+ var tabbableNodes = state.containerGroups[mruContainerIdx].tabbableNodes;
14593
+ if (tabbableNodes.length > 0) {
14594
+ // MRU tab index MAY not be found if the MRU node is focusable but not tabbable
14595
+ var mruTabIdx = tabbableNodes.findIndex(function (node) {
14596
+ return node === state.mostRecentlyFocusedNode;
14597
+ });
14598
+ if (mruTabIdx >= 0) {
14599
+ if (config.isKeyForward(state.recentNavEvent)) {
14600
+ if (mruTabIdx + 1 < tabbableNodes.length) {
14601
+ nextNode = tabbableNodes[mruTabIdx + 1];
14602
+ navAcrossContainers = false;
14603
+ }
14604
+ // else, don't wrap within the container as focus should move to next/previous
14605
+ // container
14606
+ } else {
14607
+ if (mruTabIdx - 1 >= 0) {
14608
+ nextNode = tabbableNodes[mruTabIdx - 1];
14609
+ navAcrossContainers = false;
14610
+ }
14611
+ // else, don't wrap within the container as focus should move to next/previous
14612
+ // container
14613
+ }
14614
+ // else, don't find in container order without considering direction too
14615
+ }
14616
+ }
14617
+ // else, no tabbable nodes in that container (which means we must have at least one other
14618
+ // container with at least one tabbable node in it, otherwise focus-trap would've thrown
14619
+ // an error the last time updateTabbableNodes() was run): find next node among all known
14620
+ // containers
14621
+ } else {
14622
+ // check to see if there's at least one tabbable node with a positive tab index inside
14623
+ // the trap because focus seems to escape when navigating backward from a tabbable node
14624
+ // with tabindex=0 when this is the case (instead of wrapping to the tabbable node with
14625
+ // the greatest positive tab index like it should)
14626
+ if (!state.containerGroups.some(function (g) {
14627
+ return g.tabbableNodes.some(function (n) {
14628
+ return getTabIndex(n) > 0;
14629
+ });
14630
+ })) {
14631
+ // no containers with tabbable nodes with positive tab indexes which means the focus
14632
+ // escaped for some other reason and we should just execute the fallback to the
14633
+ // MRU node or initial focus node, if any
14634
+ navAcrossContainers = false;
14635
+ }
14636
+ }
14637
+ } else {
14638
+ // no MRU node means we're likely in some initial condition when the trap has just
14639
+ // been activated and initial focus hasn't been given yet, in which case we should
14640
+ // fall through to trying to focus the initial focus node, which is what should
14641
+ // happen below at this point in the logic
14642
+ navAcrossContainers = false;
14643
+ }
14644
+ if (navAcrossContainers) {
14645
+ nextNode = findNextNavNode({
14646
+ // move FROM the MRU node, not event-related node (which will be the node that is
14647
+ // outside the trap causing the focus escape we're trying to fix)
14648
+ target: state.mostRecentlyFocusedNode,
14649
+ isBackward: config.isKeyBackward(state.recentNavEvent)
14650
+ });
14651
+ }
14652
+ if (nextNode) {
14653
+ tryFocus(nextNode);
14654
+ } else {
14655
+ tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
14656
+ }
14657
+ }
14658
+ state.recentNavEvent = undefined; // clear
14659
+ };
14660
+
14661
+ // Hijack key nav events on the first and last focusable nodes of the trap,
14662
+ // in order to prevent focus from escaping. If it escapes for even a
14663
+ // moment it can end up scrolling the page and causing confusion so we
14664
+ // kind of need to capture the action at the keydown phase.
14665
+ var checkKeyNav = function checkKeyNav(event) {
14666
+ var isBackward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
14667
+ state.recentNavEvent = event;
14668
+ var destinationNode = findNextNavNode({
14669
+ event: event,
14670
+ isBackward: isBackward
14671
+ });
14304
14672
  if (destinationNode) {
14305
14673
  if (isTabEvent(event)) {
14306
14674
  // since tab natively moves focus, we wouldn't have a destination node unless we
@@ -15187,11 +15555,38 @@ const SeamlyActivityMonitor = ({ children }) => {
15187
15555
  // It is important to use keyUp here as focus may be set from outside the
15188
15556
  // chat container via keyboard. In this case the keyDown handler would not
15189
15557
  // be fired inside the container on the initial focus event.
15190
- return ((0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('activity-monitor'), tabIndex: -1, onMouseDown: onActivityHandler, onKeyUp: onActivityHandler, onTouchStart: onActivityHandler, onMouseMove: onActivityHandler, onWheel: onActivityHandler, onPointerDown: onActivityHandler, onPointerMove: onActivityHandler }, { children: (0,jsx_runtime_namespaceObject.jsx)(seamly_activity_event_context.Provider, Object.assign({ value: onActivityHandler }, { children: children })) })));
15558
+ return ((0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('activity-monitor'), tabIndex: -1, onMouseDown: onActivityHandler, onKeyUp: onActivityHandler, onTouchStart: onActivityHandler, onMouseMove: onActivityHandler, onWheel: onActivityHandler, onPointerDown: onActivityHandler, onPointerMove: onActivityHandler, children: (0,jsx_runtime_namespaceObject.jsx)(seamly_activity_event_context.Provider, { value: onActivityHandler, children: children }) }));
15191
15559
  };
15192
15560
  /* harmony default export */ const seamly_activity_monitor = (SeamlyActivityMonitor);
15193
15561
 
15194
15562
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/core/seamly-event-subscriber.ts
15563
+ var seamly_event_subscriber_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
15564
+ function adopt(value) {
15565
+ return value instanceof P ? value : new P(function (resolve) {
15566
+ resolve(value);
15567
+ });
15568
+ }
15569
+ return new (P || (P = Promise))(function (resolve, reject) {
15570
+ function fulfilled(value) {
15571
+ try {
15572
+ step(generator.next(value));
15573
+ } catch (e) {
15574
+ reject(e);
15575
+ }
15576
+ }
15577
+ function rejected(value) {
15578
+ try {
15579
+ step(generator["throw"](value));
15580
+ } catch (e) {
15581
+ reject(e);
15582
+ }
15583
+ }
15584
+ function step(result) {
15585
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
15586
+ }
15587
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
15588
+ });
15589
+ };
15195
15590
  var seamly_event_subscriber_rest = undefined && undefined.__rest || function (s, e) {
15196
15591
  var t = {};
15197
15592
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
@@ -15212,13 +15607,13 @@ var seamly_event_subscriber_rest = undefined && undefined.__rest || function (s,
15212
15607
 
15213
15608
 
15214
15609
 
15610
+
15215
15611
  const EMITTABLE_MESSAGE_TYPES = ['text', 'choice_prompt', 'image', 'video'];
15216
15612
  const SeamlyEventSubscriber = () => {
15217
15613
  const api = useSeamlyApiContext();
15218
15614
  const syncChannelRef = (0,hooks_.useRef)();
15219
15615
  const messageChannelRef = (0,hooks_.useRef)();
15220
- const dispatch = useDispatch();
15221
- const events = useEvents();
15616
+ const dispatch = useAppDispatch();
15222
15617
  const eventBus = (0,hooks_.useContext)(SeamlyEventBusContext);
15223
15618
  const prevEmittedEventId = (0,hooks_.useRef)(null);
15224
15619
  const {
@@ -15463,31 +15858,19 @@ const SeamlyEventSubscriber = () => {
15463
15858
  if (syncChannelRef.current) {
15464
15859
  (_a = api.conversation.channel) === null || _a === void 0 ? void 0 : _a.off('sync', syncChannelRef.current);
15465
15860
  }
15466
- syncChannelRef.current = api.conversation.channel.on('sync', payload => {
15467
- var _a;
15468
- const lastEvent = events[events.length - 1];
15469
- const payloadLastEventId = (_a = payload === null || payload === void 0 ? void 0 : payload.lastEvent) === null || _a === void 0 ? void 0 : _a.id;
15470
- if (lastEvent && payloadLastEventId === lastEvent.payload.id) {
15471
- return payload;
15472
- }
15473
- return api.getConversation().then(history => {
15861
+ syncChannelRef.current = api.conversation.channel.on('sync', payload => seamly_event_subscriber_awaiter(void 0, void 0, void 0, function* () {
15862
+ try {
15863
+ const history = yield dispatch(getConversation(payload)).unwrap();
15474
15864
  if (!history) return;
15475
15865
  dispatch(setHistory(history));
15476
- }).catch(error => {
15477
- dispatch(setInterrupt({
15478
- name: error === null || error === void 0 ? void 0 : error.name,
15479
- message: error === null || error === void 0 ? void 0 : error.message,
15480
- langKey: error === null || error === void 0 ? void 0 : error.langKey,
15481
- action: error === null || error === void 0 ? void 0 : error.action,
15482
- originalEvent: error === null || error === void 0 ? void 0 : error.originalEvent,
15483
- originalError: error === null || error === void 0 ? void 0 : error.originalError
15484
- }));
15485
- });
15486
- });
15866
+ } catch (_e) {
15867
+ // nothing to do, the error is handled in the thunk
15868
+ }
15869
+ }));
15487
15870
  return true;
15488
15871
  });
15489
15872
  }
15490
- }, [api, api.connectionInfo, api.conversation.channel, events, dispatch]);
15873
+ }, [api, api.connectionInfo, api.conversation.channel, dispatch]);
15491
15874
  return null;
15492
15875
  };
15493
15876
  /* harmony default export */ const seamly_event_subscriber = (SeamlyEventSubscriber);
@@ -15594,7 +15977,7 @@ const SeamlyFileUpload = ({ children }) => {
15594
15977
  uploadHandle,
15595
15978
  }));
15596
15979
  }, [addImageToSessionStorage, addUploadBubble, api, dispatch, t]);
15597
- return ((0,jsx_runtime_namespaceObject.jsx)(seamly_file_upload_context.Provider, Object.assign({ value: onUploadFileHandler }, { children: children })));
15980
+ return ((0,jsx_runtime_namespaceObject.jsx)(seamly_file_upload_context.Provider, { value: onUploadFileHandler, children: children }));
15598
15981
  };
15599
15982
  /* harmony default export */ const seamly_file_upload = (SeamlyFileUpload);
15600
15983
 
@@ -15985,7 +16368,7 @@ const SeamlyCore = ({ store, children, eventBus, api }) => {
15985
16368
  (0,hooks_.useErrorBoundary)((error) => {
15986
16369
  store.dispatch(catchError(error));
15987
16370
  });
15988
- return ((0,jsx_runtime_namespaceObject.jsx)(components_Provider, Object.assign({ store: store }, { children: (0,jsx_runtime_namespaceObject.jsx)(SeamlyEventBusContext.Provider, Object.assign({ value: eventBus }, { children: (0,jsx_runtime_namespaceObject.jsx)(SeamlyApiContext.Provider, Object.assign({ value: api }, { children: (0,jsx_runtime_namespaceObject.jsx)(seamly_live_region, { children: (0,jsx_runtime_namespaceObject.jsx)(seamly_chat, { children: (0,jsx_runtime_namespaceObject.jsxs)(component_filter, { children: [(0,jsx_runtime_namespaceObject.jsx)(seamly_initializer, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_event_subscriber, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_read_state, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_new_notifications, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_idle_detach_counter, {}), (0,jsx_runtime_namespaceObject.jsxs)(seamly_activity_monitor, { children: [(0,jsx_runtime_namespaceObject.jsx)(seamly_instance_functions_loader, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_file_upload, { children: children })] })] }) }) }) })) })) })));
16371
+ return ((0,jsx_runtime_namespaceObject.jsx)(components_Provider, { store: store, children: (0,jsx_runtime_namespaceObject.jsx)(SeamlyEventBusContext.Provider, { value: eventBus, children: (0,jsx_runtime_namespaceObject.jsx)(SeamlyApiContext.Provider, { value: api, children: (0,jsx_runtime_namespaceObject.jsx)(seamly_live_region, { children: (0,jsx_runtime_namespaceObject.jsx)(seamly_chat, { children: (0,jsx_runtime_namespaceObject.jsxs)(component_filter, { children: [(0,jsx_runtime_namespaceObject.jsx)(seamly_initializer, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_event_subscriber, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_read_state, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_new_notifications, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_idle_detach_counter, {}), (0,jsx_runtime_namespaceObject.jsxs)(seamly_activity_monitor, { children: [(0,jsx_runtime_namespaceObject.jsx)(seamly_instance_functions_loader, {}), (0,jsx_runtime_namespaceObject.jsx)(seamly_file_upload, { children: children })] })] }) }) }) }) }) }));
15989
16372
  };
15990
16373
  /* harmony default export */ const seamly_core = (SeamlyCore);
15991
16374
 
@@ -16046,9 +16429,9 @@ const useDebounce = (value, delay = 20) => {
16046
16429
  const getState = ({
16047
16430
  forms
16048
16431
  }) => forms;
16049
- const getFormById = es_createSelector(getState, (_, {
16432
+ const getFormById = es_createSelector([getState, (_, {
16050
16433
  formId
16051
- }) => formId, (forms, formId) => forms[formId]);
16434
+ }) => formId], (forms, formId) => forms[formId]);
16052
16435
  const getFormControlsByFormId = es_createSelector(getFormById, form => (form === null || form === void 0 ? void 0 : form.controls) || {});
16053
16436
  const getFormValuesByFormId = es_createSelector(getFormControlsByFormId, controls => {
16054
16437
  const valuesObj = {};
@@ -16059,15 +16442,15 @@ const getFormValuesByFormId = es_createSelector(getFormControlsByFormId, control
16059
16442
  });
16060
16443
  return valuesObj;
16061
16444
  });
16062
- const getControlValueByName = es_createSelector(getFormControlsByFormId, (_, {
16445
+ const getControlValueByName = es_createSelector([getFormControlsByFormId, (_, {
16063
16446
  name
16064
- }) => name, (controls, name) => {
16447
+ }) => name], (controls, name) => {
16065
16448
  var _a;
16066
16449
  return (_a = controls[name]) === null || _a === void 0 ? void 0 : _a.value;
16067
16450
  });
16068
- const getControlTouchedByName = es_createSelector(getFormControlsByFormId, (_, {
16451
+ const getControlTouchedByName = es_createSelector([getFormControlsByFormId, (_, {
16069
16452
  name
16070
- }) => name, (controls, name) => {
16453
+ }) => name], (controls, name) => {
16071
16454
  var _a;
16072
16455
  return (_a = controls[name]) === null || _a === void 0 ? void 0 : _a.touched;
16073
16456
  });
@@ -16262,7 +16645,7 @@ const useEntryTextTranslation = controlName => {
16262
16645
  text: (text === null || text === void 0 ? void 0 : text.label) || t('input.inputLabelText'),
16263
16646
  limit: !(text === null || text === void 0 ? void 0 : text.label) && hasCharacterLimit ? characterLimit : null
16264
16647
  }), [t, hasCharacterLimit, characterLimit, text === null || text === void 0 ? void 0 : text.label]);
16265
- const labelClass = (0,hooks_.useMemo)(() => (text === null || text === void 0 ? void 0 : text.label) ? 'input__label' : 'visually-hidden', [text === null || text === void 0 ? void 0 : text.label]);
16648
+ const labelClass = (0,hooks_.useMemo)(() => (text === null || text === void 0 ? void 0 : text.label) ? 'label' : 'visually-hidden', [text === null || text === void 0 ? void 0 : text.label]);
16266
16649
  return {
16267
16650
  placeholder,
16268
16651
  label,
@@ -16307,14 +16690,14 @@ function AbortTransactionButton() {
16307
16690
  });
16308
16691
  clearEntryAbortTransaction();
16309
16692
  };
16310
- return ((0,jsx_runtime_namespaceObject.jsx)("li", Object.assign({ className: css_className([
16693
+ return ((0,jsx_runtime_namespaceObject.jsx)("li", { className: css_className([
16311
16694
  'cvco-conversation__item',
16312
16695
  'cvco-conversation__item--abort-transaction',
16313
- ]) }, { children: (0,jsx_runtime_namespaceObject.jsx)("button", Object.assign({ className: css_className([
16696
+ ]), children: (0,jsx_runtime_namespaceObject.jsx)("button", { className: css_className([
16314
16697
  'button',
16315
16698
  'button--secondary',
16316
16699
  'abort-transaction__button',
16317
- ]), type: "button", onClick: handleAbortTransaction }, { children: abortTransaction.label })) })));
16700
+ ]), type: "button", onClick: handleAbortTransaction, children: abortTransaction.label }) }));
16318
16701
  }
16319
16702
 
16320
16703
  ;// CONCATENATED MODULE: external "preact/compat"
@@ -16389,7 +16772,7 @@ const Event = ({ event, newParticipant }) => {
16389
16772
  if (newParticipant) {
16390
16773
  classNames.push('conversation__item--new-participant');
16391
16774
  }
16392
- return ((0,jsx_runtime_namespaceObject.jsxs)("li", Object.assign({ className: css_className(classNames), ref: containerRef }, { children: [event.timeIndicator && (0,jsx_runtime_namespaceObject.jsx)(time_indicator, { event: event }), (0,jsx_runtime_namespaceObject.jsx)(Component, Object.assign({ event: event }, { children: (0,jsx_runtime_namespaceObject.jsx)(SubComponent, { event: event }) }))] })));
16775
+ return ((0,jsx_runtime_namespaceObject.jsxs)("li", { className: css_className(classNames), ref: containerRef, children: [event.timeIndicator && (0,jsx_runtime_namespaceObject.jsx)(time_indicator, { event: event }), (0,jsx_runtime_namespaceObject.jsx)(Component, { event: event, children: (0,jsx_runtime_namespaceObject.jsx)(SubComponent, { event: event }) })] }));
16393
16776
  };
16394
16777
  /* harmony default export */ const event_event = (Event);
16395
16778
 
@@ -16474,7 +16857,7 @@ const Conversation = () => {
16474
16857
  e.preventDefault();
16475
16858
  focusSkiplinkTarget();
16476
16859
  };
16477
- return ((0,jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, { children: [isOpen && ((0,jsx_runtime_namespaceObject.jsx)("a", Object.assign({ className: css_className('skip-link'), href: `#${skiplinkTargetId}`, onClick: onClickHandler }, { children: t('skiplinkText') }))), (0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('chat__body') }, { children: (0,jsx_runtime_namespaceObject.jsxs)("div", Object.assign({ className: css_className('conversation__container') }, { children: [(0,jsx_runtime_namespaceObject.jsx)(privacy_disclaimer, {}), (0,jsx_runtime_namespaceObject.jsxs)("ol", Object.assign({ className: css_className('conversation') }, { children: [(0,jsx_runtime_namespaceObject.jsx)(component_filter, { children: (0,jsx_runtime_namespaceObject.jsx)(Events, {}) }), debouncedIsLoading ? (0,jsx_runtime_namespaceObject.jsx)(loader, {}) : null, (0,jsx_runtime_namespaceObject.jsx)(AbortTransactionButton, {})] }))] })) }))] }));
16860
+ return ((0,jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, { children: [isOpen && ((0,jsx_runtime_namespaceObject.jsx)("a", { className: css_className('skip-link'), href: `#${skiplinkTargetId}`, onClick: onClickHandler, children: t('skiplinkText') })), (0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('chat__body'), children: (0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('conversation__container'), children: [(0,jsx_runtime_namespaceObject.jsx)(privacy_disclaimer, {}), (0,jsx_runtime_namespaceObject.jsxs)("ol", { className: css_className('conversation'), children: [(0,jsx_runtime_namespaceObject.jsx)(component_filter, { children: (0,jsx_runtime_namespaceObject.jsx)(Events, {}) }), debouncedIsLoading ? (0,jsx_runtime_namespaceObject.jsx)(loader, {}) : null, (0,jsx_runtime_namespaceObject.jsx)(AbortTransactionButton, {})] })] }) })] }));
16478
16861
  };
16479
16862
  /* harmony default export */ const conversation = (Conversation);
16480
16863
 
@@ -16869,16 +17252,16 @@ const OptionsFrame = ({ className: givenClassName, children, onCancel, headingTe
16869
17252
  (0,hooks_.useEffect)(() => {
16870
17253
  focusElement(container.current);
16871
17254
  }, [container]);
16872
- return ((0,jsx_runtime_namespaceObject.jsx)("section", Object.assign({ className: css_className('options', {
17255
+ return ((0,jsx_runtime_namespaceObject.jsx)("section", { className: css_className('options', {
16873
17256
  'options--right': position.horizontal === 'right',
16874
17257
  'options--left': position.horizontal === 'left',
16875
17258
  'options--top': position.vertical === 'top',
16876
17259
  'options--bottom': position.vertical === 'bottom',
16877
- }, givenClassName), "aria-labelledby": mainHeadingId, tabIndex: -1, ref: container }, { children: (0,jsx_runtime_namespaceObject.jsxs)("div", Object.assign({ className: css_className('options__body') }, { children: [(0,jsx_runtime_namespaceObject.jsx)("h2", Object.assign({ id: mainHeadingId, className: css_className('options__title') }, { children: headingText })), (0,jsx_runtime_namespaceObject.jsxs)("button", Object.assign({ type: "button", onClick: onCancelHandler, "aria-describedby": mainHeadingId, className: css_className('button', 'options__close'), ref: (btn) => {
17260
+ }, givenClassName), "aria-labelledby": mainHeadingId, tabIndex: -1, ref: container, children: (0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('options__body'), children: [(0,jsx_runtime_namespaceObject.jsx)("h2", { id: mainHeadingId, className: css_className('options__title'), children: headingText }), (0,jsx_runtime_namespaceObject.jsxs)("button", { type: "button", onClick: onCancelHandler, "aria-describedby": mainHeadingId, className: css_className('button', 'options__close'), ref: (btn) => {
16878
17261
  if (cancelButtonRef) {
16879
17262
  cancelButtonRef.current = btn;
16880
17263
  }
16881
- } }, { children: [(0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: "close", size: "16", alt: "" }), (0,jsx_runtime_namespaceObject.jsx)("span", { children: cancelButtonText })] })), description ? ((0,jsx_runtime_namespaceObject.jsx)("p", Object.assign({ className: css_className('options__description'), id: descriptionId }, { children: description }))) : null, (0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('options__wrapper') }, { children: children }))] })) })));
17264
+ }, children: [(0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: "close", size: "16", alt: "" }), (0,jsx_runtime_namespaceObject.jsx)("span", { children: cancelButtonText })] }), description ? ((0,jsx_runtime_namespaceObject.jsx)("p", { className: css_className('options__description'), id: descriptionId, children: description })) : null, (0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('options__wrapper'), children: children })] }) }));
16882
17265
  };
16883
17266
  /* harmony default export */ const options_frame = (OptionsFrame);
16884
17267
 
@@ -17015,7 +17398,7 @@ function FormProvider(_a) {
17015
17398
  console.error('"onSubmit" is required.');
17016
17399
  return null;
17017
17400
  }
17018
- return ((0,jsx_runtime_namespaceObject.jsx)(context_Provider, Object.assign({}, props, { value: contextValue }, { children: children })));
17401
+ return ((0,jsx_runtime_namespaceObject.jsx)(context_Provider, Object.assign({}, props, { value: contextValue, children: children })));
17019
17402
  }
17020
17403
 
17021
17404
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/form-controls/form.js
@@ -17081,8 +17464,8 @@ function error_Error({
17081
17464
 
17082
17465
 
17083
17466
 
17084
- const FormControlWrapper = ({ contentHint, id, labelText, labelClass = css_className('label'), validity, errorText, children, }) => {
17085
- return ((0,jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, { children: [contentHint && ((0,jsx_runtime_namespaceObject.jsx)("span", Object.assign({ id: `${id}-content-hint`, className: css_className('input__content-hint') }, { children: contentHint }))), (0,jsx_runtime_namespaceObject.jsx)(error_Error, { id: `${id}-error`, error: !validity && errorText }), (0,jsx_runtime_namespaceObject.jsxs)("div", Object.assign({ className: css_className('form-control__wrapper') }, { children: [(0,jsx_runtime_namespaceObject.jsx)("label", Object.assign({ htmlFor: id, className: labelClass }, { children: labelText })), children] }))] }));
17467
+ const FormControlWrapper = ({ contentHint, id, labelText, labelClass, validity, errorText, children, }) => {
17468
+ return ((0,jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, { children: [contentHint && ((0,jsx_runtime_namespaceObject.jsx)("span", { id: `${id}-content-hint`, className: css_className('input__content-hint'), children: contentHint })), (0,jsx_runtime_namespaceObject.jsx)(error_Error, { id: `${id}-error`, error: !validity && errorText }), (0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('form-control__wrapper'), children: [(0,jsx_runtime_namespaceObject.jsx)("label", { htmlFor: id, className: css_className(labelClass), children: labelText }), children] })] }));
17086
17469
  };
17087
17470
  /* harmony default export */ const wrapper = (FormControlWrapper);
17088
17471
 
@@ -17117,7 +17500,7 @@ function Input(_a) {
17117
17500
  describedByIds.push(`${id}-error`);
17118
17501
  }
17119
17502
  // todo: destructure Field
17120
- return ((0,jsx_runtime_namespaceObject.jsx)(wrapper, Object.assign({ id: id, contentHint: contentHint, validity: !hasError, errorText: error, labelText: labelText, labelClass: labelClass }, { children: (0,jsx_runtime_namespaceObject.jsx)("input", Object.assign({ id: id, name: name, type: type, "aria-invalid": hasError ? 'true' : 'false', "aria-describedby": describedByIds.join(' ') || null }, field, props)) })));
17503
+ return ((0,jsx_runtime_namespaceObject.jsx)(wrapper, { id: id, contentHint: contentHint, validity: !hasError, errorText: error, labelText: labelText, labelClass: labelClass, children: (0,jsx_runtime_namespaceObject.jsx)("input", Object.assign({ id: id, name: name, type: type, "aria-invalid": hasError ? 'true' : 'false', "aria-describedby": describedByIds.join(' ') || null }, field, props)) }));
17121
17504
  }
17122
17505
  /* harmony default export */ const input = (Input);
17123
17506
 
@@ -17465,14 +17848,14 @@ const OptionsButton = () => {
17465
17848
 
17466
17849
 
17467
17850
 
17468
- const TranslationOption = ({ label, checked, description, onChange, id, }) => {
17851
+ const TranslationOption = ({ label, checked, description, onChange, id, itemClassName, }) => {
17469
17852
  const onKeyDown = (e) => {
17470
17853
  if (e.code === 'Space' || e.code === 'Enter') {
17471
17854
  e.preventDefault();
17472
17855
  onChange();
17473
17856
  }
17474
17857
  };
17475
- return ((0,jsx_runtime_namespaceObject.jsxs)("li", Object.assign({ className: css_className('translation-options__item'), "aria-selected": checked, role: "option", tabIndex: 0, onClick: onChange, onKeyDown: onKeyDown, id: id }, { children: [(0,jsx_runtime_namespaceObject.jsx)(layout_icon, { alt: "", name: "check", size: "16" }), label, " ", description && (0,jsx_runtime_namespaceObject.jsxs)("span", { children: ["(", description, ")"] })] })));
17858
+ return ((0,jsx_runtime_namespaceObject.jsxs)("li", { className: css_className([itemClassName, 'translation-options__item']), "aria-selected": checked, role: "option", tabIndex: 0, onClick: onChange, onKeyDown: onKeyDown, id: id, children: [(0,jsx_runtime_namespaceObject.jsx)(layout_icon, { alt: "", name: "check", size: "16" }), label, " ", description && (0,jsx_runtime_namespaceObject.jsxs)("span", { children: ["(", description, ")"] })] }));
17476
17859
  };
17477
17860
  /* harmony default export */ const translation_option = (TranslationOption);
17478
17861
 
@@ -17484,12 +17867,13 @@ const TranslationOption = ({ label, checked, description, onChange, id, }) => {
17484
17867
 
17485
17868
 
17486
17869
 
17870
+ const isChecked = (language, currentLocale, isOriginal) => currentLocale === language.locale || (!currentLocale && isOriginal);
17487
17871
  const TranslationOptions = ({ onChange, describedById, }) => {
17488
17872
  const { context: { locale: defaultLocale }, } = useConfig();
17489
17873
  const { t } = useI18n();
17490
17874
  const { focusContainer } = useTranslationsContainer();
17491
17875
  const { languages, currentLocale, enableTranslations, disableTranslations } = useTranslations();
17492
- const handleChange = ({ locale }) => () => {
17876
+ const handleChange = (locale) => () => {
17493
17877
  if (locale === currentLocale || defaultLocale === locale) {
17494
17878
  disableTranslations();
17495
17879
  }
@@ -17499,22 +17883,25 @@ const TranslationOptions = ({ onChange, describedById, }) => {
17499
17883
  onChange();
17500
17884
  focusContainer();
17501
17885
  };
17502
- const sortedLanguages = (0,hooks_.useMemo)(() => {
17503
- return [...languages].sort((a, b) => {
17504
- if (a.locale === defaultLocale)
17505
- return -1;
17506
- if (b.locale === defaultLocale)
17507
- return 1;
17508
- return a.nativeName.localeCompare(b.nativeName, undefined, {
17509
- sensitivity: 'base',
17510
- });
17511
- });
17512
- }, [languages, defaultLocale]);
17513
- return ((0,jsx_runtime_namespaceObject.jsx)("ul", Object.assign({ "aria-describedby": describedById, role: "listbox", tabIndex: -1, className: css_className('translation-options') }, { children: sortedLanguages.map((language, idx) => {
17514
- const isOriginal = idx === 0;
17515
- const checked = currentLocale === language.locale || (!currentLocale && isOriginal);
17516
- return ((0,jsx_runtime_namespaceObject.jsx)(translation_option, { id: language.locale, label: language.nativeName, checked: checked, description: isOriginal && t('translations.settings.original'), onChange: handleChange(language) }, language.locale));
17517
- }) })));
17886
+ const { primaryLanguages, remainingLanguages } = (0,compat_namespaceObject.useMemo)(() => languages.reduce((acc, language) => {
17887
+ const isOriginal = language.locale === defaultLocale;
17888
+ const checked = isChecked(language, currentLocale, isOriginal);
17889
+ if (language.locale !== defaultLocale) {
17890
+ acc.remainingLanguages.push(Object.assign(Object.assign({}, language), { checked, isOriginal }));
17891
+ }
17892
+ const selectedIdx = acc.remainingLanguages.findIndex((l) => l.locale === currentLocale);
17893
+ if (isOriginal || (checked && selectedIdx > 4)) {
17894
+ acc.primaryLanguages.push(Object.assign(Object.assign({}, language), { checked, isOriginal }));
17895
+ }
17896
+ return acc;
17897
+ }, {
17898
+ primaryLanguages: [],
17899
+ remainingLanguages: [],
17900
+ }), [currentLocale, defaultLocale, languages]);
17901
+ return ((0,jsx_runtime_namespaceObject.jsxs)("ul", { "aria-describedby": describedById, role: "listbox", tabIndex: -1, className: css_className('translation-options'), children: [primaryLanguages.map(({ locale, nativeName, checked, isOriginal }, idx) => ((0,jsx_runtime_namespaceObject.jsx)(translation_option, { id: locale, label: nativeName, checked: checked, description: isOriginal && t('translations.settings.original'), onChange: handleChange(locale), itemClassName: css_className({
17902
+ 'translation-options__item--original': isOriginal,
17903
+ 'translation-options__item--selected': checked && idx !== 0,
17904
+ }) }, locale))), remainingLanguages.map(({ locale, nativeName, checked, isOriginal }) => ((0,jsx_runtime_namespaceObject.jsx)(translation_option, { id: locale, label: nativeName, checked: checked, description: isOriginal && t('translations.settings.original'), onChange: handleChange(locale) }, locale)))] }));
17518
17905
  };
17519
17906
  /* harmony default export */ const translation_options = (TranslationOptions);
17520
17907
 
@@ -17527,7 +17914,7 @@ const TranslationOptions = ({ onChange, describedById, }) => {
17527
17914
  function TranslationsOptionsDialog({ onClose, position, }) {
17528
17915
  const { t } = useI18n();
17529
17916
  const descriptionId = useGeneratedId();
17530
- return ((0,jsx_runtime_namespaceObject.jsx)(options_frame, Object.assign({ onCancel: onClose, headingText: t('translations.menu.title'), cancelButtonText: t('translations.settings.cancelButtonText'), description: t('translations.menu.description'), descriptionId: descriptionId, position: position, disableButtonFocusing: true }, { children: (0,jsx_runtime_namespaceObject.jsx)(translation_options, { describedById: descriptionId, onChange: onClose }) })));
17917
+ return ((0,jsx_runtime_namespaceObject.jsx)(options_frame, { onCancel: onClose, headingText: t('translations.menu.title'), cancelButtonText: t('translations.settings.cancelButtonText'), description: t('translations.menu.description'), descriptionId: descriptionId, position: position, disableButtonFocusing: true, children: (0,jsx_runtime_namespaceObject.jsx)(translation_options, { describedById: descriptionId, onChange: onClose }) }));
17531
17918
  }
17532
17919
  /* harmony default export */ const options_dialog = (TranslationsOptionsDialog);
17533
17920
 
@@ -17567,11 +17954,11 @@ function TranslationsOptionsButton({ children, position = {
17567
17954
  e.preventDefault();
17568
17955
  }
17569
17956
  };
17570
- return ((0,jsx_runtime_namespaceObject.jsxs)("div", Object.assign({ className: css_className('translations__container'), onKeyDown: onMainKeyDownHandler }, { children: [(0,jsx_runtime_namespaceObject.jsx)(in_out_transition, Object.assign({ transitionStartState: transitionStartStates.notRendered, isActive: menuIsOpen }, { children: (0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('options__dialog'), role: "dialog" }, { children: (0,jsx_runtime_namespaceObject.jsx)(options_dialog, { onClose: handleDialogClose, position: position }) })) })), (0,jsx_runtime_namespaceObject.jsx)("button", Object.assign({ type: "button", className: css_className([
17957
+ return ((0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('translations__container'), onKeyDown: onMainKeyDownHandler, children: [(0,jsx_runtime_namespaceObject.jsx)(in_out_transition, { transitionStartState: transitionStartStates.notRendered, isActive: menuIsOpen, children: (0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('options__dialog'), role: "dialog", children: (0,jsx_runtime_namespaceObject.jsx)(options_dialog, { onClose: handleDialogClose, position: position }) }) }), (0,jsx_runtime_namespaceObject.jsx)("button", { type: "button", className: css_className([
17571
17958
  'button',
17572
17959
  'chat__options__button',
17573
17960
  ...classNames,
17574
- ]), id: toggleButtonId, onClick: handleToggleClick, onKeyDown: handleToggleKeyDown, ref: toggleButton, "aria-haspopup": "dialog", "aria-expanded": menuIsOpen }, { children: children }))] })));
17961
+ ]), id: toggleButtonId, onClick: handleToggleClick, onKeyDown: handleToggleKeyDown, ref: toggleButton, "aria-haspopup": "dialog", "aria-expanded": menuIsOpen, children: children })] }));
17575
17962
  }
17576
17963
 
17577
17964
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/app-options/index.js
@@ -17641,7 +18028,7 @@ const UnreadMessagesButton = () => {
17641
18028
  const { scrollToRef, unreadIds } = (0,hooks_.useContext)(chat_scroll_context);
17642
18029
  const { isMinimized } = useVisibility();
17643
18030
  const { t } = useI18n();
17644
- return ((0,jsx_runtime_namespaceObject.jsx)(in_out_transition, Object.assign({ isActive: !!unreadIds.length && !isMinimized }, { children: (0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('unread-messages') }, { children: (0,jsx_runtime_namespaceObject.jsxs)("button", Object.assign({ type: "button", className: css_className('button', 'button--primary'), onClick: scrollToRef }, { children: [t('message.unreadMessagesCount', { unreadCount: unreadIds.length }), (0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: "chevronDown", size: "32", alt: "" })] })) })) })));
18031
+ return ((0,jsx_runtime_namespaceObject.jsx)(in_out_transition, { isActive: !!unreadIds.length && !isMinimized, children: (0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('unread-messages'), children: (0,jsx_runtime_namespaceObject.jsxs)("button", { type: "button", className: css_className('button', 'button--primary'), onClick: scrollToRef, children: [t('message.unreadMessagesCount', { unreadCount: unreadIds.length }), (0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: "chevronDown", size: "32", alt: "" })] }) }) }));
17645
18032
  };
17646
18033
  /* harmony default export */ const unread_messages_button = (UnreadMessagesButton);
17647
18034
 
@@ -17789,13 +18176,13 @@ const ChatScrollProvider = ({ children }) => {
17789
18176
  return acc;
17790
18177
  }, {}), [events]);
17791
18178
  const { scrollToRef, scrollToBottom, containerRef, unreadIds } = use_chat_scroll(eventRefs);
17792
- return ((0,jsx_runtime_namespaceObject.jsx)(chat_scroll_context.Provider, Object.assign({ value: {
18179
+ return ((0,jsx_runtime_namespaceObject.jsx)(chat_scroll_context.Provider, { value: {
17793
18180
  eventRefs,
17794
18181
  unreadIds,
17795
18182
  scrollToRef,
17796
18183
  scrollToBottom,
17797
18184
  containerRef,
17798
- } }, { children: (0,jsx_runtime_namespaceObject.jsxs)("div", Object.assign({ className: css_className('chat__container') }, { children: [(0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('chat__container__scroll-area'), ref: containerRef }, { children: children })), (0,jsx_runtime_namespaceObject.jsx)(unread_messages_button, {})] })) })));
18185
+ }, children: (0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('chat__container'), children: [(0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('chat__container__scroll-area'), ref: containerRef, children: children }), (0,jsx_runtime_namespaceObject.jsx)(unread_messages_button, {})] }) }));
17799
18186
  };
17800
18187
  /* harmony default export */ const chat_scroll_provider = (ChatScrollProvider);
17801
18188
 
@@ -18086,13 +18473,13 @@ function TextEntryForm({ controlName, skipLinkId }) {
18086
18473
  // When a message is submitted, the keyboard should be prevented from closing on mobile devices
18087
18474
  event.preventDefault();
18088
18475
  };
18089
- return ((0,jsx_runtime_namespaceObject.jsxs)(form_controls_form, Object.assign({ className: css_className('entry-form'), disableValidationClasses: true, noValidate: "true" }, { children: [(0,jsx_runtime_namespaceObject.jsxs)("div", Object.assign({ className: css_className([
18476
+ return ((0,jsx_runtime_namespaceObject.jsxs)(form_controls_form, { className: css_className('entry-form'), disableValidationClasses: true, noValidate: "true", children: [(0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className([
18090
18477
  'input--text__container',
18091
18478
  ...(reachedCharacterWarning && !reachedCharacterLimit
18092
18479
  ? ['character-warning']
18093
18480
  : []),
18094
18481
  ...(reachedCharacterLimit ? ['character-exceeded'] : []),
18095
- ]) }, { children: [(0,jsx_runtime_namespaceObject.jsx)(input, { id: skipLinkId, type: "text", name: controlName, className: css_className('input__text'), autocomplete: "off", placeholder: placeholder, labelText: label, labelClass: css_className(labelClass), "aria-invalid": hasCharacterLimit ? reachedCharacterLimit : null, onKeyUp: handleKeyUp, onFocus: handleFocus }), (0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('character-count') }, { children: reachedCharacterWarning && (0,jsx_runtime_namespaceObject.jsx)("span", { children: remainingChars }) }))] })), (0,jsx_runtime_namespaceObject.jsx)("button", Object.assign({ className: css_className('button', 'input__submit'), type: "submit", onPointerDown: handlePointerDown, "aria-disabled": !hasValue || reachedCharacterLimit ? 'true' : null }, { children: (0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: "send", size: "32", alt: t('input.sendMessage') }) }))] })));
18482
+ ]), children: [(0,jsx_runtime_namespaceObject.jsx)(input, { id: skipLinkId, type: "text", name: controlName, className: css_className('input__text'), autocomplete: "off", placeholder: placeholder, labelText: label, labelClass: css_className(labelClass), "aria-invalid": hasCharacterLimit ? reachedCharacterLimit : null, onKeyUp: handleKeyUp, onFocus: handleFocus }), (0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('character-count'), children: reachedCharacterWarning && (0,jsx_runtime_namespaceObject.jsx)("span", { children: remainingChars }) })] }), (0,jsx_runtime_namespaceObject.jsx)("button", { className: css_className('button', 'input__submit'), type: "submit", onPointerDown: handlePointerDown, "aria-disabled": !hasValue || reachedCharacterLimit ? 'true' : null, children: (0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: "send", size: "32", alt: t('input.sendMessage') }) })] }));
18096
18483
  }
18097
18484
 
18098
18485
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/entry/text-entry/index.js
@@ -18750,7 +19137,7 @@ const CollapseButton = () => {
18750
19137
 
18751
19138
  const ChatStatus = ({ children, handleClose, title, closeButtonText, srCloseButtonText, id, }) => {
18752
19139
  const headingId = useGeneratedId();
18753
- return ((0,jsx_runtime_namespaceObject.jsxs)("section", Object.assign({ tabIndex: -1, id: id, "aria-labelledby": title ? headingId : undefined, className: css_className('chat-status', !title && 'chat-status--condensed') }, { children: [(0,jsx_runtime_namespaceObject.jsxs)("div", Object.assign({ className: css_className('chat-status__body') }, { children: [title ? ((0,jsx_runtime_namespaceObject.jsx)("h2", Object.assign({ className: css_className('chat-status__title'), id: headingId }, { children: title }))) : null, children] })), typeof handleClose === 'function' && ((0,jsx_runtime_namespaceObject.jsxs)("button", Object.assign({ type: "button", onClick: handleClose, className: css_className('button', 'button--tertiary', 'chat-status__close') }, { children: [closeButtonText || (0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: "close", size: "16", alt: "" }), srCloseButtonText && ((0,jsx_runtime_namespaceObject.jsx)("span", Object.assign({ className: css_className('visually-hidden') }, { children: srCloseButtonText })))] })))] })));
19140
+ return ((0,jsx_runtime_namespaceObject.jsxs)("section", { tabIndex: -1, id: id, "aria-labelledby": title ? headingId : undefined, className: css_className('chat-status', !title && 'chat-status--condensed'), children: [(0,jsx_runtime_namespaceObject.jsxs)("div", { className: css_className('chat-status__body'), children: [title ? ((0,jsx_runtime_namespaceObject.jsx)("h2", { className: css_className('chat-status__title'), id: headingId, children: title })) : null, children] }), typeof handleClose === 'function' && ((0,jsx_runtime_namespaceObject.jsxs)("button", { type: "button", onClick: handleClose, className: css_className('button', 'button--tertiary', 'chat-status__close'), children: [closeButtonText || (0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: "close", size: "16", alt: "" }), srCloseButtonText && ((0,jsx_runtime_namespaceObject.jsx)("span", { className: css_className('visually-hidden'), children: srCloseButtonText }))] }))] }));
18754
19141
  };
18755
19142
  /* harmony default export */ const chat_status = (ChatStatus);
18756
19143
 
@@ -18785,7 +19172,7 @@ function TranslationChatStatus() {
18785
19172
 
18786
19173
 
18787
19174
 
18788
- const ChatStatusAction = ({ handleClick, icon, title, srButtonText, }) => ((0,jsx_runtime_namespaceObject.jsxs)("button", Object.assign({ type: "button", onClick: handleClick, className: css_className('button', 'button--primary', 'chat-status__button') }, { children: [(0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: icon, size: "16", alt: "" }), title, srButtonText && ((0,jsx_runtime_namespaceObject.jsx)("span", Object.assign({ className: css_className('visually-hidden') }, { children: srButtonText })))] })));
19175
+ const ChatStatusAction = ({ handleClick, icon, title, srButtonText, }) => ((0,jsx_runtime_namespaceObject.jsxs)("button", { type: "button", onClick: handleClick, className: css_className('button', 'button--primary', 'chat-status__button'), children: [(0,jsx_runtime_namespaceObject.jsx)(layout_icon, { name: icon, size: "16", alt: "" }), title, srButtonText && ((0,jsx_runtime_namespaceObject.jsx)("span", { className: css_className('visually-hidden'), children: srButtonText }))] }));
18789
19176
  /* harmony default export */ const chat_status_action = (ChatStatusAction);
18790
19177
 
18791
19178
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/translation-proposal/index.tsx
@@ -18799,7 +19186,7 @@ function TranslationProposal() {
18799
19186
  if (!showProposal) {
18800
19187
  return null;
18801
19188
  }
18802
- return ((0,jsx_runtime_namespaceObject.jsx)(chat_status, Object.assign({ handleClose: dismissTranslationProposal, srCloseButtonText: translationProposal.srDismissButtonText, id: id, title: translationProposal.titleLabel }, { children: (0,jsx_runtime_namespaceObject.jsx)(chat_status_action, { handleClick: activateTranslationProposal, icon: "newTranslation", title: translationProposal.buttonLabel }) })));
19189
+ return ((0,jsx_runtime_namespaceObject.jsx)(chat_status, { handleClose: dismissTranslationProposal, srCloseButtonText: translationProposal.srDismissButtonText, id: id, title: translationProposal.titleLabel, children: (0,jsx_runtime_namespaceObject.jsx)(chat_status_action, { handleClick: activateTranslationProposal, icon: "newTranslation", title: translationProposal.buttonLabel }) }));
18803
19190
  }
18804
19191
 
18805
19192
  ;// CONCATENATED MODULE: ./src/javascripts/domains/translations/components/translation-status.tsx
@@ -19066,10 +19453,14 @@ const WindowOpenButton = ({
19066
19453
  "aria-label": ariaLabel,
19067
19454
  "aria-hidden": isOpen,
19068
19455
  onClick: handleClick,
19069
- children: [(0,jsx_runtime_namespaceObject.jsx)("span", {
19070
- className: css_className('message-count'),
19071
- "aria-hidden": "true",
19072
- children: !!count && count
19456
+ children: [(0,jsx_runtime_namespaceObject.jsx)(in_out_transition, {
19457
+ isActive: !!count,
19458
+ transitionStartState: transitionStartStates.notRendered,
19459
+ children: (0,jsx_runtime_namespaceObject.jsx)("span", {
19460
+ className: css_className('message-count'),
19461
+ "aria-hidden": "true",
19462
+ children: count
19463
+ })
19073
19464
  }), (0,jsx_runtime_namespaceObject.jsx)(ButtonIcon, {})]
19074
19465
  })
19075
19466
  });
@@ -19104,7 +19495,7 @@ const WindowView = () => {
19104
19495
  },
19105
19496
  },
19106
19497
  }), [continueChatText]);
19107
- return ((0,jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, { children: [(0,jsx_runtime_namespaceObject.jsx)(window_open_button, { onClick: openChat }), (0,jsx_runtime_namespaceObject.jsx)(in_out_transition, Object.assign({ isActive: preChat && !isOpen && !userHasResponded, exitAfter: getDelay(preChat, 'exitAfter'), enterDelay: getDelay(preChat, 'enterDelay'), transitionStartState: transitionStartStates.rendered }, { children: (0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('unstarted-wrapper', 'unstarted-wrapper--window') }, { children: (0,jsx_runtime_namespaceObject.jsx)(PreChatMessages, {}) })) })), (0,jsx_runtime_namespaceObject.jsx)(in_out_transition, Object.assign({ isActive: continueChat && !isOpen && userHasResponded, exitAfter: getDelay(continueChat, 'exitAfter'), enterDelay: getDelay(continueChat, 'enterDelay'), transitionStartState: transitionStartStates.notRendered }, { children: (0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className('unstarted-wrapper', 'unstarted-wrapper--window', 'unstarted-wrapper--continue') }, { children: (0,jsx_runtime_namespaceObject.jsx)(event_text, { event: continueChatEvent }) })) })), (0,jsx_runtime_namespaceObject.jsx)(in_out_transition, Object.assign({ isActive: isOpen, transitionStartState: transitionStartStates.notRendered }, { children: (0,jsx_runtime_namespaceObject.jsx)(chat, { children: (0,jsx_runtime_namespaceObject.jsx)(chat_frame, { children: (0,jsx_runtime_namespaceObject.jsx)(conversation, {}) }) }) }))] }));
19498
+ return ((0,jsx_runtime_namespaceObject.jsxs)(jsx_runtime_namespaceObject.Fragment, { children: [(0,jsx_runtime_namespaceObject.jsx)(window_open_button, { onClick: openChat }), (0,jsx_runtime_namespaceObject.jsx)(in_out_transition, { isActive: preChat && !isOpen && !userHasResponded, exitAfter: getDelay(preChat, 'exitAfter'), enterDelay: getDelay(preChat, 'enterDelay'), transitionStartState: transitionStartStates.rendered, children: (0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('unstarted-wrapper', 'unstarted-wrapper--window'), children: (0,jsx_runtime_namespaceObject.jsx)(PreChatMessages, {}) }) }), (0,jsx_runtime_namespaceObject.jsx)(in_out_transition, { isActive: continueChat && !isOpen && userHasResponded, exitAfter: getDelay(continueChat, 'exitAfter'), enterDelay: getDelay(continueChat, 'enterDelay'), transitionStartState: transitionStartStates.notRendered, children: (0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className('unstarted-wrapper', 'unstarted-wrapper--window', 'unstarted-wrapper--continue'), children: (0,jsx_runtime_namespaceObject.jsx)(event_text, { event: continueChatEvent }) }) }), (0,jsx_runtime_namespaceObject.jsx)(in_out_transition, { isActive: isOpen, transitionStartState: transitionStartStates.notRendered, children: (0,jsx_runtime_namespaceObject.jsx)(chat, { children: (0,jsx_runtime_namespaceObject.jsx)(chat_frame, { children: (0,jsx_runtime_namespaceObject.jsx)(conversation, {}) }) }) })] }));
19108
19499
  };
19109
19500
  /* harmony default export */ const window_view = (WindowView);
19110
19501
 
@@ -19319,7 +19710,7 @@ const View = ({ children }) => {
19319
19710
  if (userHasResponded) {
19320
19711
  classNames.push('app--user-responded');
19321
19712
  }
19322
- return (isVisible && ((0,jsx_runtime_namespaceObject.jsx)("div", Object.assign({ className: css_className(classNames), lang: blockLang, tabIndex: -1, "data-nosnippet": true, style: { zIndex }, ref: containerElementRef }, { children: children || (0,jsx_runtime_namespaceObject.jsx)(ViewComponent, {}) }))));
19713
+ return (isVisible && ((0,jsx_runtime_namespaceObject.jsx)("div", { className: css_className(classNames), lang: blockLang, tabIndex: -1, "data-nosnippet": true, style: { zIndex }, ref: containerElementRef, children: children || (0,jsx_runtime_namespaceObject.jsx)(ViewComponent, {}) })));
19323
19714
  };
19324
19715
  /* harmony default export */ const view = (View);
19325
19716
 
@@ -19409,14 +19800,16 @@ class Engine {
19409
19800
  yield store.dispatch(initializeConfig());
19410
19801
  try {
19411
19802
  const { locale } = yield store.dispatch(initializeApp()).unwrap();
19412
- yield store.dispatch(setLocale(locale));
19803
+ if (locale) {
19804
+ yield store.dispatch(setLocale(locale));
19805
+ }
19413
19806
  }
19414
19807
  catch (rejectedValueOrSerializedError) {
19415
19808
  // nothing to do
19416
19809
  }
19417
19810
  store.dispatch(initializeVisibility());
19418
19811
  if (View) {
19419
- (0,external_preact_.render)((0,jsx_runtime_namespaceObject.jsx)(seamly_core, Object.assign({ eventBus: this.eventBus, store: store, api: this.api }, { children: (0,jsx_runtime_namespaceObject.jsx)(View, {}) })), this.parentElement);
19812
+ (0,external_preact_.render)((0,jsx_runtime_namespaceObject.jsx)(seamly_core, { eventBus: this.eventBus, store: store, api: this.api, children: (0,jsx_runtime_namespaceObject.jsx)(View, {}) }), this.parentElement);
19420
19813
  }
19421
19814
  else {
19422
19815
  (0,external_preact_.render)((0,jsx_runtime_namespaceObject.jsx)(chat_app, { config: renderConfig, eventBus: this.eventBus, store: store, api: this.api }), this.parentElement);