@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
@@ -2104,6 +2104,7 @@ _ConversationConnector_connectionListeners = new WeakMap(), _ConversationConnect
2104
2104
  return !complete;
2105
2105
  }), "f");
2106
2106
  };
2107
+ /* harmony default export */ const conversation_connector = (ConversationConnector);
2107
2108
  ;// CONCATENATED MODULE: ./src/javascripts/api/index.ts
2108
2109
  var api_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
2109
2110
  function adopt(value) {
@@ -2143,6 +2144,14 @@ var api_classPrivateFieldGet = undefined && undefined.__classPrivateFieldGet ||
2143
2144
  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");
2144
2145
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
2145
2146
  };
2147
+ var __rest = undefined && undefined.__rest || function (s, e) {
2148
+ var t = {};
2149
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
2150
+ if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
2151
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
2152
+ }
2153
+ return t;
2154
+ };
2146
2155
  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;
2147
2156
 
2148
2157
 
@@ -2230,7 +2239,7 @@ class API {
2230
2239
  _API_conversationAuthToken.set(this, void 0);
2231
2240
  _API_layoutMode.set(this, void 0);
2232
2241
  _API_config.set(this, void 0);
2233
- this.conversation = new ConversationConnector();
2242
+ this.conversation = new conversation_connector();
2234
2243
  _API_getLocale.set(this, locale => locale || this.locale);
2235
2244
  this.store = objectStore(`${namespace}.connection${context.locale ? `.${context.locale}` : ''}`, config.storageProvider || store);
2236
2245
  this.connectionInfo = {
@@ -2260,7 +2269,8 @@ class API {
2260
2269
  });
2261
2270
  }
2262
2271
  getConversationUrl() {
2263
- return this.store.get('conversationUrl');
2272
+ const conversationUrl = this.store.get('conversationUrl');
2273
+ return conversationUrl;
2264
2274
  }
2265
2275
  hasConversation() {
2266
2276
  return !!this.getConversationUrl();
@@ -2368,7 +2378,7 @@ class API {
2368
2378
  if (error.status >= 500) {
2369
2379
  throw new SeamlyGeneralError(error);
2370
2380
  }
2371
- throw error;
2381
+ throw new ApiError(error);
2372
2382
  }
2373
2383
  });
2374
2384
  }
@@ -2477,7 +2487,7 @@ class API {
2477
2487
  if (error.status >= 500) {
2478
2488
  throw new SeamlyGeneralError(error);
2479
2489
  }
2480
- throw error;
2490
+ throw new ApiError(error);
2481
2491
  }
2482
2492
  });
2483
2493
  }
@@ -2503,6 +2513,7 @@ class API {
2503
2513
  this.conversation.pushToChannel(command, buildPayload(command, payload), 10000);
2504
2514
  }
