@xapp/chat-widget 1.94.4 → 1.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +1 -1
- package/dist/index.es.js +353 -96
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +352 -95
- package/dist/index.js.map +1 -1
- package/dist/utils/classNames.d.ts +0 -0
- package/dist/xapp-chat-widget.css +1 -1
- package/dist/xapp-chat-widget.js +3 -3
- package/dist/xapp-chat-widget.js.map +1 -1
- package/package.json +5 -7
package/dist/index.es.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import React, { useCallback, useState, useEffect, useRef, createContext, useMemo, useContext, memo
|
|
1
|
+
import React, { useCallback, useState, useEffect, useRef, useLayoutEffect, createContext, useMemo, useContext, memo } from 'react';
|
|
2
2
|
export { default as React } from 'react';
|
|
3
3
|
import require$$0, { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { useSelector, useDispatch, Provider } from 'react-redux';
|
|
5
5
|
|
|
6
6
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
7
7
|
|
|
8
|
-
function getDefaultExportFromCjs (x) {
|
|
9
|
-
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
8
|
var lib = {};
|
|
13
9
|
|
|
14
10
|
var ActionBar$1 = {};
|
|
@@ -396,6 +392,17 @@ var ActionBarCta = function (_a) {
|
|
|
396
392
|
|
|
397
393
|
var DEFAULT_MOBILE_BREAKPOINT = 768;
|
|
398
394
|
var RESIZE_DEBOUNCE_MS = 150;
|
|
395
|
+
/**
|
|
396
|
+
* ChatWidget.scss sizes the chat panel against this variable. Nothing used to set it, so it always
|
|
397
|
+
* fell back to the hardcoded 80px in the SCSS - and the real mobile bar is taller than that once
|
|
398
|
+
* env(safe-area-inset-bottom) applies, which pushed the chat input row behind the bar. Measure the
|
|
399
|
+
* bar instead of guessing, so it also stays correct when a customer restyles it.
|
|
400
|
+
*
|
|
401
|
+
* This is written on documentElement, so it assumes one ActionBar per page - the same
|
|
402
|
+
* single-instance assumption the widget already makes for --xapp-widget-z-index and friends.
|
|
403
|
+
* Two concurrent bars would fight over it, and either one unmounting would clear it.
|
|
404
|
+
*/
|
|
405
|
+
var ACTION_BAR_HEIGHT_VAR = "--xapp-action-bar-height";
|
|
399
406
|
var ActionBar = function (_a) {
|
|
400
407
|
var _b, _c, _d;
|
|
401
408
|
var config = _a.config, visible = _a.visible, chatDisabled = _a.chatDisabled, _e = _a.hasUserInteracted, hasUserInteracted = _e === void 0 ? false : _e, onChatClick = _a.onChatClick, onChatMinimize = _a.onChatMinimize, onFormClick = _a.onFormClick, onCtaDismiss = _a.onCtaDismiss;
|
|
@@ -403,6 +410,7 @@ var ActionBar = function (_a) {
|
|
|
403
410
|
var mobileBreakpoint = (_b = config.mobileBreakpoint) !== null && _b !== void 0 ? _b : DEFAULT_MOBILE_BREAKPOINT;
|
|
404
411
|
var position = (_c = config.position) !== null && _c !== void 0 ? _c : "right";
|
|
405
412
|
var resizeTimeoutRef = useRef(null);
|
|
413
|
+
var barRef = useRef(null);
|
|
406
414
|
// Debounced resize handler
|
|
407
415
|
var handleResize = useCallback(function () {
|
|
408
416
|
if (resizeTimeoutRef.current) {
|
|
@@ -423,6 +431,41 @@ var ActionBar = function (_a) {
|
|
|
423
431
|
}
|
|
424
432
|
};
|
|
425
433
|
}, [mobileBreakpoint, handleResize]);
|
|
434
|
+
// Publish the bar's real height so the chat panel can size around it.
|
|
435
|
+
//
|
|
436
|
+
// useLayoutEffect, not useEffect: this commits before paint, so the panel never gets a
|
|
437
|
+
// frame laid out against the 80px SCSS fallback. useEffect would run after paint and
|
|
438
|
+
// reintroduce a one-frame version of the very misalignment this is here to remove.
|
|
439
|
+
useLayoutEffect(function () {
|
|
440
|
+
var bar = barRef.current;
|
|
441
|
+
if (!bar) {
|
|
442
|
+
return undefined;
|
|
443
|
+
}
|
|
444
|
+
var publishHeight = function () {
|
|
445
|
+
// getBoundingClientRect covers the whole border box, including the safe-area padding
|
|
446
|
+
// the mobile bar adds - which is exactly the space the chat panel has to clear.
|
|
447
|
+
var height = bar.getBoundingClientRect().height;
|
|
448
|
+
// A zero height means the bar is hidden or not laid out yet. Publishing 0px would
|
|
449
|
+
// be worse than the SCSS fallback, so leave whatever is already there alone.
|
|
450
|
+
if (height <= 0) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
document.documentElement.style.setProperty(ACTION_BAR_HEIGHT_VAR, "".concat(height, "px"));
|
|
454
|
+
};
|
|
455
|
+
publishHeight();
|
|
456
|
+
// Older browsers without ResizeObserver keep the mount-time measurement above.
|
|
457
|
+
if (typeof ResizeObserver === "undefined") {
|
|
458
|
+
return function () {
|
|
459
|
+
document.documentElement.style.removeProperty(ACTION_BAR_HEIGHT_VAR);
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
var observer = new ResizeObserver(publishHeight);
|
|
463
|
+
observer.observe(bar);
|
|
464
|
+
return function () {
|
|
465
|
+
observer.disconnect();
|
|
466
|
+
document.documentElement.style.removeProperty(ACTION_BAR_HEIGHT_VAR);
|
|
467
|
+
};
|
|
468
|
+
}, [isMobile]);
|
|
426
469
|
// Filter out chat buttons if chat is disabled
|
|
427
470
|
var filteredButtons = chatDisabled
|
|
428
471
|
? config.buttons.filter(function (button) { return !lib.isActionBarChatButton(button); })
|
|
@@ -447,7 +490,7 @@ var ActionBar = function (_a) {
|
|
|
447
490
|
var handleCtaDismiss = function () {
|
|
448
491
|
onCtaDismiss === null || onCtaDismiss === void 0 ? void 0 : onCtaDismiss();
|
|
449
492
|
};
|
|
450
|
-
return (jsxs("div", { className: classNames, role: "toolbar", "aria-label": "Chat actions", children: [showCta && (jsx("div", { className: "xapp-action-bar-cta-wrapper", children: jsx(ActionBarCta, { config: config.cta, isMobile: isMobile, onClick: handleCtaClick, onDismiss: handleCtaDismiss, hasUserInteracted: hasUserInteracted }) })), jsx("div", { className: "xapp-action-bar__buttons", children: filteredButtons.map(function (button) { return (jsx(ActionBarButton, { button: button, chatActive: visible, onChatClick: onChatClick, onChatMinimize: onChatMinimize, onFormClick: onFormClick, isMobile: isMobile }, button.id)); }) })] }));
|
|
493
|
+
return (jsxs("div", { ref: barRef, className: classNames, role: "toolbar", "aria-label": "Chat actions", children: [showCta && (jsx("div", { className: "xapp-action-bar-cta-wrapper", children: jsx(ActionBarCta, { config: config.cta, isMobile: isMobile, onClick: handleCtaClick, onDismiss: handleCtaDismiss, hasUserInteracted: hasUserInteracted }) })), jsx("div", { className: "xapp-action-bar__buttons", children: filteredButtons.map(function (button) { return (jsx(ActionBarButton, { button: button, chatActive: visible, onChatClick: onChatClick, onChatMinimize: onChatMinimize, onFormClick: onFormClick, isMobile: isMobile }, button.id)); }) })] }));
|
|
451
494
|
};
|
|
452
495
|
|
|
453
496
|
/**
|
|
@@ -2305,8 +2348,9 @@ var RichText = function (props) {
|
|
|
2305
2348
|
};
|
|
2306
2349
|
|
|
2307
2350
|
var RichInput = function (props) {
|
|
2308
|
-
var id = props.id, value = props.value, type = props.type, autoFocus = props.autoFocus, spellCheck = props.spellCheck, tabIndex = props.tabIndex, maxLength = props.maxLength, onChange = props.onChange, onInput = props.onInput, onKeyDown = props.onKeyDown, onSearch = props.onSearch;
|
|
2351
|
+
var id = props.id, value = props.value, type = props.type, autoFocus = props.autoFocus, spellCheck = props.spellCheck, tabIndex = props.tabIndex, maxLength = props.maxLength, enterKeyHint = props.enterKeyHint, onChange = props.onChange, onInput = props.onInput, onKeyDown = props.onKeyDown, onSearch = props.onSearch;
|
|
2309
2352
|
var rich = value.formats.some(function (f) { return f.type === "inputText"; });
|
|
2353
|
+
var keyHint = enterKeyHint || (type === "search" ? "search" : "send");
|
|
2310
2354
|
var handleChange = react.useCallback(function (ev) {
|
|
2311
2355
|
if (onChange) {
|
|
2312
2356
|
onChange({
|
|
@@ -2358,7 +2402,7 @@ var RichInput = function (props) {
|
|
|
2358
2402
|
}
|
|
2359
2403
|
return undefined;
|
|
2360
2404
|
}, [inputNode, onSearch]);
|
|
2361
|
-
return (jsxRuntime.jsx("div", { className: "xappw-rich-input ".concat(props.className), children: rich ? (jsxRuntime.jsx(RichText, { id: id, value: value, onChange: handleRichChange, onInput: handleRichInput, onKeyDown: handleKeyDown, className: "xappw-rich-input__input ".concat(props.className, "__input") })) : (jsxRuntime.jsx("input", { id: id, ref: inputRef, type: type, value: value.text, autoComplete: "off", autoFocus: autoFocus, placeholder: props.placeholder, spellCheck: spellCheck, tabIndex: tabIndex ? Number(tabIndex) : 0, maxLength: maxLength, className: "xappw-rich-input__input ".concat(props.className, "__input"), onFocus: props.onFocus, onChange: handleChange, onInput: handleInput, onKeyDown: handleKeyDown })) }));
|
|
2405
|
+
return (jsxRuntime.jsx("div", { className: "xappw-rich-input ".concat(props.className), children: rich ? (jsxRuntime.jsx(RichText, { id: id, value: value, onChange: handleRichChange, onInput: handleRichInput, onKeyDown: handleKeyDown, className: "xappw-rich-input__input ".concat(props.className, "__input") })) : (jsxRuntime.jsx("input", { id: id, ref: inputRef, type: type, value: value.text, autoComplete: "off", enterKeyHint: keyHint, autoFocus: autoFocus, placeholder: props.placeholder, spellCheck: spellCheck, tabIndex: tabIndex ? Number(tabIndex) : 0, maxLength: maxLength, className: "xappw-rich-input__input ".concat(props.className, "__input"), onFocus: props.onFocus, onChange: handleChange, onInput: handleInput, onKeyDown: handleKeyDown })) }));
|
|
2362
2406
|
};
|
|
2363
2407
|
|
|
2364
2408
|
var SuggestionsGroupHeading = function (props) {
|
|
@@ -2702,6 +2746,268 @@ function useSuggestionsFetch$1(options) {
|
|
|
2702
2746
|
return response;
|
|
2703
2747
|
}
|
|
2704
2748
|
|
|
2749
|
+
/**
|
|
2750
|
+
* Stop the host page scrolling behind an open overlay.
|
|
2751
|
+
*
|
|
2752
|
+
* `body { overflow: hidden }` is the obvious way to do this, and is what both widgets used
|
|
2753
|
+
* to do — but **iOS Safari ignores `overflow: hidden` on the body**, so the customer's page
|
|
2754
|
+
* carried on scrolling under the modal. The technique that does work there is to take the
|
|
2755
|
+
* body out of flow at a negative offset equal to the current scroll position, then put it
|
|
2756
|
+
* back and re-scroll to that exact position on release.
|
|
2757
|
+
*
|
|
2758
|
+
* Reference counted rather than a plain on/off flag, and the count lives on the `<body>`
|
|
2759
|
+
* element rather than in module scope. That is deliberate: the chat widget's `FormModal`
|
|
2760
|
+
* loads the **standalone** form widget bundle, which carries its own copy of this module,
|
|
2761
|
+
* so the two overlays that can be open at once are not sharing any JS state. With a module
|
|
2762
|
+
* counter, the second lock would read the already-pinned scroll position (which the browser
|
|
2763
|
+
* reports as 0), the first release would unpin the body while the second overlay was still
|
|
2764
|
+
* open, and the second release would then re-apply `position: fixed` and leave the host page
|
|
2765
|
+
* stuck. The DOM is the only thing both bundles can agree on.
|
|
2766
|
+
*/
|
|
2767
|
+
/** How many overlays currently hold the lock. Absent means unlocked. */
|
|
2768
|
+
var COUNT_ATTRIBUTE$1 = "data-xapp-scroll-lock";
|
|
2769
|
+
/** What to put back when the last one lets go, as JSON. */
|
|
2770
|
+
var RESTORE_ATTRIBUTE = "data-xapp-scroll-lock-restore";
|
|
2771
|
+
var PINNED_PROPERTIES = ["position", "top", "left", "right", "width", "overflow"];
|
|
2772
|
+
function readCount$1(body) {
|
|
2773
|
+
var count = Number(body.getAttribute(COUNT_ATTRIBUTE$1));
|
|
2774
|
+
return Number.isFinite(count) && count > 0 ? count : 0;
|
|
2775
|
+
}
|
|
2776
|
+
function captureRestorePoint(body) {
|
|
2777
|
+
var inlineStyles = PINNED_PROPERTIES.reduce(function (styles, property) {
|
|
2778
|
+
styles[property] = body.style.getPropertyValue(property);
|
|
2779
|
+
return styles;
|
|
2780
|
+
}, {});
|
|
2781
|
+
return { scrollY: window.scrollY || window.pageYOffset || 0, inlineStyles: inlineStyles };
|
|
2782
|
+
}
|
|
2783
|
+
function takeRestorePoint(body) {
|
|
2784
|
+
var serialized = body.getAttribute(RESTORE_ATTRIBUTE);
|
|
2785
|
+
body.removeAttribute(RESTORE_ATTRIBUTE);
|
|
2786
|
+
try {
|
|
2787
|
+
var parsed = JSON.parse(serialized || "");
|
|
2788
|
+
if (parsed && typeof parsed.scrollY === "number" && parsed.inlineStyles) {
|
|
2789
|
+
return parsed;
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
catch (_a) {
|
|
2793
|
+
// Fall through: something else rewrote the attribute. Better to clear our own
|
|
2794
|
+
// properties and leave the page usable than to throw and leave it pinned.
|
|
2795
|
+
}
|
|
2796
|
+
return { scrollY: 0, inlineStyles: {} };
|
|
2797
|
+
}
|
|
2798
|
+
/**
|
|
2799
|
+
* Lock the body and return the release function.
|
|
2800
|
+
*
|
|
2801
|
+
* The returned function is idempotent — calling it twice is a no-op, which matters because
|
|
2802
|
+
* React StrictMode runs an effect's cleanup more than once.
|
|
2803
|
+
*/
|
|
2804
|
+
function lockBodyScroll() {
|
|
2805
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
2806
|
+
return function () { return undefined; };
|
|
2807
|
+
}
|
|
2808
|
+
var body = document.body;
|
|
2809
|
+
if (readCount$1(body) === 0) {
|
|
2810
|
+
var restorePoint = captureRestorePoint(body);
|
|
2811
|
+
body.setAttribute(RESTORE_ATTRIBUTE, JSON.stringify(restorePoint));
|
|
2812
|
+
body.style.position = "fixed";
|
|
2813
|
+
body.style.top = "-".concat(restorePoint.scrollY, "px");
|
|
2814
|
+
body.style.left = "0";
|
|
2815
|
+
body.style.right = "0";
|
|
2816
|
+
body.style.width = "100%";
|
|
2817
|
+
// Redundant next to `position: fixed`, but harmless, and it keeps the behaviour the
|
|
2818
|
+
// widgets already had on the browsers that do honour it.
|
|
2819
|
+
body.style.overflow = "hidden";
|
|
2820
|
+
}
|
|
2821
|
+
body.setAttribute(COUNT_ATTRIBUTE$1, String(readCount$1(body) + 1));
|
|
2822
|
+
var released = false;
|
|
2823
|
+
return function releaseBodyScroll() {
|
|
2824
|
+
if (released) {
|
|
2825
|
+
return;
|
|
2826
|
+
}
|
|
2827
|
+
released = true;
|
|
2828
|
+
var remaining = readCount$1(body) - 1;
|
|
2829
|
+
if (remaining > 0) {
|
|
2830
|
+
body.setAttribute(COUNT_ATTRIBUTE$1, String(remaining));
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2833
|
+
if (remaining < 0) {
|
|
2834
|
+
return;
|
|
2835
|
+
}
|
|
2836
|
+
body.removeAttribute(COUNT_ATTRIBUTE$1);
|
|
2837
|
+
var _a = takeRestorePoint(body), scrollY = _a.scrollY, inlineStyles = _a.inlineStyles;
|
|
2838
|
+
PINNED_PROPERTIES.forEach(function (property) {
|
|
2839
|
+
if (inlineStyles[property]) {
|
|
2840
|
+
body.style.setProperty(property, inlineStyles[property]);
|
|
2841
|
+
}
|
|
2842
|
+
else {
|
|
2843
|
+
body.style.removeProperty(property);
|
|
2844
|
+
}
|
|
2845
|
+
});
|
|
2846
|
+
// An empty `style=""` on the host page's body is untidy and is not what we found.
|
|
2847
|
+
if (!body.style.length) {
|
|
2848
|
+
body.removeAttribute("style");
|
|
2849
|
+
}
|
|
2850
|
+
window.scrollTo(0, scrollY);
|
|
2851
|
+
};
|
|
2852
|
+
}
|
|
2853
|
+
/**
|
|
2854
|
+
* Lock the body scroll for as long as the calling component is mounted.
|
|
2855
|
+
*
|
|
2856
|
+
* The cleanup runs on unmount, so a modal that disappears without a clean close — a route
|
|
2857
|
+
* change, a parent re-render, an error boundary — still leaves the page scrollable.
|
|
2858
|
+
*/
|
|
2859
|
+
function useBodyScrollLock(enabled) {
|
|
2860
|
+
if (enabled === void 0) { enabled = true; }
|
|
2861
|
+
react.useEffect(function () {
|
|
2862
|
+
if (!enabled) {
|
|
2863
|
+
return undefined;
|
|
2864
|
+
}
|
|
2865
|
+
return lockBodyScroll();
|
|
2866
|
+
}, [enabled]);
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
/**
|
|
2870
|
+
* Publish the visual viewport's geometry as CSS custom properties, so overlays can size
|
|
2871
|
+
* themselves around the soft keyboard.
|
|
2872
|
+
*
|
|
2873
|
+
* We are an **embedded** widget: the customer owns the host page's `<meta name="viewport">`,
|
|
2874
|
+
* so we cannot add `interactive-widget=resizes-content` and let the browser solve this for
|
|
2875
|
+
* us. Reading `window.visualViewport` ourselves is the only mechanism we control. (Injecting
|
|
2876
|
+
* or mutating the host's viewport meta is not an option — it is not ours, and breaking it
|
|
2877
|
+
* breaks the whole page in ways nobody would attribute to us.)
|
|
2878
|
+
*
|
|
2879
|
+
* Three properties are published on `<html>`:
|
|
2880
|
+
*
|
|
2881
|
+
* --xapp-viewport-height the visible height, in px
|
|
2882
|
+
* --xapp-viewport-offset-top how far the visual viewport has been scrolled down within
|
|
2883
|
+
* the layout viewport — nonzero on iOS when the keyboard
|
|
2884
|
+
* pushes the page up
|
|
2885
|
+
* --xapp-keyboard-inset layout height minus visual height: how much the keyboard
|
|
2886
|
+
* (or any other browser UI) is covering
|
|
2887
|
+
*
|
|
2888
|
+
* `--xapp-keyboard-inset` is the one worth having. It is what a `padding-bottom` wants, and
|
|
2889
|
+
* deriving it here means the consuming CSS does not have to do arithmetic across two
|
|
2890
|
+
* variables that update at slightly different moments.
|
|
2891
|
+
*
|
|
2892
|
+
* Reference counted on the DOM, for the same reason `bodyScrollLock` is: chat-widget's
|
|
2893
|
+
* `FormModal` loads the **standalone** form-widget bundle, which carries its own copy of
|
|
2894
|
+
* this module. Two independent copies can be live at once, and a module-scope counter would
|
|
2895
|
+
* not see across them. Without counting, closing the form modal while the chat panel is
|
|
2896
|
+
* still open (with the keyboard still up) would clear the properties out from under the
|
|
2897
|
+
* panel and snap it back to its fallback height mid-interaction.
|
|
2898
|
+
*/
|
|
2899
|
+
var HEIGHT_PROPERTY = "--xapp-viewport-height";
|
|
2900
|
+
var OFFSET_TOP_PROPERTY = "--xapp-viewport-offset-top";
|
|
2901
|
+
var KEYBOARD_INSET_PROPERTY = "--xapp-keyboard-inset";
|
|
2902
|
+
/** How many subscribers currently want these properties maintained. */
|
|
2903
|
+
var COUNT_ATTRIBUTE = "data-xapp-viewport-subscribers";
|
|
2904
|
+
/**
|
|
2905
|
+
* Below this, a shrunken viewport is treated as browser chrome rather than a keyboard.
|
|
2906
|
+
* Address bars collapse and expand by ~60-90px during normal scrolling, and reacting to
|
|
2907
|
+
* that would make the layout twitch while the user is only reading.
|
|
2908
|
+
*/
|
|
2909
|
+
var KEYBOARD_THRESHOLD_PX = 120;
|
|
2910
|
+
function readCount(root) {
|
|
2911
|
+
var count = Number(root.getAttribute(COUNT_ATTRIBUTE));
|
|
2912
|
+
return Number.isFinite(count) && count > 0 ? count : 0;
|
|
2913
|
+
}
|
|
2914
|
+
/**
|
|
2915
|
+
* Write the current geometry to `<html>`.
|
|
2916
|
+
*
|
|
2917
|
+
* Deliberately does nothing when `visualViewport` is unavailable: the consuming CSS falls
|
|
2918
|
+
* back to `100dvh`, which is correct-ish and certainly better than a zero height. Publishing
|
|
2919
|
+
* `0px` would collapse the widget entirely — a worse failure than the one being fixed.
|
|
2920
|
+
*/
|
|
2921
|
+
function publish(root) {
|
|
2922
|
+
var viewport = typeof window === "undefined" ? undefined : window.visualViewport;
|
|
2923
|
+
if (!viewport) {
|
|
2924
|
+
return;
|
|
2925
|
+
}
|
|
2926
|
+
var height = viewport.height, offsetTop = viewport.offsetTop;
|
|
2927
|
+
if (!(height > 0)) {
|
|
2928
|
+
// Mid-transition, or a browser reporting nonsense. Keep the last good values.
|
|
2929
|
+
return;
|
|
2930
|
+
}
|
|
2931
|
+
// window.innerHeight is the LAYOUT viewport, which the keyboard does not shrink on iOS.
|
|
2932
|
+
// The difference between the two is the occluded strip.
|
|
2933
|
+
var layoutHeight = window.innerHeight || height;
|
|
2934
|
+
var rawInset = Math.max(0, layoutHeight - height);
|
|
2935
|
+
var inset = rawInset >= KEYBOARD_THRESHOLD_PX ? rawInset : 0;
|
|
2936
|
+
root.style.setProperty(HEIGHT_PROPERTY, "".concat(Math.round(height), "px"));
|
|
2937
|
+
root.style.setProperty(OFFSET_TOP_PROPERTY, "".concat(Math.round(offsetTop), "px"));
|
|
2938
|
+
root.style.setProperty(KEYBOARD_INSET_PROPERTY, "".concat(Math.round(inset), "px"));
|
|
2939
|
+
}
|
|
2940
|
+
function clear(root) {
|
|
2941
|
+
root.style.removeProperty(HEIGHT_PROPERTY);
|
|
2942
|
+
root.style.removeProperty(OFFSET_TOP_PROPERTY);
|
|
2943
|
+
root.style.removeProperty(KEYBOARD_INSET_PROPERTY);
|
|
2944
|
+
}
|
|
2945
|
+
/**
|
|
2946
|
+
* Start publishing viewport geometry. Returns a release function.
|
|
2947
|
+
*
|
|
2948
|
+
* Imperative twin of {@link useVisualViewportProperties}, for callers outside React.
|
|
2949
|
+
*/
|
|
2950
|
+
function trackVisualViewport() {
|
|
2951
|
+
if (typeof document === "undefined") {
|
|
2952
|
+
return function () { return undefined; };
|
|
2953
|
+
}
|
|
2954
|
+
var root = document.documentElement;
|
|
2955
|
+
root.setAttribute(COUNT_ATTRIBUTE, String(readCount(root) + 1));
|
|
2956
|
+
publish(root);
|
|
2957
|
+
var viewport = typeof window === "undefined" ? undefined : window.visualViewport;
|
|
2958
|
+
var frame;
|
|
2959
|
+
var onChange = function () {
|
|
2960
|
+
// These fire many times per second through the keyboard animation. Coalescing to one
|
|
2961
|
+
// write per frame keeps us off the layout-thrash path.
|
|
2962
|
+
if (frame !== undefined) {
|
|
2963
|
+
return;
|
|
2964
|
+
}
|
|
2965
|
+
frame = window.requestAnimationFrame(function () {
|
|
2966
|
+
frame = undefined;
|
|
2967
|
+
publish(root);
|
|
2968
|
+
});
|
|
2969
|
+
};
|
|
2970
|
+
// `scroll` matters as much as `resize`: on iOS the keyboard scrolls the visual viewport
|
|
2971
|
+
// within the layout viewport, and offsetTop only changes on that event.
|
|
2972
|
+
viewport === null || viewport === void 0 ? void 0 : viewport.addEventListener("resize", onChange);
|
|
2973
|
+
viewport === null || viewport === void 0 ? void 0 : viewport.addEventListener("scroll", onChange);
|
|
2974
|
+
var released = false;
|
|
2975
|
+
return function () {
|
|
2976
|
+
if (released) {
|
|
2977
|
+
return;
|
|
2978
|
+
}
|
|
2979
|
+
released = true;
|
|
2980
|
+
viewport === null || viewport === void 0 ? void 0 : viewport.removeEventListener("resize", onChange);
|
|
2981
|
+
viewport === null || viewport === void 0 ? void 0 : viewport.removeEventListener("scroll", onChange);
|
|
2982
|
+
if (frame !== undefined) {
|
|
2983
|
+
window.cancelAnimationFrame(frame);
|
|
2984
|
+
frame = undefined;
|
|
2985
|
+
}
|
|
2986
|
+
var remaining = readCount(root) - 1;
|
|
2987
|
+
if (remaining > 0) {
|
|
2988
|
+
root.setAttribute(COUNT_ATTRIBUTE, String(remaining));
|
|
2989
|
+
return;
|
|
2990
|
+
}
|
|
2991
|
+
root.removeAttribute(COUNT_ATTRIBUTE);
|
|
2992
|
+
clear(root);
|
|
2993
|
+
};
|
|
2994
|
+
}
|
|
2995
|
+
/**
|
|
2996
|
+
* Publish viewport geometry for as long as this component is mounted.
|
|
2997
|
+
*
|
|
2998
|
+
* @param enabled pass `false` to opt out — e.g. above the mobile breakpoint, where there is
|
|
2999
|
+
* no soft keyboard to work around and the desktop sizing should stand.
|
|
3000
|
+
*/
|
|
3001
|
+
function useVisualViewportProperties(enabled) {
|
|
3002
|
+
if (enabled === void 0) { enabled = true; }
|
|
3003
|
+
react.useEffect(function () {
|
|
3004
|
+
if (!enabled) {
|
|
3005
|
+
return undefined;
|
|
3006
|
+
}
|
|
3007
|
+
return trackVisualViewport();
|
|
3008
|
+
}, [enabled]);
|
|
3009
|
+
}
|
|
3010
|
+
|
|
2705
3011
|
/**
|
|
2706
3012
|
* Quicker configurable uuid
|
|
2707
3013
|
*
|
|
@@ -2728,7 +3034,9 @@ var SuggestionsList_1 = SuggestionsList;
|
|
|
2728
3034
|
var findItemByIndex_1 = findItemByIndex;
|
|
2729
3035
|
var getItemsLength_1 = getItemsLength;
|
|
2730
3036
|
var parseSuggestionsResponse_1 = parseSuggestionsResponse;
|
|
3037
|
+
var useBodyScrollLock_1 = useBodyScrollLock;
|
|
2731
3038
|
var useSuggestionsFetch_1 = useSuggestionsFetch$1;
|
|
3039
|
+
var useVisualViewportProperties_1 = useVisualViewportProperties;
|
|
2732
3040
|
var uuid_1 = uuid;
|
|
2733
3041
|
|
|
2734
3042
|
var cjs = {};
|
|
@@ -12116,85 +12424,15 @@ var AdminBar = function (_a) {
|
|
|
12116
12424
|
return (jsx("div", { className: "xappw-admin-input-container visible", children: joined ? renderLeave() : renderJoin() }));
|
|
12117
12425
|
};
|
|
12118
12426
|
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
/* global define */
|
|
12129
|
-
|
|
12130
|
-
(function () {
|
|
12131
|
-
|
|
12132
|
-
var hasOwn = {}.hasOwnProperty;
|
|
12133
|
-
|
|
12134
|
-
function classNames () {
|
|
12135
|
-
var classes = '';
|
|
12136
|
-
|
|
12137
|
-
for (var i = 0; i < arguments.length; i++) {
|
|
12138
|
-
var arg = arguments[i];
|
|
12139
|
-
if (arg) {
|
|
12140
|
-
classes = appendClass(classes, parseValue(arg));
|
|
12141
|
-
}
|
|
12142
|
-
}
|
|
12143
|
-
|
|
12144
|
-
return classes;
|
|
12145
|
-
}
|
|
12146
|
-
|
|
12147
|
-
function parseValue (arg) {
|
|
12148
|
-
if (typeof arg === 'string' || typeof arg === 'number') {
|
|
12149
|
-
return arg;
|
|
12150
|
-
}
|
|
12151
|
-
|
|
12152
|
-
if (typeof arg !== 'object') {
|
|
12153
|
-
return '';
|
|
12154
|
-
}
|
|
12155
|
-
|
|
12156
|
-
if (Array.isArray(arg)) {
|
|
12157
|
-
return classNames.apply(null, arg);
|
|
12158
|
-
}
|
|
12159
|
-
|
|
12160
|
-
if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {
|
|
12161
|
-
return arg.toString();
|
|
12162
|
-
}
|
|
12163
|
-
|
|
12164
|
-
var classes = '';
|
|
12165
|
-
|
|
12166
|
-
for (var key in arg) {
|
|
12167
|
-
if (hasOwn.call(arg, key) && arg[key]) {
|
|
12168
|
-
classes = appendClass(classes, key);
|
|
12169
|
-
}
|
|
12170
|
-
}
|
|
12171
|
-
|
|
12172
|
-
return classes;
|
|
12173
|
-
}
|
|
12174
|
-
|
|
12175
|
-
function appendClass (value, newClass) {
|
|
12176
|
-
if (!newClass) {
|
|
12177
|
-
return value;
|
|
12178
|
-
}
|
|
12179
|
-
|
|
12180
|
-
if (value) {
|
|
12181
|
-
return value + ' ' + newClass;
|
|
12182
|
-
}
|
|
12183
|
-
|
|
12184
|
-
return value + newClass;
|
|
12185
|
-
}
|
|
12186
|
-
|
|
12187
|
-
if (module.exports) {
|
|
12188
|
-
classNames.default = classNames;
|
|
12189
|
-
module.exports = classNames;
|
|
12190
|
-
} else {
|
|
12191
|
-
window.classNames = classNames;
|
|
12192
|
-
}
|
|
12193
|
-
}());
|
|
12194
|
-
} (classnames));
|
|
12195
|
-
|
|
12196
|
-
var classnamesExports = classnames.exports;
|
|
12197
|
-
var classNames = /*@__PURE__*/getDefaultExportFromCjs(classnamesExports);
|
|
12427
|
+
/**
|
|
12428
|
+
* Joins the keys of `classes` whose value is truthy into a single
|
|
12429
|
+
* space-separated string. Local replacement for the `classnames` package.
|
|
12430
|
+
*/
|
|
12431
|
+
function classNames(classes) {
|
|
12432
|
+
return Object.keys(classes)
|
|
12433
|
+
.filter(function (key) { return classes[key]; })
|
|
12434
|
+
.join(" ");
|
|
12435
|
+
}
|
|
12198
12436
|
|
|
12199
12437
|
var MarkdownBuilder = function (_a) {
|
|
12200
12438
|
var text = _a.text, applyBrandingClass = _a.applyBrandingClass, linkColor = _a.linkColor;
|
|
@@ -12544,14 +12782,11 @@ var FormModal = function (_a) {
|
|
|
12544
12782
|
document.removeEventListener("keydown", handleKeyDown);
|
|
12545
12783
|
};
|
|
12546
12784
|
}, [onClose]);
|
|
12547
|
-
// Prevent body scroll when modal is open
|
|
12548
|
-
|
|
12549
|
-
|
|
12550
|
-
|
|
12551
|
-
|
|
12552
|
-
document.body.style.overflow = originalOverflow;
|
|
12553
|
-
};
|
|
12554
|
-
}, []);
|
|
12785
|
+
// Prevent body scroll when modal is open.
|
|
12786
|
+
//
|
|
12787
|
+
// This used to set `body { overflow: hidden }` directly, which iOS Safari ignores - the
|
|
12788
|
+
// host page scrolled on underneath the open modal.
|
|
12789
|
+
useBodyScrollLock_1();
|
|
12555
12790
|
// Focus trap - focus the modal content on mount
|
|
12556
12791
|
useEffect(function () {
|
|
12557
12792
|
if (contentRef.current) {
|
|
@@ -35542,6 +35777,20 @@ var createQueueWithTimer = (timeout) => {
|
|
|
35542
35777
|
setTimeout(notify, timeout);
|
|
35543
35778
|
};
|
|
35544
35779
|
};
|
|
35780
|
+
var createRafWithFallbackTimer = (raf, timeout) => {
|
|
35781
|
+
return (notify) => {
|
|
35782
|
+
let called = false;
|
|
35783
|
+
const callback = () => {
|
|
35784
|
+
if (called) return;
|
|
35785
|
+
called = true;
|
|
35786
|
+
cancelAnimationFrame(rafId);
|
|
35787
|
+
clearTimeout(timerId);
|
|
35788
|
+
notify();
|
|
35789
|
+
};
|
|
35790
|
+
const rafId = raf(callback);
|
|
35791
|
+
const timerId = setTimeout(callback, timeout);
|
|
35792
|
+
};
|
|
35793
|
+
};
|
|
35545
35794
|
var autoBatchEnhancer = (options = {
|
|
35546
35795
|
type: "raf"
|
|
35547
35796
|
}) => (next) => (...args) => {
|
|
@@ -35552,7 +35801,7 @@ var autoBatchEnhancer = (options = {
|
|
|
35552
35801
|
const listeners = /* @__PURE__ */ new Set();
|
|
35553
35802
|
const queueCallback = options.type === "tick" ? queueMicrotask : options.type === "raf" ? (
|
|
35554
35803
|
// requestAnimationFrame won't exist in SSR environments. Fall back to a vague approximation just to keep from erroring.
|
|
35555
|
-
typeof window !== "undefined" && window.requestAnimationFrame ? window.requestAnimationFrame : createQueueWithTimer(10)
|
|
35804
|
+
typeof window !== "undefined" && window.requestAnimationFrame ? createRafWithFallbackTimer(window.requestAnimationFrame, 100) : createQueueWithTimer(10)
|
|
35556
35805
|
) : options.type === "callback" ? options.queueNotification : createQueueWithTimer(options.timeout);
|
|
35557
35806
|
const notifyListeners = () => {
|
|
35558
35807
|
notificationQueued = false;
|
|
@@ -35874,6 +36123,14 @@ var ChatWidgetUI = function (props) {
|
|
|
35874
36123
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13;
|
|
35875
36124
|
var innerDispatch = useChatDispatch();
|
|
35876
36125
|
var dispatch = useChatServerDispatch();
|
|
36126
|
+
// Publish the visual viewport's geometry so the panel can size around the soft keyboard.
|
|
36127
|
+
//
|
|
36128
|
+
// Mounted unconditionally rather than behind a width check, and the mobile-only scoping
|
|
36129
|
+
// lives in ChatWidget.scss instead: only the max-width: 640px block reads
|
|
36130
|
+
// --xapp-keyboard-inset, so on desktop this publishes properties nothing consumes and
|
|
36131
|
+
// behaviour is unchanged. A width check here would mean a fourth hardcoded 640 in a
|
|
36132
|
+
// codebase where that duplication is already an open issue (#1561).
|
|
36133
|
+
useVisualViewportProperties_1();
|
|
35877
36134
|
// From Redux
|
|
35878
36135
|
var chatState = useSelector(function (state) { return state; });
|
|
35879
36136
|
// Refresh modalReference
|