2505
2515
  sendContext(context) {
2516
+ var _a;
2506
2517
  const {
2507
2518
  locale,
2508
2519
  variables
@@ -2524,19 +2535,29 @@ class API {
2524
2535
  if (Object.keys(payload).length === 0 && payload.constructor === Object) {
2525
2536
  return;
2526
2537
  }
2527
- this.send('context', payload, false);
2538
+ // Destructure the server locale from the payload
2539
+ const {
2540
+ locale: _
2541
+ } = payload,
2542
+ restPayload = __rest(payload, ["locale"]);
2543
+ const configLocale = (_a = api_classPrivateFieldGet(this, _API_config, "f").context) === null || _a === void 0 ? void 0 : _a.locale;
2544
+ this.send('context', Object.assign(Object.assign({}, configLocale ? {
2545
+ locale: configLocale
2546
+ } : {}), restPayload), false);
2528
2547
  }
2529
2548
  }
2530
2549
  _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() {
2531
- return this.store.get('accessToken');
2550
+ const accessToken = this.store.get('accessToken');
2551
+ return accessToken;
2532
2552
  }, _API_setAccessToken = function _API_setAccessToken(accessToken) {
2533
2553
  this.store.set('accessToken', accessToken);
2534
2554
  }, _API_setConversationUrl = function _API_setConversationUrl(url) {
2535
2555
  this.store.set('conversationUrl', url);
2536
2556
  }, _API_getChannelTopic = function _API_getChannelTopic() {
2557
+ const channelTopic = this.store.get('channelTopic') || this.store.get('channelName');
2537
2558
  // The `channelName` fallback is needed for seamless client upgrades.
2538
2559
  // TODO: Remove when all clients have been upgraded past v20.
2539
- return this.store.get('channelTopic') || this.store.get('channelName');
2560
+ return channelTopic;
2540
2561
  }, _API_setChannelTopic = function _API_setChannelTopic(topic) {
2541
2562
  this.store.set('channelTopic', topic);
2542
2563
  }, _API_getUrlPrefix = function _API_getUrlPrefix(protocol) {
@@ -2601,7 +2622,7 @@ _API_ready = new WeakMap(), _API_externalId = new WeakMap(), _API_conversationAu
2601
2622
  return {
2602
2623
  clientName: "@seamly/web-ui",
2603
2624
  clientVariant: api_classPrivateFieldGet(this, _API_layoutMode, "f"),
2604
- clientVersion: "22.1.0",
2625
+ clientVersion: "22.3.0-beta.1",
2605
2626
  currentUrl: window.location.toString(),
2606
2627
  screenResolution: `${window.screen.width}x${window.screen.height}`,
2607
2628
  timezone: getTimeZone(),
@@ -2637,15 +2658,52 @@ const setBatch = newBatch => batch = newBatch; // Supply a getter just to skip d
2637
2658
  const getBatch = () => batch;
2638
2659
  ;// CONCATENATED MODULE: ./node_modules/react-redux/es/components/Context.js
2639
2660
 
2640
- const Context_ReactReduxContext = /*#__PURE__*/(0,compat_module.createContext)(null);
2661
+ const ContextKey = Symbol.for(`react-redux-context-${compat_module.version}`);
2662
+ const gT = globalThis;
2663
+
2664
+ function getContext() {
2665
+ let realContext = gT[ContextKey];
2666
+
2667
+ if (!realContext) {
2668
+ realContext = (0,compat_module.createContext)(null);
2669
+
2670
+ if (false) {}
2671
+
2672
+ gT[ContextKey] = realContext;
2673
+ }
2674
+
2675
+ return realContext;
2676
+ }
2677
+
2678
+ const Context_ReactReduxContext = /*#__PURE__*/new Proxy({}, /*#__PURE__*/new Proxy({}, {
2679
+ get(_, handler) {
2680
+ const target = getContext(); // @ts-ignore
2641
2681
 
2642
- if (false) {}
2682
+ return (_target, ...args) => Reflect[handler](target, ...args);
2683
+ }
2643
2684
 
2685
+ }));
2644
2686
  /* harmony default export */ const Context = ((/* unused pure expression or super */ null && (Context_ReactReduxContext)));
2645
2687
  ;// CONCATENATED MODULE: ./node_modules/react-redux/es/hooks/useReduxContext.js
2646
2688
 
2647
2689
 
2648
2690
 
2691
+ /**
2692
+ * Hook factory, which creates a `useReduxContext` hook bound to a given context. This is a low-level
2693
+ * hook that you should usually not need to call directly.
2694
+ *
2695
+ * @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
2696
+ * @returns {Function} A `useReduxContext` hook bound to the specified context.
2697
+ */
2698
+ function createReduxContextHook(context = Context_ReactReduxContext) {
2699
+ return function useReduxContext() {
2700
+ const contextValue = (0,compat_module.useContext)(context);
2701
+
2702
+ if (false) {}
2703
+
2704
+ return contextValue;
2705
+ };
2706
+ }
2649
2707
  /**
2650
2708
  * A hook to access the value of the `ReactReduxContext`. This is a low-level
2651
2709
  * hook that you should usually not need to call directly.
@@ -2662,13 +2720,8 @@ if (false) {}
2662
2720
  * return <div>{store.getState()}</div>
2663
2721
  * }
2664
2722
  */
2665
- function useReduxContext_useReduxContext() {
2666
- const contextValue = (0,compat_module.useContext)(Context_ReactReduxContext);
2667
-
2668
- if (false) {}
2669
2723
 
2670
- return contextValue;
2671
- }
2724
+ const useReduxContext_useReduxContext = /*#__PURE__*/createReduxContextHook();
2672
2725
  ;// CONCATENATED MODULE: ./node_modules/react-redux/es/utils/useSyncExternalStore.js
2673
2726
  const useSyncExternalStore_notInitialized = () => {
2674
2727
  throw new Error('uSES not initialized!');
@@ -2693,16 +2746,37 @@ const refEquality = (a, b) => a === b;
2693
2746
 
2694
2747
 
2695
2748
  function createSelectorHook(context = Context_ReactReduxContext) {
2696
- const useReduxContext = context === Context_ReactReduxContext ? useReduxContext_useReduxContext : () => (0,compat_module.useContext)(context);
2697
- return function useSelector(selector, equalityFn = refEquality) {
2749
+ const useReduxContext = context === Context_ReactReduxContext ? useReduxContext_useReduxContext : createReduxContextHook(context);
2750
+ return function useSelector(selector, equalityFnOrOptions = {}) {
2751
+ const {
2752
+ equalityFn = refEquality,
2753
+ stabilityCheck = undefined,
2754
+ noopCheck = undefined
2755
+ } = typeof equalityFnOrOptions === 'function' ? {
2756
+ equalityFn: equalityFnOrOptions
2757
+ } : equalityFnOrOptions;
2758
+
2698
2759
  if (false) {}
2699
2760
 
2700
2761
  const {
2701
2762
  store,
2702
2763
  subscription,
2703
- getServerState
2764
+ getServerState,
2765
+ stabilityCheck: globalStabilityCheck,
2766
+ noopCheck: globalNoopCheck
2704
2767
  } = useReduxContext();
2705
- const selectedState = useSyncExternalStoreWithSelector(subscription.addNestedSub, store.getState, getServerState || store.getState, selector, equalityFn);
2768
+ const firstRun = (0,compat_module.useRef)(true);
2769
+ const wrappedSelector = (0,compat_module.useCallback)({
2770
+ [selector.name](state) {
2771
+ const selected = selector(state);
2772
+
2773
+ if (false) {}
2774
+
2775
+ return selected;
2776
+ }
2777
+
2778
+ }[selector.name], [selector, globalStabilityCheck, stabilityCheck]);
2779
+ const selectedState = useSyncExternalStoreWithSelector(subscription.addNestedSub, store.getState, getServerState || store.getState, wrappedSelector, equalityFn);
2706
2780
  (0,compat_module.useDebugValue)(selectedState);
2707
2781
  return selectedState;
2708
2782
  };
@@ -3289,16 +3363,20 @@ function Provider({
3289
3363
  store,
3290
3364
  context,
3291
3365
  children,
3292
- serverState
3366
+ serverState,
3367
+ stabilityCheck = 'once',
3368
+ noopCheck = 'once'
3293
3369
  }) {
3294
3370
  const contextValue = (0,compat_module.useMemo)(() => {
3295
3371
  const subscription = Subscription_createSubscription(store);
3296
3372
  return {
3297
3373
  store,
3298
3374
  subscription,
3299
- getServerState: serverState ? () => serverState : undefined
3375
+ getServerState: serverState ? () => serverState : undefined,
3376
+ stabilityCheck,
3377
+ noopCheck
3300
3378
  };
3301
- }, [store, serverState]);
3379
+ }, [store, serverState, stabilityCheck, noopCheck]);
3302
3380
  const previousState = (0,compat_module.useMemo)(() => store.getState(), [store]);
3303
3381
  useIsomorphicLayoutEffect_useIsomorphicLayoutEffect(() => {
3304
3382
  const {
@@ -3327,7 +3405,6 @@ function Provider({
3327
3405
  ;// CONCATENATED MODULE: ./node_modules/react-redux/es/hooks/useStore.js
3328
3406
 
3329
3407
 
3330
-
3331
3408
  /**
3332
3409
  * Hook factory, which creates a `useStore` hook bound to a given context.
3333
3410
  *
@@ -3337,7 +3414,8 @@ function Provider({
3337
3414
 
3338
3415
  function createStoreHook(context = Context_ReactReduxContext) {
3339
3416
  const useReduxContext = // @ts-ignore
3340
- context === Context_ReactReduxContext ? useReduxContext_useReduxContext : () => (0,compat_module.useContext)(context);
3417
+ context === Context_ReactReduxContext ? useReduxContext_useReduxContext : // @ts-ignore
3418
+ createReduxContextHook(context);
3341
3419
  return function useStore() {
3342
3420
  const {
3343
3421
  store
@@ -6378,6 +6456,62 @@ const setLocale = createAsyncThunk('setLocale', (locale, {
6378
6456
  return true;
6379
6457
  }
6380
6458
  });
6459
+ ;// CONCATENATED MODULE: ./src/javascripts/domains/redux/create-debounced-async-thunk.ts
6460
+
6461
+ /**
6462
+ * A debounced analogue of the `createAsyncThunk` from `@reduxjs/toolkit`
6463
+ * @param typePrefix - a string action type value
6464
+ * @param payloadCreator - a callback function that should return a promise containing the result of some asynchronous logic
6465
+ * @param debounceOptions - the debounce options object
6466
+ */
6467
+ const createDebouncedAsyncThunk = (typePrefix, payloadCreator, debounceOptions) => {
6468
+ const {
6469
+ wait = 300,
6470
+ maxWait = 0,
6471
+ leading = false
6472
+ } = debounceOptions !== null && debounceOptions !== void 0 ? debounceOptions : {};
6473
+ let debounceTimer = null;
6474
+ let maxWaitTimer = null;
6475
+ let resolve;
6476
+ const cancel = () => {
6477
+ if (resolve) {
6478
+ resolve(false);
6479
+ resolve = undefined;
6480
+ }
6481
+ };
6482
+ const invoke = () => {
6483
+ clearTimeout(maxWaitTimer);
6484
+ maxWaitTimer = undefined;
6485
+ if (resolve) {
6486
+ resolve(true);
6487
+ resolve = undefined;
6488
+ }
6489
+ };
6490
+ const debounceExecutionCondition = () => {
6491
+ const immediate = leading && !debounceTimer;
6492
+ // Start debounced condition resolution
6493
+ clearTimeout(debounceTimer);
6494
+ debounceTimer = setTimeout(() => {
6495
+ invoke();
6496
+ debounceTimer = null;
6497
+ }, wait);
6498
+ if (immediate) {
6499
+ return true;
6500
+ }
6501
+ cancel();
6502
+ // Start max wait condition resolution
6503
+ if (maxWait && !maxWaitTimer) {
6504
+ maxWaitTimer = setTimeout(invoke, maxWait);
6505
+ }
6506
+ return new Promise(res => {
6507
+ resolve = res;
6508
+ });
6509
+ };
6510
+ return createAsyncThunk(typePrefix, payloadCreator, {
6511
+ condition: debounceExecutionCondition
6512
+ });
6513
+ };
6514
+ /* harmony default export */ const create_debounced_async_thunk = (createDebouncedAsyncThunk);
6381
6515
  ;// CONCATENATED MODULE: ./node_modules/reselect/es/defaultMemoize.js
6382
6516
  // Cache implementation based on Erik Rasmussen's `lru-memoize`:
6383
6517
  // https://github.com/erikras/lru-memoize
@@ -6934,8 +7068,9 @@ const setVisibility = createAsyncThunk('setVisibility', (requestedVisibility, {
6934
7068
  if (previousVisibility === calculatedVisibility) {
6935
7069
  return undefined;
6936
7070
  }
7071
+ const visibility = api.store.get(StoreKey);
6937
7072
  // Store the user-requested visibility in order to reinitialize after refresh
6938
- api.store.set(StoreKey, Object.assign(Object.assign({}, api.store.get(StoreKey) || {}), {
7073
+ api.store.set(StoreKey, Object.assign(Object.assign({}, visibility || {}), {
6939
7074
  [layoutMode]: requestedVisibility
6940
7075
  }));
6941
7076
  if (requestedVisibility) {
@@ -6999,6 +7134,7 @@ var app_actions_awaiter = undefined && undefined.__awaiter || function (thisArg,
6999
7134
 
7000
7135
 
7001
7136
 
7137
+
7002
7138
  const initializeApp = createAsyncThunk('initializeApp', (_, {
7003
7139
  extra: {
7004
7140
  api,
@@ -7064,14 +7200,14 @@ const initializeApp = createAsyncThunk('initializeApp', (_, {
7064
7200
  });
7065
7201
  }
7066
7202
  }));
7067
- const resetApp = createAsyncThunk('resetApp', (_, {
7203
+ const resetApp = create_debounced_async_thunk('resetApp', (_, {
7068
7204
  dispatch,
7069
7205
  extra: {
7070
7206
  api
7071
7207
  }
7072
7208
  }) => app_actions_awaiter(void 0, void 0, void 0, function* () {
7073
7209
  yield api.disconnect();
7074
- yield api.clearStore();
7210
+ api.clearStore();
7075
7211
  dispatch(resetConfig());
7076
7212
  yield dispatch(initializeConfig());
7077
7213
  try {
@@ -7079,11 +7215,14 @@ const resetApp = createAsyncThunk('resetApp', (_, {
7079
7215
  locale
7080
7216
  } = yield dispatch(initializeApp()).unwrap();
7081
7217
  yield dispatch(setLocale(locale));
7082
- } catch (rejectedValueOrSerializedError) {
7218
+ } catch (e) {
7083
7219
  // nothing to do
7084
7220
  }
7085
7221
  dispatch(initializeVisibility());
7086
- }));
7222
+ }), {
7223
+ wait: 2000,
7224
+ leading: true
7225
+ });
7087
7226
  ;// CONCATENATED MODULE: ./src/javascripts/domains/app/hooks.js
7088
7227
 
7089
7228
 
@@ -7119,12 +7258,75 @@ const {
7119
7258
  setHasResponded
7120
7259
  } = appSlice.actions;
7121
7260
  /* harmony default export */ const slice = (appSlice.reducer);
7261
+ ;// CONCATENATED MODULE: ./src/javascripts/domains/store/actions.ts
7262
+ var store_actions_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
7263
+ function adopt(value) {
7264
+ return value instanceof P ? value : new P(function (resolve) {
7265
+ resolve(value);
7266
+ });
7267
+ }
7268
+ return new (P || (P = Promise))(function (resolve, reject) {
7269
+ function fulfilled(value) {
7270
+ try {
7271
+ step(generator.next(value));
7272
+ } catch (e) {
7273
+ reject(e);
7274
+ }
7275
+ }
7276
+ function rejected(value) {
7277
+ try {
7278
+ step(generator["throw"](value));
7279
+ } catch (e) {
7280
+ reject(e);
7281
+ }
7282
+ }
7283
+ function step(result) {
7284
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
7285
+ }
7286
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
7287
+ });
7288
+ };
7289
+
7290
+ const getConversation = createAsyncThunk('getConversation', (_, {
7291
+ extra: {
7292
+ api
7293
+ },
7294
+ rejectWithValue
7295
+ }) => store_actions_awaiter(void 0, void 0, void 0, function* () {
7296
+ try {
7297
+ return api.getConversation();
7298
+ } catch (error) {
7299
+ return rejectWithValue({
7300
+ name: error === null || error === void 0 ? void 0 : error.name,
7301
+ message: error === null || error === void 0 ? void 0 : error.message,
7302
+ langKey: error === null || error === void 0 ? void 0 : error.langKey,
7303
+ action: error === null || error === void 0 ? void 0 : error.action,
7304
+ originalEvent: error === null || error === void 0 ? void 0 : error.originalEvent,
7305
+ originalError: error === null || error === void 0 ? void 0 : error.originalError
7306
+ });
7307
+ }
7308
+ }), {
7309
+ condition(payload, {
7310
+ getState
7311
+ }) {
7312
+ var _a;
7313
+ const {
7314
+ state: {
7315
+ events
7316
+ }
7317
+ } = getState();
7318
+ const lastEvent = events[events.length - 1];
7319
+ const payloadLastEventId = (_a = payload === null || payload === void 0 ? void 0 : payload.lastEvent) === null || _a === void 0 ? void 0 : _a.id;
7320
+ return lastEvent && payloadLastEventId !== lastEvent.payload.id;
7321
+ }
7322
+ });
7122
7323
  ;// CONCATENATED MODULE: ./src/javascripts/domains/interrupt/slice.ts
7123
7324
 
7124
7325
 
7125
7326
 
7126
7327
 
7127
7328
 
7329
+
7128
7330
  const slice_initialState = {
7129
7331
  error: undefined
7130
7332
  };
@@ -7138,7 +7340,7 @@ const interruptSlice = createSlice({
7138
7340
  clearInterrupt: () => slice_initialState
7139
7341
  },
7140
7342
  extraReducers: builder => {
7141
- builder.addCase(initializeConfig.pending, () => slice_initialState).addMatcher(isAnyOf(initializeApp.rejected, initializeConfig.rejected, setLocale.rejected, setVisibility.rejected, initializeVisibility.rejected), (state, {
7343
+ builder.addCase(initializeConfig.pending, () => slice_initialState).addMatcher(isAnyOf(initializeApp.rejected, initializeConfig.rejected, setLocale.rejected, setVisibility.rejected, initializeVisibility.rejected, getConversation.rejected), (state, {
7142
7344
  payload
7143
7345
  }) => {
7144
7346
  state.error = payload;
@@ -7775,7 +7977,7 @@ const {
7775
7977
  } = storeSlice.actions;
7776
7978
  /* harmony default export */ const store_slice = (storeSlice.reducer);
7777
7979
  ;// CONCATENATED MODULE: ./src/javascripts/domains/config/slice.ts
7778
- var __rest = undefined && undefined.__rest || function (s, e) {
7980
+ var slice_rest = undefined && undefined.__rest || function (s, e) {
7779
7981
  var t = {};
7780
7982
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
7781
7983
  if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
@@ -7818,7 +8020,7 @@ const updateState = (state, config) => {
7818
8020
  {
7819
8021
  messages
7820
8022
  } = _a,
7821
- partialConfig = __rest(_a, ["messages"]);
8023
+ partialConfig = slice_rest(_a, ["messages"]);
7822
8024
  let newState = state;
7823
8025
  if (Object.keys(partialConfig).length > 0) {
7824
8026
  newState = Object.assign(Object.assign({}, newState), partialConfig);
@@ -7852,13 +8054,15 @@ const configSlice = createSlice({
7852
8054
  preChat,
7853
8055
  agentParticipant,
7854
8056
  userParticipant,
7855
- startChatIcon
8057
+ startChatIcon,
8058
+ locale
7856
8059
  }
7857
8060
  }) => {
7858
8061
  state.preChatEvents = preChat.map(payload => ({
7859
8062
  type: 'message',
7860
8063
  payload
7861
8064
  }));
8065
+ state.context.locale = locale;
7862
8066
  state.agentParticipant = agentParticipant;
7863
8067
  state.userParticipant = userParticipant;
7864
8068
  state.startChatIcon = startChatIcon;
@@ -8300,7 +8504,13 @@ const translationSlice = createSlice({
8300
8504
  const feature = (_a = payload === null || payload === void 0 ? void 0 : payload.features) === null || _a === void 0 ? void 0 : _a.translation;
8301
8505
  if (!feature) return;
8302
8506
  state.isAvailable = feature.enabled === true;
8303
- state.languages = feature.languages;
8507
+ state.languages = [...feature.languages].sort((a, b) => {
8508
+ if (a.locale === payload.locale) return -1;
8509
+ if (b.locale === payload.locale) return 1;
8510
+ return a.nativeName.localeCompare(b.nativeName, undefined, {
8511
+ sensitivity: 'base'
8512
+ });
8513
+ });
8304
8514
  }).addCase(setHistory, (state, {
8305
8515
  payload
8306
8516
  }) => {
@@ -9536,6 +9746,9 @@ function useInterrupt() {
9536
9746
 
9537
9747
 
9538
9748
 
9749
+
9750
+
9751
+
9539
9752
  function useSessionExpiredCommand() {
9540
9753
  const {
9541
9754
  meta: {
@@ -9543,13 +9756,35 @@ function useSessionExpiredCommand() {
9543
9756
  action
9544
9757
  }
9545
9758
  } = useInterrupt();
9759
+ const dispatch = useAppDispatch();
9546
9760
  const seamlyCommands = use_seamly_commands();
9547
9761
  const isExpiredError = (originalError === null || originalError === void 0 ? void 0 : originalError.name) === 'SeamlySessionExpiredError';
9762
+ const limit = (0,hooks_.useRef)(0);
9763
+ const limitTimer = (0,hooks_.useRef)(null);
9548
9764
  (0,hooks_.useEffect)(() => {
9549
9765
  if (isExpiredError && seamlyCommands[action]) {
9766
+ if (limit.current >= 10) {
9767
+ limitTimer.current = setTimeout(() => {
9768
+ limit.current = 0;
9769
+ }, 10000);
9770
+ const error = new SeamlyGeneralError();
9771
+ dispatch(setInterrupt({
9772
+ name: error.name,
9773
+ message: error.message,
9774
+ langKey: error.langKey,
9775
+ originalEvent: error.originalEvent,
9776
+ originalError: error.originalError,
9777
+ action: error.action
9778
+ }));
9779
+ return () => {};
9780
+ }
9781
+ limit.current += 1;
9550
9782
  seamlyCommands[action]();
9551
9783
  }
9552
- }, [action, seamlyCommands, isExpiredError]);
9784
+ return () => {
9785
+ if (limitTimer.current) clearTimeout(limitTimer.current);
9786
+ };
9787
+ }, [action, seamlyCommands, isExpiredError, dispatch]);
9553
9788
  }
9554
9789
  ;// CONCATENATED MODULE: ./src/javascripts/ui/hooks/use-seamly-chat.ts
9555
9790
  var use_seamly_chat_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
@@ -10377,7 +10612,7 @@ const EventParticipant = ({
10377
10612
  })
10378
10613
  }));
10379
10614
  }
10380
- if (showName) {
10615
+ if (showName && participantName) {
10381
10616
  authorInfo.push((0,jsx_runtime_namespaceObject.jsx)("span", {
10382
10617
  className: css_className('message__author-name'),
10383
10618
  children: participantName
@@ -10457,108 +10692,61 @@ function MessageContainer({
10457
10692
  });
10458
10693
  }
10459
10694
  /* harmony default export */ const message_container = (MessageContainer);
10460
- ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-component.js
10695
+ ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-component.tsx
10461
10696
 
10462
10697
 
10463
10698
 
10464
10699
 
10465
10700
 
10466
-
10467
- const CardComponent = ({
10468
- id,
10469
- action,
10470
- buttonText,
10471
- description,
10472
- hasFocus,
10473
- image,
10474
- title,
10475
- isCarouselItem
10476
- }) => {
10477
- const cardRef = (0,hooks_.useRef)(null);
10478
- const {
10479
- sendMessage,
10480
- sendAction,
10481
- emitEvent
10482
- } = use_seamly_commands();
10483
- const descriptionId = useGeneratedId();
10484
- const isMounted = (0,hooks_.useRef)();
10485
- const CardActionComponent = action.type === cardTypes.navigate ? 'a' : 'button';
10486
- const emitCardEvent = (0,hooks_.useCallback)(() => emitEvent(`action.${actionTypes.clickCard}`, {
10487
- type: actionTypes.clickCta,
10488
- originMessage: id,
10489
- action
10490
- }), [emitEvent, id, action]);
10491
- const handleClick = (0,hooks_.useCallback)(() => {
10492
- emitCardEvent();
10493
- if (action.type === cardTypes.ask) {
10494
- sendMessage({
10495
- body: action.ask
10496
- });
10497
- } else if (action.type === cardTypes.topic) {
10498
- const {
10499
- topic: name,
10500
- fallbackMessage
10501
- } = action;
10502
- sendAction({
10503
- type: actionTypes.setTopic,
10504
- body: {
10505
- name,
10506
- fallbackMessage
10701
+ const CardComponent = ({ id, action, buttonText, description, hasFocus, image, title, isCarouselItem, }) => {
10702
+ const cardRef = (0,hooks_.useRef)(null);
10703
+ const { sendMessage, sendAction, emitEvent } = use_seamly_commands();
10704
+ const descriptionId = useGeneratedId();
10705
+ const isMounted = (0,hooks_.useRef)(false);
10706
+ const CardActionComponent = action.type === cardTypes.navigate ? 'a' : 'button';
10707
+ const emitCardEvent = (0,hooks_.useCallback)(() => emitEvent(`action.${actionTypes.clickCard}`, {
10708
+ type: actionTypes.clickCta,
10709
+ originMessage: id,
10710
+ action,
10711
+ }), [emitEvent, id, action]);
10712
+ const handleClick = (0,hooks_.useCallback)(() => {
10713
+ emitCardEvent();
10714
+ if (action.type === cardTypes.ask) {
10715
+ sendMessage({ body: action.ask });
10507
10716
  }
10508
- });
10509
- }
10510
- }, [sendMessage, action, sendAction, emitCardEvent]);
10511
- const actionProps = (0,hooks_.useMemo)(() => action.type === cardTypes.navigate ? {
10512
- href: action.link,
10513
- rel: 'noopener noreferrer',
10514
- target: action.newTab ? '_blank' : '_self',
10515
- onClick: emitCardEvent
10516
- } : {
10517
- onClick: handleClick
10518
- }, [action, handleClick, emitCardEvent]);
10519
- (0,hooks_.useEffect)(() => {
10520
- if (isCarouselItem) {
10521
- if (hasFocus && isMounted.current) {
10522
- window.requestAnimationFrame(() => cardRef.current.focus());
10523
- } else {
10524
- cardRef.current.blur();
10525
- }
10526
- }
10527
- isMounted.current = true;
10528
- }, [hasFocus, isCarouselItem]);
10529
- return (0,jsx_runtime_namespaceObject.jsxs)("div", {
10530
- className: css_className('card__wrapper'),
10531
- id: id,
10532
- tabIndex: "-1" // set tabIndex of -1 so card can be focussed
10533
- ,
10534
- ref: cardRef,
10535
- children: [(0,jsx_runtime_namespaceObject.jsx)("img", {
10536
- className: css_className('card__image'),
10537
- src: image,
10538
- alt: ""
10539
- }), (0,jsx_runtime_namespaceObject.jsxs)("div", {
10540
- className: css_className('card__content'),
10541
- id: id,
10542
- children: [title && (0,jsx_runtime_namespaceObject.jsx)("h2", {
10543
- className: css_className('card__title'),
10544
- children: title
10545
- }), description && (0,jsx_runtime_namespaceObject.jsx)("div", {
10546
- className: css_className('card__description'),
10547
- dangerouslySetInnerHTML: {
10548
- __html: description
10717
+ else if (action.type === cardTypes.topic) {
10718
+ const { topic: name, fallbackMessage } = action;
10719
+ sendAction({
10720
+ type: actionTypes.setTopic,
10721
+ body: { name, fallbackMessage },
10722
+ });
10549
10723
  }
10550
- }), (0,jsx_runtime_namespaceObject.jsx)(CardActionComponent, {
10551
- tabIndex: isCarouselItem && !hasFocus ? '-1' : undefined // disable to prevent tabbing through cards
10552
- ,
10553
- className: css_className('button', 'button--primary'),
10554
- "aria-describedby": descriptionId,
10555
- ...actionProps,
10556
- children: buttonText
10557
- })]
10558
- })]
10559
- });
10724
+ }, [sendMessage, action, sendAction, emitCardEvent]);
10725
+ const actionProps = (0,hooks_.useMemo)(() => action.type === cardTypes.navigate
10726
+ ? {
10727
+ href: action.link,
10728
+ rel: 'noopener noreferrer',
10729
+ target: action.newTab ? '_blank' : '_self',
10730
+ onClick: emitCardEvent,
10731
+ }
10732
+ : {
10733
+ onClick: handleClick,
10734
+ }, [action, handleClick, emitCardEvent]);
10735
+ (0,hooks_.useEffect)(() => {
10736
+ if (isCarouselItem) {
10737
+ if (hasFocus && isMounted.current) {
10738
+ window.requestAnimationFrame(() => cardRef.current.focus());
10739
+ }
10740
+ else {
10741
+ cardRef.current.blur();
10742
+ }
10743
+ }
10744
+ isMounted.current = true;
10745
+ }, [hasFocus, isCarouselItem]);
10746
+ 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 }))] })] }));
10560
10747
  };
10561
10748
  /* harmony default export */ const card_component = (CardComponent);
10749
+
10562
10750
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/conversation/event/card-message.js
10563
10751
 
10564
10752
 
@@ -11578,7 +11766,7 @@ const TimeIndicator = ({
11578
11766
  /* harmony default export */ const time_indicator = (TimeIndicator);
11579
11767
  ;// CONCATENATED MODULE: ./node_modules/tabbable/dist/index.esm.js
11580
11768
  /*!
11581
- * tabbable 6.1.2
11769
+ * tabbable 6.2.0
11582
11770
  * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
11583
11771
  */
11584
11772
  // NOTE: separate `:not()` selectors has broader browser support than the newer
@@ -11758,7 +11946,27 @@ var getCandidatesIteratively = function getCandidatesIteratively(elements, inclu
11758
11946
  }
11759
11947
  return candidates;
11760
11948
  };
11761
- var getTabindex = function getTabindex(node, isScope) {
11949
+
11950
+ /**
11951
+ * @private
11952
+ * Determines if the node has an explicitly specified `tabindex` attribute.
11953
+ * @param {HTMLElement} node
11954
+ * @returns {boolean} True if so; false if not.
11955
+ */
11956
+ var hasTabIndex = function hasTabIndex(node) {
11957
+ return !isNaN(parseInt(node.getAttribute('tabindex'), 10));
11958
+ };
11959
+
11960
+ /**
11961
+ * Determine the tab index of a given node.
11962
+ * @param {HTMLElement} node
11963
+ * @returns {number} Tab order (negative, 0, or positive number).
11964
+ * @throws {Error} If `node` is falsy.
11965
+ */
11966
+ var getTabIndex = function getTabIndex(node) {
11967
+ if (!node) {
11968
+ throw new Error('No node provided');
11969
+ }
11762
11970
  if (node.tabIndex < 0) {
11763
11971
  // in Chrome, <details/>, <audio controls/> and <video controls/> elements get a default
11764
11972
  // `tabIndex` of -1 when the 'tabindex' attribute isn't specified in the DOM,
@@ -11767,16 +11975,28 @@ var getTabindex = function getTabindex(node, isScope) {
11767
11975
  // order, consider their tab index to be 0.
11768
11976
  // Also browsers do not return `tabIndex` correctly for contentEditable nodes;
11769
11977
  // so if they don't have a tabindex attribute specifically set, assume it's 0.
11770
- //
11771
- // isScope is positive for custom element with shadow root or slot that by default
11772
- // have tabIndex -1, but need to be sorted by document order in order for their
11773
- // content to be inserted in the correct position
11774
- if ((isScope || /^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || isContentEditable(node)) && isNaN(parseInt(node.getAttribute('tabindex'), 10))) {
11978
+ if ((/^(AUDIO|VIDEO|DETAILS)$/.test(node.tagName) || isContentEditable(node)) && !hasTabIndex(node)) {
11775
11979
  return 0;
11776
11980
  }
11777
11981
  }
11778
11982
  return node.tabIndex;
11779
11983
  };
11984
+
11985
+ /**
11986
+ * Determine the tab index of a given node __for sort order purposes__.
11987
+ * @param {HTMLElement} node
11988
+ * @param {boolean} [isScope] True for a custom element with shadow root or slot that, by default,
11989
+ * has tabIndex -1, but needs to be sorted by document order in order for its content to be
11990
+ * inserted into the correct sort position.
11991
+ * @returns {number} Tab order (negative, 0, or positive number).
11992
+ */
11993
+ var getSortOrderTabIndex = function getSortOrderTabIndex(node, isScope) {
11994
+ var tabIndex = getTabIndex(node);
11995
+ if (tabIndex < 0 && isScope && !hasTabIndex(node)) {
11996
+ return 0;
11997
+ }
11998
+ return tabIndex;
11999
+ };
11780
12000
  var sortOrderedTabbables = function sortOrderedTabbables(a, b) {
11781
12001
  return a.tabIndex === b.tabIndex ? a.documentOrder - b.documentOrder : a.tabIndex - b.tabIndex;
11782
12002
  };
@@ -12019,7 +12239,7 @@ var isNodeMatchingSelectorFocusable = function isNodeMatchingSelectorFocusable(o
12019
12239
  return true;
12020
12240
  };
12021
12241
  var isNodeMatchingSelectorTabbable = function isNodeMatchingSelectorTabbable(options, node) {
12022
- if (isNonTabbableRadio(node) || getTabindex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) {
12242
+ if (isNonTabbableRadio(node) || getTabIndex(node) < 0 || !isNodeMatchingSelectorFocusable(options, node)) {
12023
12243
  return false;
12024
12244
  }
12025
12245
  return true;
@@ -12044,7 +12264,7 @@ var sortByOrder = function sortByOrder(candidates) {
12044
12264
  candidates.forEach(function (item, i) {
12045
12265
  var isScope = !!item.scopeParent;
12046
12266
  var element = isScope ? item.scopeParent : item;
12047
- var candidateTabindex = getTabindex(element, isScope);
12267
+ var candidateTabindex = getSortOrderTabIndex(element, isScope);
12048
12268
  var elements = isScope ? sortByOrder(item.candidates) : element;
12049
12269
  if (candidateTabindex === 0) {
12050
12270
  isScope ? regularTabbables.push.apply(regularTabbables, elements) : regularTabbables.push(element);
@@ -12063,32 +12283,32 @@ var sortByOrder = function sortByOrder(candidates) {
12063
12283
  return acc;
12064
12284
  }, []).concat(regularTabbables);
12065
12285
  };
12066
- var tabbable = function tabbable(el, options) {
12286
+ var tabbable = function tabbable(container, options) {
12067
12287
  options = options || {};
12068
12288
  var candidates;
12069
12289
  if (options.getShadowRoot) {
12070
- candidates = getCandidatesIteratively([el], options.includeContainer, {
12290
+ candidates = getCandidatesIteratively([container], options.includeContainer, {
12071
12291
  filter: isNodeMatchingSelectorTabbable.bind(null, options),
12072
12292
  flatten: false,
12073
12293
  getShadowRoot: options.getShadowRoot,
12074
12294
  shadowRootFilter: isValidShadowRootTabbable
12075
12295
  });
12076
12296
  } else {
12077
- candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
12297
+ candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorTabbable.bind(null, options));
12078
12298
  }
12079
12299
  return sortByOrder(candidates);
12080
12300
  };
12081
- var focusable = function focusable(el, options) {
12301
+ var focusable = function focusable(container, options) {
12082
12302
  options = options || {};
12083
12303
  var candidates;
12084
12304
  if (options.getShadowRoot) {
12085
- candidates = getCandidatesIteratively([el], options.includeContainer, {
12305
+ candidates = getCandidatesIteratively([container], options.includeContainer, {
12086
12306
  filter: isNodeMatchingSelectorFocusable.bind(null, options),
12087
12307
  flatten: true,
12088
12308
  getShadowRoot: options.getShadowRoot
12089
12309
  });
12090
12310
  } else {
12091
- candidates = getCandidates(el, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
12311
+ candidates = getCandidates(container, options.includeContainer, isNodeMatchingSelectorFocusable.bind(null, options));
12092
12312
  }
12093
12313
  return candidates;
12094
12314
  };
@@ -12119,7 +12339,7 @@ var isFocusable = function isFocusable(node, options) {
12119
12339
 
12120
12340
  ;// CONCATENATED MODULE: ./node_modules/focus-trap/dist/focus-trap.esm.js
12121
12341
  /*!
12122
- * focus-trap 7.4.3
12342
+ * focus-trap 7.5.2
12123
12343
  * @license MIT, https://github.com/focus-trap/focus-trap/blob/master/LICENSE
12124
12344
  */
12125
12345
 
@@ -12205,10 +12425,10 @@ var isSelectableInput = function isSelectableInput(node) {
12205
12425
  return node.tagName && node.tagName.toLowerCase() === 'input' && typeof node.select === 'function';
12206
12426
  };
12207
12427
  var isEscapeEvent = function isEscapeEvent(e) {
12208
- return e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27;
12428
+ 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;
12209
12429
  };
12210
12430
  var isTabEvent = function isTabEvent(e) {
12211
- return e.key === 'Tab' || e.keyCode === 9;
12431
+ return (e === null || e === void 0 ? void 0 : e.key) === 'Tab' || (e === null || e === void 0 ? void 0 : e.keyCode) === 9;
12212
12432
  };
12213
12433
 
12214
12434
  // checks for TAB by default
@@ -12292,8 +12512,11 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12292
12512
  // container: HTMLElement,
12293
12513
  // tabbableNodes: Array<HTMLElement>, // empty if none
12294
12514
  // focusableNodes: Array<HTMLElement>, // empty if none
12295
- // firstTabbableNode: HTMLElement|null,
12296
- // lastTabbableNode: HTMLElement|null,
12515
+ // posTabIndexesFound: boolean,
12516
+ // firstTabbableNode: HTMLElement|undefined,
12517
+ // lastTabbableNode: HTMLElement|undefined,
12518
+ // firstDomTabbableNode: HTMLElement|undefined,
12519
+ // lastDomTabbableNode: HTMLElement|undefined,
12297
12520
  // nextTabbableNode: (node: HTMLElement, forward: boolean) => HTMLElement|undefined
12298
12521
  // }>}
12299
12522
  containerGroups: [],
@@ -12310,7 +12533,9 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12310
12533
  paused: false,
12311
12534
  // timer ID for when delayInitialFocus is true and initial focus in this trap
12312
12535
  // has been delayed during activation
12313
- delayInitialFocusTimer: undefined
12536
+ delayInitialFocusTimer: undefined,
12537
+ // the most recent KeyboardEvent for the configured nav key (typically [SHIFT+]TAB), if any
12538
+ recentNavEvent: undefined
12314
12539
  };
12315
12540
  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
12316
12541
 
@@ -12329,7 +12554,9 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12329
12554
  /**
12330
12555
  * Finds the index of the container that contains the element.
12331
12556
  * @param {HTMLElement} element
12332
- * @param {Event} [event]
12557
+ * @param {Event} [event] If available, and `element` isn't directly found in any container,
12558
+ * the event's composed path is used to see if includes any known trap containers in the
12559
+ * case where the element is inside a Shadow DOM.
12333
12560
  * @returns {number} Index of the container in either `state.containers` or
12334
12561
  * `state.containerGroups` (the order/length of these lists are the same); -1
12335
12562
  * if the element isn't found.
@@ -12424,14 +12651,41 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12424
12651
  var tabbableNodes = tabbable(container, config.tabbableOptions);
12425
12652
 
12426
12653
  // NOTE: if we have tabbable nodes, we must have focusable nodes; focusable nodes
12427
- // are a superset of tabbable nodes
12654
+ // are a superset of tabbable nodes since nodes with negative `tabindex` attributes
12655
+ // are focusable but not tabbable
12428
12656
  var focusableNodes = focusable(container, config.tabbableOptions);
12657
+ var firstTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[0] : undefined;
12658
+ var lastTabbableNode = tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : undefined;
12659
+ var firstDomTabbableNode = focusableNodes.find(function (node) {
12660
+ return isTabbable(node);
12661
+ });
12662
+ var lastDomTabbableNode = focusableNodes.slice().reverse().find(function (node) {
12663
+ return isTabbable(node);
12664
+ });
12665
+ var posTabIndexesFound = !!tabbableNodes.find(function (node) {
12666
+ return getTabIndex(node) > 0;
12667
+ });
12429
12668
  return {
12430
12669
  container: container,
12431
12670
  tabbableNodes: tabbableNodes,
12432
12671
  focusableNodes: focusableNodes,
12433
- firstTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[0] : null,
12434
- lastTabbableNode: tabbableNodes.length > 0 ? tabbableNodes[tabbableNodes.length - 1] : null,
12672
+ /** True if at least one node with positive `tabindex` was found in this container. */
12673
+ posTabIndexesFound: posTabIndexesFound,
12674
+ /** First tabbable node in container, __tabindex__ order; `undefined` if none. */
12675
+ firstTabbableNode: firstTabbableNode,
12676
+ /** Last tabbable node in container, __tabindex__ order; `undefined` if none. */
12677
+ lastTabbableNode: lastTabbableNode,
12678
+ // NOTE: DOM order is NOT NECESSARILY "document position" order, but figuring that out
12679
+ // would require more than just https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition
12680
+ // because that API doesn't work with Shadow DOM as well as it should (@see
12681
+ // https://github.com/whatwg/dom/issues/320) and since this first/last is only needed, so far,
12682
+ // to address an edge case related to positive tabindex support, this seems like a much easier,
12683
+ // "close enough most of the time" alternative for positive tabindexes which should generally
12684
+ // be avoided anyway...
12685
+ /** First tabbable node in container, __DOM__ order; `undefined` if none. */
12686
+ firstDomTabbableNode: firstDomTabbableNode,
12687
+ /** Last tabbable node in container, __DOM__ order; `undefined` if none. */
12688
+ lastDomTabbableNode: lastDomTabbableNode,
12435
12689
  /**
12436
12690
  * Finds the __tabbable__ node that follows the given node in the specified direction,
12437
12691
  * in this container, if any.
@@ -12442,30 +12696,24 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12442
12696
  */
12443
12697
  nextTabbableNode: function nextTabbableNode(node) {
12444
12698
  var forward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
12445
- // NOTE: If tabindex is positive (in order to manipulate the tab order separate
12446
- // from the DOM order), this __will not work__ because the list of focusableNodes,
12447
- // while it contains tabbable nodes, does not sort its nodes in any order other
12448
- // than DOM order, because it can't: Where would you place focusable (but not
12449
- // tabbable) nodes in that order? They have no order, because they aren't tabbale...
12450
- // Support for positive tabindex is already broken and hard to manage (possibly
12451
- // not supportable, TBD), so this isn't going to make things worse than they
12452
- // already are, and at least makes things better for the majority of cases where
12453
- // tabindex is either 0/unset or negative.
12454
- // FYI, positive tabindex issue: https://github.com/focus-trap/focus-trap/issues/375
12455
- var nodeIdx = focusableNodes.findIndex(function (n) {
12456
- return n === node;
12457
- });
12699
+ var nodeIdx = tabbableNodes.indexOf(node);
12458
12700
  if (nodeIdx < 0) {
12459
- return undefined;
12460
- }
12461
- if (forward) {
12462
- return focusableNodes.slice(nodeIdx + 1).find(function (n) {
12463
- return isTabbable(n, config.tabbableOptions);
12701
+ // either not tabbable nor focusable, or was focused but not tabbable (negative tabindex):
12702
+ // since `node` should at least have been focusable, we assume that's the case and mimic
12703
+ // what browsers do, which is set focus to the next node in __document position order__,
12704
+ // regardless of positive tabindexes, if any -- and for reasons explained in the NOTE
12705
+ // above related to `firstDomTabbable` and `lastDomTabbable` properties, we fall back to
12706
+ // basic DOM order
12707
+ if (forward) {
12708
+ return focusableNodes.slice(focusableNodes.indexOf(node) + 1).find(function (el) {
12709
+ return isTabbable(el);
12710
+ });
12711
+ }
12712
+ return focusableNodes.slice(0, focusableNodes.indexOf(node)).reverse().find(function (el) {
12713
+ return isTabbable(el);
12464
12714
  });
12465
12715
  }
12466
- return focusableNodes.slice(0, nodeIdx).reverse().find(function (n) {
12467
- return isTabbable(n, config.tabbableOptions);
12468
- });
12716
+ return tabbableNodes[nodeIdx + (forward ? 1 : -1)];
12469
12717
  }
12470
12718
  };
12471
12719
  });
@@ -12478,6 +12726,19 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12478
12726
  ) {
12479
12727
  throw new Error('Your focus-trap must have at least one container with at least one tabbable node in it at all times');
12480
12728
  }
12729
+
12730
+ // NOTE: Positive tabindexes are only properly supported in single-container traps because
12731
+ // doing it across multiple containers where tabindexes could be all over the place
12732
+ // would require Tabbable to support multiple containers, would require additional
12733
+ // specialized Shadow DOM support, and would require Tabbable's multi-container support
12734
+ // to look at those containers in document position order rather than user-provided
12735
+ // order (as they are treated in Focus-trap, for legacy reasons). See discussion on
12736
+ // https://github.com/focus-trap/focus-trap/issues/375 for more details.
12737
+ if (state.containerGroups.find(function (g) {
12738
+ return g.posTabIndexesFound;
12739
+ }) && state.containerGroups.length > 1) {
12740
+ 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.");
12741
+ }
12481
12742
  };
12482
12743
  var tryFocus = function tryFocus(node) {
12483
12744
  if (node === false) {
@@ -12493,6 +12754,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12493
12754
  node.focus({
12494
12755
  preventScroll: !!config.preventScroll
12495
12756
  });
12757
+ // NOTE: focus() API does not trigger focusIn event so set MRU node manually
12496
12758
  state.mostRecentlyFocusedNode = node;
12497
12759
  if (isSelectableInput(node)) {
12498
12760
  node.select();
@@ -12503,64 +12765,23 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12503
12765
  return node ? node : node === false ? false : previousActiveElement;
12504
12766
  };
12505
12767
 
12506
- // This needs to be done on mousedown and touchstart instead of click
12507
- // so that it precedes the focus event.
12508
- var checkPointerDown = function checkPointerDown(e) {
12509
- var target = getActualTarget(e);
12510
- if (findContainerIndex(target, e) >= 0) {
12511
- // allow the click since it ocurred inside the trap
12512
- return;
12513
- }
12514
- if (valueOrHandler(config.clickOutsideDeactivates, e)) {
12515
- // immediately deactivate the trap
12516
- trap.deactivate({
12517
- // NOTE: by setting `returnFocus: false`, deactivate() will do nothing,
12518
- // which will result in the outside click setting focus to the node
12519
- // that was clicked (and if not focusable, to "nothing"); by setting
12520
- // `returnFocus: true`, we'll attempt to re-focus the node originally-focused
12521
- // on activation (or the configured `setReturnFocus` node), whether the
12522
- // outside click was on a focusable node or not
12523
- returnFocus: config.returnFocusOnDeactivate
12524
- });
12525
- return;
12526
- }
12527
-
12528
- // This is needed for mobile devices.
12529
- // (If we'll only let `click` events through,
12530
- // then on mobile they will be blocked anyways if `touchstart` is blocked.)
12531
- if (valueOrHandler(config.allowOutsideClick, e)) {
12532
- // allow the click outside the trap to take place
12533
- return;
12534
- }
12535
-
12536
- // otherwise, prevent the click
12537
- e.preventDefault();
12538
- };
12539
-
12540
- // In case focus escapes the trap for some strange reason, pull it back in.
12541
- var checkFocusIn = function checkFocusIn(e) {
12542
- var target = getActualTarget(e);
12543
- var targetContained = findContainerIndex(target, e) >= 0;
12544
-
12545
- // In Firefox when you Tab out of an iframe the Document is briefly focused.
12546
- if (targetContained || target instanceof Document) {
12547
- if (targetContained) {
12548
- state.mostRecentlyFocusedNode = target;
12549
- }
12550
- } else {
12551
- // escaped! pull it back in to where it just left
12552
- e.stopImmediatePropagation();
12553
- tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
12554
- }
12555
- };
12556
-
12557
- // Hijack key nav events on the first and last focusable nodes of the trap,
12558
- // in order to prevent focus from escaping. If it escapes for even a
12559
- // moment it can end up scrolling the page and causing confusion so we
12560
- // kind of need to capture the action at the keydown phase.
12561
- var checkKeyNav = function checkKeyNav(event) {
12562
- var isBackward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
12563
- var target = getActualTarget(event);
12768
+ /**
12769
+ * Finds the next node (in either direction) where focus should move according to a
12770
+ * keyboard focus-in event.
12771
+ * @param {Object} params
12772
+ * @param {Node} [params.target] Known target __from which__ to navigate, if any.
12773
+ * @param {KeyboardEvent|FocusEvent} [params.event] Event to use if `target` isn't known (event
12774
+ * will be used to determine the `target`). Ignored if `target` is specified.
12775
+ * @param {boolean} [params.isBackward] True if focus should move backward.
12776
+ * @returns {Node|undefined} The next node, or `undefined` if a next node couldn't be
12777
+ * determined given the current state of the trap.
12778
+ */
12779
+ var findNextNavNode = function findNextNavNode(_ref2) {
12780
+ var target = _ref2.target,
12781
+ event = _ref2.event,
12782
+ _ref2$isBackward = _ref2.isBackward,
12783
+ isBackward = _ref2$isBackward === void 0 ? false : _ref2$isBackward;
12784
+ target = target || getActualTarget(event);
12564
12785
  updateTabbableNodes();
12565
12786
  var destinationNode = null;
12566
12787
  if (state.tabbableGroups.length > 0) {
@@ -12583,8 +12804,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12583
12804
  // REVERSE
12584
12805
 
12585
12806
  // is the target the first tabbable node in a group?
12586
- var startOfGroupIndex = findIndex(state.tabbableGroups, function (_ref2) {
12587
- var firstTabbableNode = _ref2.firstTabbableNode;
12807
+ var startOfGroupIndex = findIndex(state.tabbableGroups, function (_ref3) {
12808
+ var firstTabbableNode = _ref3.firstTabbableNode;
12588
12809
  return target === firstTabbableNode;
12589
12810
  });
12590
12811
  if (startOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target, false))) {
@@ -12602,7 +12823,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12602
12823
  // the LAST group if it's the first tabbable node of the FIRST group)
12603
12824
  var destinationGroupIndex = startOfGroupIndex === 0 ? state.tabbableGroups.length - 1 : startOfGroupIndex - 1;
12604
12825
  var destinationGroup = state.tabbableGroups[destinationGroupIndex];
12605
- destinationNode = destinationGroup.lastTabbableNode;
12826
+ destinationNode = getTabIndex(target) >= 0 ? destinationGroup.lastTabbableNode : destinationGroup.lastDomTabbableNode;
12606
12827
  } else if (!isTabEvent(event)) {
12607
12828
  // user must have customized the nav keys so we have to move focus manually _within_
12608
12829
  // the active group: do this based on the order determined by tabbable()
@@ -12612,8 +12833,8 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12612
12833
  // FORWARD
12613
12834
 
12614
12835
  // is the target the last tabbable node in a group?
12615
- var lastOfGroupIndex = findIndex(state.tabbableGroups, function (_ref3) {
12616
- var lastTabbableNode = _ref3.lastTabbableNode;
12836
+ var lastOfGroupIndex = findIndex(state.tabbableGroups, function (_ref4) {
12837
+ var lastTabbableNode = _ref4.lastTabbableNode;
12617
12838
  return target === lastTabbableNode;
12618
12839
  });
12619
12840
  if (lastOfGroupIndex < 0 && (containerGroup.container === target || isFocusable(target, config.tabbableOptions) && !isTabbable(target, config.tabbableOptions) && !containerGroup.nextTabbableNode(target))) {
@@ -12631,7 +12852,7 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12631
12852
  // group if it's the last tabbable node of the LAST group)
12632
12853
  var _destinationGroupIndex = lastOfGroupIndex === state.tabbableGroups.length - 1 ? 0 : lastOfGroupIndex + 1;
12633
12854
  var _destinationGroup = state.tabbableGroups[_destinationGroupIndex];
12634
- destinationNode = _destinationGroup.firstTabbableNode;
12855
+ destinationNode = getTabIndex(target) >= 0 ? _destinationGroup.firstTabbableNode : _destinationGroup.firstDomTabbableNode;
12635
12856
  } else if (!isTabEvent(event)) {
12636
12857
  // user must have customized the nav keys so we have to move focus manually _within_
12637
12858
  // the active group: do this based on the order determined by tabbable()
@@ -12643,6 +12864,153 @@ var createFocusTrap = function createFocusTrap(elements, userOptions) {
12643
12864
  // NOTE: the fallbackFocus option does not support returning false to opt-out
12644
12865
  destinationNode = getNodeForOption('fallbackFocus');
12645
12866
  }
12867
+ return destinationNode;
12868
+ };
12869
+
12870
+ // This needs to be done on mousedown and touchstart instead of click
12871
+ // so that it precedes the focus event.
12872
+ var checkPointerDown = function checkPointerDown(e) {
12873
+ var target = getActualTarget(e);
12874
+ if (findContainerIndex(target, e) >= 0) {
12875
+ // allow the click since it ocurred inside the trap
12876
+ return;
12877
+ }
12878
+ if (valueOrHandler(config.clickOutsideDeactivates, e)) {
12879
+ // immediately deactivate the trap
12880
+ trap.deactivate({
12881
+ // NOTE: by setting `returnFocus: false`, deactivate() will do nothing,
12882
+ // which will result in the outside click setting focus to the node
12883
+ // that was clicked (and if not focusable, to "nothing"); by setting
12884
+ // `returnFocus: true`, we'll attempt to re-focus the node originally-focused
12885
+ // on activation (or the configured `setReturnFocus` node), whether the
12886
+ // outside click was on a focusable node or not
12887
+ returnFocus: config.returnFocusOnDeactivate
12888
+ });
12889
+ return;
12890
+ }
12891
+
12892
+ // This is needed for mobile devices.
12893
+ // (If we'll only let `click` events through,
12894
+ // then on mobile they will be blocked anyways if `touchstart` is blocked.)
12895
+ if (valueOrHandler(config.allowOutsideClick, e)) {
12896
+ // allow the click outside the trap to take place
12897
+ return;
12898
+ }
12899
+
12900
+ // otherwise, prevent the click
12901
+ e.preventDefault();
12902
+ };
12903
+
12904
+ // In case focus escapes the trap for some strange reason, pull it back in.
12905
+ // NOTE: the focusIn event is NOT cancelable, so if focus escapes, it may cause unexpected
12906
+ // scrolling if the node that got focused was out of view; there's nothing we can do to
12907
+ // prevent that from happening by the time we discover that focus escaped
12908
+ var checkFocusIn = function checkFocusIn(event) {
12909
+ var target = getActualTarget(event);
12910
+ var targetContained = findContainerIndex(target, event) >= 0;
12911
+
12912
+ // In Firefox when you Tab out of an iframe the Document is briefly focused.
12913
+ if (targetContained || target instanceof Document) {
12914
+ if (targetContained) {
12915
+ state.mostRecentlyFocusedNode = target;
12916
+ }
12917
+ } else {
12918
+ // escaped! pull it back in to where it just left
12919
+ event.stopImmediatePropagation();
12920
+
12921
+ // focus will escape if the MRU node had a positive tab index and user tried to nav forward;
12922
+ // it will also escape if the MRU node had a 0 tab index and user tried to nav backward
12923
+ // toward a node with a positive tab index
12924
+ var nextNode; // next node to focus, if we find one
12925
+ var navAcrossContainers = true;
12926
+ if (state.mostRecentlyFocusedNode) {
12927
+ if (getTabIndex(state.mostRecentlyFocusedNode) > 0) {
12928
+ // MRU container index must be >=0 otherwise we wouldn't have it as an MRU node...
12929
+ var mruContainerIdx = findContainerIndex(state.mostRecentlyFocusedNode);
12930
+ // there MAY not be any tabbable nodes in the container if there are at least 2 containers
12931
+ // and the MRU node is focusable but not tabbable (focus-trap requires at least 1 container
12932
+ // with at least one tabbable node in order to function, so this could be the other container
12933
+ // with nothing tabbable in it)
12934
+ var tabbableNodes = state.containerGroups[mruContainerIdx].tabbableNodes;
12935
+ if (tabbableNodes.length > 0) {
12936
+ // MRU tab index MAY not be found if the MRU node is focusable but not tabbable
12937
+ var mruTabIdx = tabbableNodes.findIndex(function (node) {
12938
+ return node === state.mostRecentlyFocusedNode;
12939
+ });
12940
+ if (mruTabIdx >= 0) {
12941
+ if (config.isKeyForward(state.recentNavEvent)) {
12942
+ if (mruTabIdx + 1 < tabbableNodes.length) {
12943
+ nextNode = tabbableNodes[mruTabIdx + 1];
12944
+ navAcrossContainers = false;
12945
+ }
12946
+ // else, don't wrap within the container as focus should move to next/previous
12947
+ // container
12948
+ } else {
12949
+ if (mruTabIdx - 1 >= 0) {
12950
+ nextNode = tabbableNodes[mruTabIdx - 1];
12951
+ navAcrossContainers = false;
12952
+ }
12953
+ // else, don't wrap within the container as focus should move to next/previous
12954
+ // container
12955
+ }
12956
+ // else, don't find in container order without considering direction too
12957
+ }
12958
+ }
12959
+ // else, no tabbable nodes in that container (which means we must have at least one other
12960
+ // container with at least one tabbable node in it, otherwise focus-trap would've thrown
12961
+ // an error the last time updateTabbableNodes() was run): find next node among all known
12962
+ // containers
12963
+ } else {
12964
+ // check to see if there's at least one tabbable node with a positive tab index inside
12965
+ // the trap because focus seems to escape when navigating backward from a tabbable node
12966
+ // with tabindex=0 when this is the case (instead of wrapping to the tabbable node with
12967
+ // the greatest positive tab index like it should)
12968
+ if (!state.containerGroups.some(function (g) {
12969
+ return g.tabbableNodes.some(function (n) {
12970
+ return getTabIndex(n) > 0;
12971
+ });
12972
+ })) {
12973
+ // no containers with tabbable nodes with positive tab indexes which means the focus
12974
+ // escaped for some other reason and we should just execute the fallback to the
12975
+ // MRU node or initial focus node, if any
12976
+ navAcrossContainers = false;
12977
+ }
12978
+ }
12979
+ } else {
12980
+ // no MRU node means we're likely in some initial condition when the trap has just
12981
+ // been activated and initial focus hasn't been given yet, in which case we should
12982
+ // fall through to trying to focus the initial focus node, which is what should
12983
+ // happen below at this point in the logic
12984
+ navAcrossContainers = false;
12985
+ }
12986
+ if (navAcrossContainers) {
12987
+ nextNode = findNextNavNode({
12988
+ // move FROM the MRU node, not event-related node (which will be the node that is
12989
+ // outside the trap causing the focus escape we're trying to fix)
12990
+ target: state.mostRecentlyFocusedNode,
12991
+ isBackward: config.isKeyBackward(state.recentNavEvent)
12992
+ });
12993
+ }
12994
+ if (nextNode) {
12995
+ tryFocus(nextNode);
12996
+ } else {
12997
+ tryFocus(state.mostRecentlyFocusedNode || getInitialFocusNode());
12998
+ }
12999
+ }
13000
+ state.recentNavEvent = undefined; // clear
13001
+ };
13002
+
13003
+ // Hijack key nav events on the first and last focusable nodes of the trap,
13004
+ // in order to prevent focus from escaping. If it escapes for even a
13005
+ // moment it can end up scrolling the page and causing confusion so we
13006
+ // kind of need to capture the action at the keydown phase.
13007
+ var checkKeyNav = function checkKeyNav(event) {
13008
+ var isBackward = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
13009
+ state.recentNavEvent = event;
13010
+ var destinationNode = findNextNavNode({
13011
+ event: event,
13012
+ isBackward: isBackward
13013
+ });
12646
13014
  if (destinationNode) {
12647
13015
  if (isTabEvent(event)) {
12648
13016
  // since tab natively moves focus, we wouldn't have a destination node unless we
@@ -13529,11 +13897,38 @@ const SeamlyActivityMonitor = ({ children }) => {
13529
13897
  // It is important to use keyUp here as focus may be set from outside the
13530
13898
  // chat container via keyboard. In this case the keyDown handler would not
13531
13899
  // be fired inside the container on the initial focus event.
13532
- 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 })) })));
13900
+ 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 }) }));
13533
13901
  };
13534
13902
  /* harmony default export */ const seamly_activity_monitor = (SeamlyActivityMonitor);
13535
13903
 
13536
13904
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/core/seamly-event-subscriber.ts
13905
+ var seamly_event_subscriber_awaiter = undefined && undefined.__awaiter || function (thisArg, _arguments, P, generator) {
13906
+ function adopt(value) {
13907
+ return value instanceof P ? value : new P(function (resolve) {
13908
+ resolve(value);
13909
+ });
13910
+ }
13911
+ return new (P || (P = Promise))(function (resolve, reject) {
13912
+ function fulfilled(value) {
13913
+ try {
13914
+ step(generator.next(value));
13915
+ } catch (e) {
13916
+ reject(e);
13917
+ }
13918
+ }
13919
+ function rejected(value) {
13920
+ try {
13921
+ step(generator["throw"](value));
13922
+ } catch (e) {
13923
+ reject(e);
13924
+ }
13925
+ }
13926
+ function step(result) {
13927
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
13928
+ }
13929
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
13930
+ });
13931
+ };
13537
13932
  var seamly_event_subscriber_rest = undefined && undefined.__rest || function (s, e) {
13538
13933
  var t = {};
13539
13934
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
@@ -13554,13 +13949,13 @@ var seamly_event_subscriber_rest = undefined && undefined.__rest || function (s,
13554
13949
 
13555
13950
 
13556
13951
 
13952
+
13557
13953
  const EMITTABLE_MESSAGE_TYPES = ['text', 'choice_prompt', 'image', 'video'];
13558
13954
  const SeamlyEventSubscriber = () => {
13559
13955
  const api = seamly_api_hooks_useSeamlyApiContext();
13560
13956
  const syncChannelRef = (0,hooks_.useRef)();
13561
13957
  const messageChannelRef = (0,hooks_.useRef)();
13562
- const dispatch = useDispatch();
13563
- const events = useEvents();
13958
+ const dispatch = useAppDispatch();
13564
13959
  const eventBus = (0,hooks_.useContext)(SeamlyEventBusContext);
13565
13960
  const prevEmittedEventId = (0,hooks_.useRef)(null);
13566
13961
  const {
@@ -13805,31 +14200,19 @@ const SeamlyEventSubscriber = () => {
13805
14200
  if (syncChannelRef.current) {
13806
14201
  (_a = api.conversation.channel) === null || _a === void 0 ? void 0 : _a.off('sync', syncChannelRef.current);
13807
14202
  }
13808
- syncChannelRef.current = api.conversation.channel.on('sync', payload => {
13809
- var _a;
13810
- const lastEvent = events[events.length - 1];
13811
- const payloadLastEventId = (_a = payload === null || payload === void 0 ? void 0 : payload.lastEvent) === null || _a === void 0 ? void 0 : _a.id;
13812
- if (lastEvent && payloadLastEventId === lastEvent.payload.id) {
13813
- return payload;
13814
- }
13815
- return api.getConversation().then(history => {
14203
+ syncChannelRef.current = api.conversation.channel.on('sync', payload => seamly_event_subscriber_awaiter(void 0, void 0, void 0, function* () {
14204
+ try {
14205
+ const history = yield dispatch(getConversation(payload)).unwrap();
13816
14206
  if (!history) return;
13817
14207
  dispatch(setHistory(history));
13818
- }).catch(error => {
13819
- dispatch(setInterrupt({
13820
- name: error === null || error === void 0 ? void 0 : error.name,
13821
- message: error === null || error === void 0 ? void 0 : error.message,
13822
- langKey: error === null || error === void 0 ? void 0 : error.langKey,
13823
- action: error === null || error === void 0 ? void 0 : error.action,
13824
- originalEvent: error === null || error === void 0 ? void 0 : error.originalEvent,
13825
- originalError: error === null || error === void 0 ? void 0 : error.originalError
13826
- }));
13827
- });
13828
- });
14208
+ } catch (_e) {
14209
+ // nothing to do, the error is handled in the thunk
14210
+ }
14211
+ }));
13829
14212
  return true;
13830
14213
  });
13831
14214
  }
13832
- }, [api, api.connectionInfo, api.conversation.channel, events, dispatch]);
14215
+ }, [api, api.connectionInfo, api.conversation.channel, dispatch]);
13833
14216
  return null;
13834
14217
  };
13835
14218
  /* harmony default export */ const seamly_event_subscriber = (SeamlyEventSubscriber);
@@ -13936,7 +14319,7 @@ const SeamlyFileUpload = ({ children }) => {
13936
14319
  uploadHandle,
13937
14320
  }));
13938
14321
  }, [addImageToSessionStorage, addUploadBubble, api, dispatch, t]);
13939
- return ((0,jsx_runtime_namespaceObject.jsx)(seamly_file_upload_context.Provider, Object.assign({ value: onUploadFileHandler }, { children: children })));
14322
+ return ((0,jsx_runtime_namespaceObject.jsx)(seamly_file_upload_context.Provider, { value: onUploadFileHandler, children: children }));
13940
14323
  };
13941
14324
  /* harmony default export */ const seamly_file_upload = (SeamlyFileUpload);
13942
14325
 
@@ -14327,7 +14710,7 @@ const SeamlyCore = ({ store, children, eventBus, api }) => {
14327
14710
  (0,hooks_.useErrorBoundary)((error) => {
14328
14711
  store.dispatch(catchError(error));
14329
14712
  });
14330
- 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 })] })] }) }) }) })) })) })));
14713
+ 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 })] })] }) }) }) }) }) }));
14331
14714
  };
14332
14715
  /* harmony default export */ const seamly_core = (SeamlyCore);
14333
14716
 
@@ -14388,9 +14771,9 @@ const useDebounce = (value, delay = 20) => {
14388
14771
  const getState = ({
14389
14772
  forms
14390
14773
  }) => forms;
14391
- const getFormById = es_createSelector(getState, (_, {
14774
+ const getFormById = es_createSelector([getState, (_, {
14392
14775
  formId
14393
- }) => formId, (forms, formId) => forms[formId]);
14776
+ }) => formId], (forms, formId) => forms[formId]);
14394
14777
  const getFormControlsByFormId = es_createSelector(getFormById, form => (form === null || form === void 0 ? void 0 : form.controls) || {});
14395
14778
  const getFormValuesByFormId = es_createSelector(getFormControlsByFormId, controls => {
14396
14779
  const valuesObj = {};
@@ -14401,15 +14784,15 @@ const getFormValuesByFormId = es_createSelector(getFormControlsByFormId, control
14401
14784
  });
14402
14785
  return valuesObj;
14403
14786
  });
14404
- const getControlValueByName = es_createSelector(getFormControlsByFormId, (_, {
14787
+ const getControlValueByName = es_createSelector([getFormControlsByFormId, (_, {
14405
14788
  name
14406
- }) => name, (controls, name) => {
14789
+ }) => name], (controls, name) => {
14407
14790
  var _a;
14408
14791
  return (_a = controls[name]) === null || _a === void 0 ? void 0 : _a.value;
14409
14792
  });
14410
- const getControlTouchedByName = es_createSelector(getFormControlsByFormId, (_, {
14793
+ const getControlTouchedByName = es_createSelector([getFormControlsByFormId, (_, {
14411
14794
  name
14412
- }) => name, (controls, name) => {
14795
+ }) => name], (controls, name) => {
14413
14796
  var _a;
14414
14797
  return (_a = controls[name]) === null || _a === void 0 ? void 0 : _a.touched;
14415
14798
  });
@@ -14604,7 +14987,7 @@ const useEntryTextTranslation = controlName => {
14604
14987
  text: (text === null || text === void 0 ? void 0 : text.label) || t('input.inputLabelText'),
14605
14988
  limit: !(text === null || text === void 0 ? void 0 : text.label) && hasCharacterLimit ? characterLimit : null
14606
14989
  }), [t, hasCharacterLimit, characterLimit, text === null || text === void 0 ? void 0 : text.label]);
14607
- 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]);
14990
+ 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]);
14608
14991
  return {
14609
14992
  placeholder,
14610
14993
  label,
@@ -14649,14 +15032,14 @@ function AbortTransactionButton() {
14649
15032
  });
14650
15033
  clearEntryAbortTransaction();
14651
15034
  };
14652
- return ((0,jsx_runtime_namespaceObject.jsx)("li", Object.assign({ className: css_className([
15035
+ return ((0,jsx_runtime_namespaceObject.jsx)("li", { className: css_className([
14653
15036
  'cvco-conversation__item',
14654
15037
  'cvco-conversation__item--abort-transaction',
14655
- ]) }, { children: (0,jsx_runtime_namespaceObject.jsx)("button", Object.assign({ className: css_className([
15038
+ ]), children: (0,jsx_runtime_namespaceObject.jsx)("button", { className: css_className([
14656
15039
  'button',
14657
15040
  'button--secondary',
14658
15041
  'abort-transaction__button',
14659
- ]), type: "button", onClick: handleAbortTransaction }, { children: abortTransaction.label })) })));
15042
+ ]), type: "button", onClick: handleAbortTransaction, children: abortTransaction.label }) }));
14660
15043
  }
14661
15044
 
14662
15045
  ;// CONCATENATED MODULE: external "preact/compat"
@@ -14731,7 +15114,7 @@ const Event = ({ event, newParticipant }) => {
14731
15114
  if (newParticipant) {
14732
15115
  classNames.push('conversation__item--new-participant');
14733
15116
  }
14734
- 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 }) }))] })));
15117
+ 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 }) })] }));
14735
15118
  };
14736
15119
  /* harmony default export */ const event_event = (Event);
14737
15120
 
@@ -14816,7 +15199,7 @@ const Conversation = () => {
14816
15199
  e.preventDefault();
14817
15200
  focusSkiplinkTarget();
14818
15201
  };
14819
- 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, {})] }))] })) }))] }));
15202
+ 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, {})] })] }) })] }));
14820
15203
  };
14821
15204
  /* harmony default export */ const conversation = (Conversation);
14822
15205
 
@@ -15211,16 +15594,16 @@ const OptionsFrame = ({ className: givenClassName, children, onCancel, headingTe
15211
15594
  (0,hooks_.useEffect)(() => {
15212
15595
  focusElement(container.current);
15213
15596
  }, [container]);
15214
- return ((0,jsx_runtime_namespaceObject.jsx)("section", Object.assign({ className: css_className('options', {
15597
+ return ((0,jsx_runtime_namespaceObject.jsx)("section", { className: css_className('options', {
15215
15598
  'options--right': position.horizontal === 'right',
15216
15599
  'options--left': position.horizontal === 'left',
15217
15600
  'options--top': position.vertical === 'top',
15218
15601
  'options--bottom': position.vertical === 'bottom',
15219
- }, 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) => {
15602
+ }, 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) => {
15220
15603
  if (cancelButtonRef) {
15221
15604
  cancelButtonRef.current = btn;
15222
15605
  }
15223
- } }, { 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 }))] })) })));
15606
+ }, 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 })] }) }));
15224
15607
  };
15225
15608
  /* harmony default export */ const options_frame = (OptionsFrame);
15226
15609
 
@@ -15357,7 +15740,7 @@ function FormProvider(_a) {
15357
15740
  console.error('"onSubmit" is required.');
15358
15741
  return null;
15359
15742
  }
15360
- return ((0,jsx_runtime_namespaceObject.jsx)(context_Provider, Object.assign({}, props, { value: contextValue }, { children: children })));
15743
+ return ((0,jsx_runtime_namespaceObject.jsx)(context_Provider, Object.assign({}, props, { value: contextValue, children: children })));
15361
15744
  }
15362
15745
 
15363
15746
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/form-controls/form.js
@@ -15423,8 +15806,8 @@ function error_Error({
15423
15806
 
15424
15807
 
15425
15808
 
15426
- const FormControlWrapper = ({ contentHint, id, labelText, labelClass = css_className('label'), validity, errorText, children, }) => {
15427
- 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] }))] }));
15809
+ const FormControlWrapper = ({ contentHint, id, labelText, labelClass, validity, errorText, children, }) => {
15810
+ 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] })] }));
15428
15811
  };
15429
15812
  /* harmony default export */ const wrapper = (FormControlWrapper);
15430
15813
 
@@ -15459,7 +15842,7 @@ function Input(_a) {
15459
15842
  describedByIds.push(`${id}-error`);
15460
15843
  }
15461
15844
  // todo: destructure Field
15462
- 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)) })));
15845
+ 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)) }));
15463
15846
  }
15464
15847
  /* harmony default export */ const input = (Input);
15465
15848
 
@@ -15807,14 +16190,14 @@ const OptionsButton = () => {
15807
16190
 
15808
16191
 
15809
16192
 
15810
- const TranslationOption = ({ label, checked, description, onChange, id, }) => {
16193
+ const TranslationOption = ({ label, checked, description, onChange, id, itemClassName, }) => {
15811
16194
  const onKeyDown = (e) => {
15812
16195
  if (e.code === 'Space' || e.code === 'Enter') {
15813
16196
  e.preventDefault();
15814
16197
  onChange();
15815
16198
  }
15816
16199
  };
15817
- 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, ")"] })] })));
16200
+ 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, ")"] })] }));
15818
16201
  };
15819
16202
  /* harmony default export */ const translation_option = (TranslationOption);
15820
16203
 
@@ -15826,12 +16209,13 @@ const TranslationOption = ({ label, checked, description, onChange, id, }) => {
15826
16209
 
15827
16210
 
15828
16211
 
16212
+ const isChecked = (language, currentLocale, isOriginal) => currentLocale === language.locale || (!currentLocale && isOriginal);
15829
16213
  const TranslationOptions = ({ onChange, describedById, }) => {
15830
16214
  const { context: { locale: defaultLocale }, } = useConfig();
15831
16215
  const { t } = useI18n();
15832
16216
  const { focusContainer } = useTranslationsContainer();
15833
16217
  const { languages, currentLocale, enableTranslations, disableTranslations } = useTranslations();
15834
- const handleChange = ({ locale }) => () => {
16218
+ const handleChange = (locale) => () => {
15835
16219
  if (locale === currentLocale || defaultLocale === locale) {
15836
16220
  disableTranslations();
15837
16221
  }
@@ -15841,22 +16225,25 @@ const TranslationOptions = ({ onChange, describedById, }) => {
15841
16225
  onChange();
15842
16226
  focusContainer();
15843
16227
  };
15844
- const sortedLanguages = (0,hooks_.useMemo)(() => {
15845
- return [...languages].sort((a, b) => {
15846
- if (a.locale === defaultLocale)
15847
- return -1;
15848
- if (b.locale === defaultLocale)
15849
- return 1;
15850
- return a.nativeName.localeCompare(b.nativeName, undefined, {
15851
- sensitivity: 'base',
15852
- });
15853
- });
15854
- }, [languages, defaultLocale]);
15855
- 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) => {
15856
- const isOriginal = idx === 0;
15857
- const checked = currentLocale === language.locale || (!currentLocale && isOriginal);
15858
- 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));
15859
- }) })));
16228
+ const { primaryLanguages, remainingLanguages } = (0,compat_namespaceObject.useMemo)(() => languages.reduce((acc, language) => {
16229
+ const isOriginal = language.locale === defaultLocale;
16230
+ const checked = isChecked(language, currentLocale, isOriginal);
16231
+ if (language.locale !== defaultLocale) {
16232
+ acc.remainingLanguages.push(Object.assign(Object.assign({}, language), { checked, isOriginal }));
16233
+ }
16234
+ const selectedIdx = acc.remainingLanguages.findIndex((l) => l.locale === currentLocale);
16235
+ if (isOriginal || (checked && selectedIdx > 4)) {
16236
+ acc.primaryLanguages.push(Object.assign(Object.assign({}, language), { checked, isOriginal }));
16237
+ }
16238
+ return acc;
16239
+ }, {
16240
+ primaryLanguages: [],
16241
+ remainingLanguages: [],
16242
+ }), [currentLocale, defaultLocale, languages]);
16243
+ 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({
16244
+ 'translation-options__item--original': isOriginal,
16245
+ 'translation-options__item--selected': checked && idx !== 0,
16246
+ }) }, 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)))] }));
15860
16247
  };
15861
16248
  /* harmony default export */ const translation_options = (TranslationOptions);
15862
16249
 
@@ -15869,7 +16256,7 @@ const TranslationOptions = ({ onChange, describedById, }) => {
15869
16256
  function TranslationsOptionsDialog({ onClose, position, }) {
15870
16257
  const { t } = useI18n();
15871
16258
  const descriptionId = useGeneratedId();
15872
- 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 }) })));
16259
+ 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 }) }));
15873
16260
  }
15874
16261
  /* harmony default export */ const options_dialog = (TranslationsOptionsDialog);
15875
16262
 
@@ -15909,11 +16296,11 @@ function TranslationsOptionsButton({ children, position = {
15909
16296
  e.preventDefault();
15910
16297
  }
15911
16298
  };
15912
- 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([
16299
+ 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([
15913
16300
  'button',
15914
16301
  'chat__options__button',
15915
16302
  ...classNames,
15916
- ]), id: toggleButtonId, onClick: handleToggleClick, onKeyDown: handleToggleKeyDown, ref: toggleButton, "aria-haspopup": "dialog", "aria-expanded": menuIsOpen }, { children: children }))] })));
16303
+ ]), id: toggleButtonId, onClick: handleToggleClick, onKeyDown: handleToggleKeyDown, ref: toggleButton, "aria-haspopup": "dialog", "aria-expanded": menuIsOpen, children: children })] }));
15917
16304
  }
15918
16305
 
15919
16306
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/app-options/index.js
@@ -15983,7 +16370,7 @@ const UnreadMessagesButton = () => {
15983
16370
  const { scrollToRef, unreadIds } = (0,hooks_.useContext)(chat_scroll_context);
15984
16371
  const { isMinimized } = useVisibility();
15985
16372
  const { t } = useI18n();
15986
- 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: "" })] })) })) })));
16373
+ 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: "" })] }) }) }));
15987
16374
  };
15988
16375
  /* harmony default export */ const unread_messages_button = (UnreadMessagesButton);
15989
16376
 
@@ -16131,13 +16518,13 @@ const ChatScrollProvider = ({ children }) => {
16131
16518
  return acc;
16132
16519
  }, {}), [events]);
16133
16520
  const { scrollToRef, scrollToBottom, containerRef, unreadIds } = use_chat_scroll(eventRefs);
16134
- return ((0,jsx_runtime_namespaceObject.jsx)(chat_scroll_context.Provider, Object.assign({ value: {
16521
+ return ((0,jsx_runtime_namespaceObject.jsx)(chat_scroll_context.Provider, { value: {
16135
16522
  eventRefs,
16136
16523
  unreadIds,
16137
16524
  scrollToRef,
16138
16525
  scrollToBottom,
16139
16526
  containerRef,
16140
- } }, { 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, {})] })) })));
16527
+ }, 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, {})] }) }));
16141
16528
  };
16142
16529
  /* harmony default export */ const chat_scroll_provider = (ChatScrollProvider);
16143
16530
 
@@ -16428,13 +16815,13 @@ function TextEntryForm({ controlName, skipLinkId }) {
16428
16815
  // When a message is submitted, the keyboard should be prevented from closing on mobile devices
16429
16816
  event.preventDefault();
16430
16817
  };
16431
- 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([
16818
+ 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([
16432
16819
  'input--text__container',
16433
16820
  ...(reachedCharacterWarning && !reachedCharacterLimit
16434
16821
  ? ['character-warning']
16435
16822
  : []),
16436
16823
  ...(reachedCharacterLimit ? ['character-exceeded'] : []),
16437
- ]) }, { 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') }) }))] })));
16824
+ ]), 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') }) })] }));
16438
16825
  }
16439
16826
 
16440
16827
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/entry/text-entry/index.js
@@ -17092,7 +17479,7 @@ const CollapseButton = () => {
17092
17479
 
17093
17480
  const ChatStatus = ({ children, handleClose, title, closeButtonText, srCloseButtonText, id, }) => {
17094
17481
  const headingId = useGeneratedId();
17095
- 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 })))] })))] })));
17482
+ 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 }))] }))] }));
17096
17483
  };
17097
17484
  /* harmony default export */ const chat_status = (ChatStatus);
17098
17485
 
@@ -17127,7 +17514,7 @@ function TranslationChatStatus() {
17127
17514
 
17128
17515
 
17129
17516
 
17130
- 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 })))] })));
17517
+ 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 }))] }));
17131
17518
  /* harmony default export */ const chat_status_action = (ChatStatusAction);
17132
17519
 
17133
17520
  ;// CONCATENATED MODULE: ./src/javascripts/ui/components/translation-proposal/index.tsx
@@ -17141,7 +17528,7 @@ function TranslationProposal() {
17141
17528
  if (!showProposal) {
17142
17529
  return null;
17143
17530
  }
17144
- 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 }) })));
17531
+ 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 }) }));
17145
17532
  }
17146
17533
 
17147
17534
  ;// CONCATENATED MODULE: ./src/javascripts/domains/translations/components/translation-status.tsx
@@ -17408,10 +17795,14 @@ const WindowOpenButton = ({
17408
17795
  "aria-label": ariaLabel,
17409
17796
  "aria-hidden": isOpen,
17410
17797
  onClick: handleClick,
17411
- children: [(0,jsx_runtime_namespaceObject.jsx)("span", {
17412
- className: css_className('message-count'),
17413
- "aria-hidden": "true",
17414
- children: !!count && count
17798
+ children: [(0,jsx_runtime_namespaceObject.jsx)(in_out_transition, {
17799
+ isActive: !!count,
17800
+ transitionStartState: transitionStartStates.notRendered,
17801
+ children: (0,jsx_runtime_namespaceObject.jsx)("span", {
17802
+ className: css_className('message-count'),
17803
+ "aria-hidden": "true",
17804
+ children: count
17805
+ })
17415
17806
  }), (0,jsx_runtime_namespaceObject.jsx)(ButtonIcon, {})]
17416
17807
  })
17417
17808
  });
@@ -17446,7 +17837,7 @@ const WindowView = () => {
17446
17837
  },
17447
17838
  },
17448
17839
  }), [continueChatText]);
17449
- 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, {}) }) }) }))] }));
17840
+ 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, {}) }) }) })] }));
17450
17841
  };
17451
17842
  /* harmony default export */ const window_view = (WindowView);
17452
17843
 
@@ -17661,7 +18052,7 @@ const View = ({ children }) => {
17661
18052
  if (userHasResponded) {
17662
18053
  classNames.push('app--user-responded');
17663
18054
  }
17664
- 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, {}) }))));
18055
+ 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, {}) })));
17665
18056
  };
17666
18057
  /* harmony default export */ const view = (View);
17667
18058
 
@@ -17751,14 +18142,16 @@ class Engine {
17751
18142
  yield store.dispatch(initializeConfig());
17752
18143
  try {
17753
18144
  const { locale } = yield store.dispatch(initializeApp()).unwrap();
17754
- yield store.dispatch(setLocale(locale));
18145
+ if (locale) {
18146
+ yield store.dispatch(setLocale(locale));
18147
+ }
17755
18148
  }
17756
18149
  catch (rejectedValueOrSerializedError) {
17757
18150
  // nothing to do
17758
18151
  }
17759
18152
  store.dispatch(initializeVisibility());
17760
18153
  if (View) {
17761
- (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);
18154
+ (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);
17762
18155
  }
17763
18156
  else {
17764
18157
  (0,external_preact_.render)((0,jsx_runtime_namespaceObject.jsx)(chat_app, { config: renderConfig, eventBus: this.eventBus, store: store, api: this.api }), this.parentElement);
@@ -19101,6 +19494,22 @@ const cardTopic = {
19101
19494
  }
19102
19495
  }
19103
19496
  };
19497
+ const cardNoImage = {
19498
+ type: 'message',
19499
+ payload: {
19500
+ type: 'card',
19501
+ id: randomId(),
19502
+ body: {
19503
+ action: {
19504
+ ask: '',
19505
+ type: 'ask'
19506
+ },
19507
+ buttonText: 'Ask about pizzas!',
19508
+ description: 'Pizza Margherita is a <strong>typical Neapolitan pizza</strong>.\n\nIt is made with San Marzano tomatoes, mozzarella cheese, fresh basil, salt, and extra-virgin olive oil.',
19509
+ title: 'Pizza Margherita'
19510
+ }
19511
+ }
19512
+ };
19104
19513
  const standardState = {
19105
19514
  base: {
19106
19515
  category: categoryKeys.unstarted,
@@ -19338,7 +19747,7 @@ const standardState = {
19338
19747
  serviceInfo: {
19339
19748
  activeServiceSessionId: '3942159e-9878-469e-9120-f44fd6be0f35'
19340
19749
  },
19341
- events: [cardAskText, cardNavigate, cardTopic]
19750
+ events: [cardAskText, cardNavigate, cardTopic, cardNoImage]
19342
19751
  },
19343
19752
  carousel: {
19344
19753
  category: categoryKeys.messages,
@@ -19856,6 +20265,104 @@ const standardState = {
19856
20265
  }]
19857
20266
  }
19858
20267
  },
20268
+ translationsActiveLarge: {
20269
+ category: categoryKeys.translations,
20270
+ headingText: 'Show translations active (large list)',
20271
+ description: '',
20272
+ ...baseState,
20273
+ config: {
20274
+ ...baseState.config,
20275
+ context: {
20276
+ ...baseState.context,
20277
+ locale: 'nl'
20278
+ }
20279
+ },
20280
+ translations: {
20281
+ ...translationsSlice,
20282
+ currentLocale: 'lv',
20283
+ isActive: true,
20284
+ isAvailable: true,
20285
+ languages: [{
20286
+ locale: 'nl',
20287
+ nativeName: 'Dutch'
20288
+ }, {
20289
+ locale: 'en',
20290
+ nativeName: 'English'
20291
+ }, {
20292
+ locale: 'ar',
20293
+ nativeName: 'Arabic'
20294
+ }, {
20295
+ locale: 'bg',
20296
+ nativeName: 'Bulgarian'
20297
+ }, {
20298
+ locale: 'zh',
20299
+ nativeName: 'Chinese'
20300
+ }, {
20301
+ locale: 'cs',
20302
+ nativeName: 'Czech'
20303
+ }, {
20304
+ locale: 'da',
20305
+ nativeName: 'Danish'
20306
+ }, {
20307
+ locale: 'et',
20308
+ nativeName: 'Estonian'
20309
+ }, {
20310
+ locale: 'fi',
20311
+ nativeName: 'Finnish'
20312
+ }, {
20313
+ locale: 'fr',
20314
+ nativeName: 'French'
20315
+ }, {
20316
+ locale: 'de-informal',
20317
+ nativeName: 'German'
20318
+ }, {
20319
+ locale: 'el',
20320
+ nativeName: 'Greek'
20321
+ }, {
20322
+ locale: 'hu',
20323
+ nativeName: 'Hungarian'
20324
+ }, {
20325
+ locale: 'it',
20326
+ nativeName: 'Italian'
20327
+ }, {
20328
+ locale: 'ja',
20329
+ nativeName: 'Japanese'
20330
+ }, {
20331
+ locale: 'lv',
20332
+ nativeName: 'Latvian'
20333
+ }, {
20334
+ locale: 'pl',
20335
+ nativeName: 'Polish'
20336
+ }, {
20337
+ locale: 'ro',
20338
+ nativeName: 'Romanian'
20339
+ }, {
20340
+ locale: 'ru',
20341
+ nativeName: 'Russian'
20342
+ }, {
20343
+ locale: 'sk',
20344
+ nativeName: 'Slovak'
20345
+ }, {
20346
+ locale: 'sl',
20347
+ nativeName: 'Slovenian'
20348
+ }, {
20349
+ locale: 'es-informal',
20350
+ nativeName: 'Spanish'
20351
+ }, {
20352
+ locale: 'sv',
20353
+ nativeName: 'Swedish'
20354
+ }, {
20355
+ locale: 'ti',
20356
+ nativeName: 'Tigrinya'
20357
+ }, {
20358
+ locale: 'tr',
20359
+ nativeName: 'Turkish'
20360
+ }, {
20361
+ locale: 'uk',
20362
+ nativeName: 'Ukrainian'
20363
+ }]
20364
+ }
20365
+ },
19859
20366
  translationsFullConversation: {
19860
20367
  category: categoryKeys.translations,
19861
20368
  headingText: 'Show translated messages',