@droppii-org/chat-sdk 0.6.39 → 0.6.40
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/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationDetailInput.js +9 -0
- package/dist/hooks/common/useOutsideTapDismiss.d.ts +12 -0
- package/dist/hooks/common/useOutsideTapDismiss.d.ts.map +1 -0
- package/dist/hooks/common/useOutsideTapDismiss.js +81 -0
- package/dist/screens/conversation-detail/index.d.ts.map +1 -1
- package/dist/screens/conversation-detail/index.js +2 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAoB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,wEAAwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,uBAAuB,GAAI,yFAO9B,4BAA4B,4CA0vB9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -15,6 +15,7 @@ import useMessageDraftStore from "../../store/messageDraft";
|
|
|
15
15
|
import { emit } from "../../utils/events";
|
|
16
16
|
import { extractLinkUrls } from "../../utils/link";
|
|
17
17
|
import { useFetchUrlMetadata } from "../../hooks/common/useFetchUrlMetadata";
|
|
18
|
+
import { useOutsideTapDismiss } from "../../hooks/common/useOutsideTapDismiss";
|
|
18
19
|
import { processAndValidateDocuments, processAndValidateFiles, } from "../../utils/fileValidation";
|
|
19
20
|
import { FilePreviewList } from "../../components/message/footer/FilePreview";
|
|
20
21
|
import LinkInputPreview from "../../components/message/footer/LinkInputPreview";
|
|
@@ -97,6 +98,14 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
|
|
|
97
98
|
const [previewDismissed, setPreviewDismissed] = useState(false);
|
|
98
99
|
const [isMoreOptionOpen, { setFalse: closeMoreOption, toggle: toggleMoreOption },] = useBoolean(false);
|
|
99
100
|
const [isStickerOpen, { setFalse: closeSticker, toggle: toggleSticker },] = useBoolean(false);
|
|
101
|
+
useOutsideTapDismiss({
|
|
102
|
+
enabled: isMoreOptionOpen || isStickerOpen,
|
|
103
|
+
insideRef: containerRef,
|
|
104
|
+
onDismiss: () => {
|
|
105
|
+
closeMoreOption();
|
|
106
|
+
closeSticker();
|
|
107
|
+
},
|
|
108
|
+
});
|
|
100
109
|
const [caretIndex, setCaretIndex] = useState(0);
|
|
101
110
|
const rawMentionTrigger = useMentionTrigger(value, caretIndex);
|
|
102
111
|
// Escape dismisses the menu for the CURRENT trigger span without erasing
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
/** Marks the area where a tap closes the open composer panel (the thread timeline). */
|
|
3
|
+
export declare const COMPOSER_DISMISS_ZONE_ATTR = "data-composer-dismiss-zone";
|
|
4
|
+
interface UseOutsideTapDismissOptions {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
/** Taps inside this element never dismiss (the composer and its panels). */
|
|
7
|
+
insideRef: RefObject<HTMLElement | null>;
|
|
8
|
+
onDismiss: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const useOutsideTapDismiss: ({ enabled, insideRef, onDismiss, }: UseOutsideTapDismissOptions) => void;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=useOutsideTapDismiss.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOutsideTapDismiss.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useOutsideTapDismiss.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,uFAAuF;AACvF,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;AAOvE,UAAU,2BAA2B;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzC,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AA6BD,eAAO,MAAM,oBAAoB,GAAI,oCAIlC,2BAA2B,SAuD7B,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
/** Marks the area where a tap closes the open composer panel (the thread timeline). */
|
|
3
|
+
export const COMPOSER_DISMISS_ZONE_ATTR = "data-composer-dismiss-zone";
|
|
4
|
+
// Past this much pointer travel the gesture is a scroll/drag, not a tap.
|
|
5
|
+
const TAP_MOVE_TOLERANCE_PX = 10;
|
|
6
|
+
// Upper bound for a click that never arrives (pointerup on another element).
|
|
7
|
+
const SWALLOW_FALLBACK_MS = 1000;
|
|
8
|
+
const isInDismissZone = (target, inside) => {
|
|
9
|
+
if (!(target instanceof Element))
|
|
10
|
+
return false;
|
|
11
|
+
if (inside === null || inside === void 0 ? void 0 : inside.contains(target))
|
|
12
|
+
return false;
|
|
13
|
+
return target.closest(`[${COMPOSER_DISMISS_ZONE_ATTR}]`) !== null;
|
|
14
|
+
};
|
|
15
|
+
// The dismissing tap's click must not hit what sits under it; the window ends at
|
|
16
|
+
// the next pointerdown, so a browser-delayed click is still swallowed.
|
|
17
|
+
const swallowNextClick = () => {
|
|
18
|
+
const stop = () => {
|
|
19
|
+
window.removeEventListener("click", swallow, { capture: true });
|
|
20
|
+
window.removeEventListener("pointerdown", stop, { capture: true });
|
|
21
|
+
clearTimeout(fallbackTimer);
|
|
22
|
+
};
|
|
23
|
+
const swallow = (event) => {
|
|
24
|
+
event.preventDefault();
|
|
25
|
+
event.stopImmediatePropagation();
|
|
26
|
+
stop();
|
|
27
|
+
};
|
|
28
|
+
window.addEventListener("click", swallow, { capture: true });
|
|
29
|
+
window.addEventListener("pointerdown", stop, { capture: true });
|
|
30
|
+
const fallbackTimer = setTimeout(stop, SWALLOW_FALLBACK_MS);
|
|
31
|
+
};
|
|
32
|
+
export const useOutsideTapDismiss = ({ enabled, insideRef, onDismiss, }) => {
|
|
33
|
+
const onDismissRef = useRef(onDismiss);
|
|
34
|
+
onDismissRef.current = onDismiss;
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!enabled)
|
|
37
|
+
return;
|
|
38
|
+
let tapStart = null;
|
|
39
|
+
const hasMoved = (event) => !!tapStart &&
|
|
40
|
+
Math.hypot(event.clientX - tapStart.x, event.clientY - tapStart.y) >
|
|
41
|
+
TAP_MOVE_TOLERANCE_PX;
|
|
42
|
+
// A second pointer landing mid-tap (pinch, two-finger touch) makes this a
|
|
43
|
+
// multi-touch gesture, so the pending tap is dropped rather than resumed.
|
|
44
|
+
const handlePointerDown = (event) => {
|
|
45
|
+
const isPrimaryTap = event.isPrimary !== false && event.button === 0;
|
|
46
|
+
tapStart =
|
|
47
|
+
isPrimaryTap && isInDismissZone(event.target, insideRef.current)
|
|
48
|
+
? { x: event.clientX, y: event.clientY, pointerId: event.pointerId }
|
|
49
|
+
: null;
|
|
50
|
+
};
|
|
51
|
+
const handlePointerMove = (event) => {
|
|
52
|
+
if ((tapStart === null || tapStart === void 0 ? void 0 : tapStart.pointerId) === event.pointerId && hasMoved(event)) {
|
|
53
|
+
tapStart = null;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const handlePointerUp = (event) => {
|
|
57
|
+
if (!tapStart || tapStart.pointerId !== event.pointerId)
|
|
58
|
+
return;
|
|
59
|
+
const isTap = !hasMoved(event) && isInDismissZone(event.target, insideRef.current);
|
|
60
|
+
tapStart = null;
|
|
61
|
+
if (!isTap)
|
|
62
|
+
return;
|
|
63
|
+
swallowNextClick();
|
|
64
|
+
onDismissRef.current();
|
|
65
|
+
};
|
|
66
|
+
// Touch scrolling cancels the pointer once the browser takes over the pan.
|
|
67
|
+
const handlePointerCancel = () => {
|
|
68
|
+
tapStart = null;
|
|
69
|
+
};
|
|
70
|
+
document.addEventListener("pointerdown", handlePointerDown, true);
|
|
71
|
+
document.addEventListener("pointermove", handlePointerMove, true);
|
|
72
|
+
document.addEventListener("pointerup", handlePointerUp, true);
|
|
73
|
+
document.addEventListener("pointercancel", handlePointerCancel, true);
|
|
74
|
+
return () => {
|
|
75
|
+
document.removeEventListener("pointerdown", handlePointerDown, true);
|
|
76
|
+
document.removeEventListener("pointermove", handlePointerMove, true);
|
|
77
|
+
document.removeEventListener("pointerup", handlePointerUp, true);
|
|
78
|
+
document.removeEventListener("pointercancel", handlePointerCancel, true);
|
|
79
|
+
};
|
|
80
|
+
}, [enabled, insideRef]);
|
|
81
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-detail/index.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAWrF,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,6CAA6C,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-detail/index.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAWrF,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,6CAA6C,CAAC;AAIrD,MAAM,WAAW,4BACf,SAAQ,4BAA4B,EAClC,4BAA4B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,uBAAuB,GAAI,8IAc9B,4BAA4B,mDAyO9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -30,6 +30,7 @@ import { useBotFlow } from "../../hooks/conversation/useBotFlow";
|
|
|
30
30
|
import { BOT_TYPE } from "../../constants/botFlow";
|
|
31
31
|
import { useResolveConversation, } from "../../hooks/conversation/useResolveConversation";
|
|
32
32
|
import { isBotPeer } from "../../utils/conversation";
|
|
33
|
+
import { COMPOSER_DISMISS_ZONE_ATTR } from "../../hooks/common/useOutsideTapDismiss";
|
|
33
34
|
const DChatConversationDetail = (_a) => {
|
|
34
35
|
var _b;
|
|
35
36
|
var { className, children, onBack, conversationId, messageId, userId, groupId, botId,
|
|
@@ -114,6 +115,6 @@ const DChatConversationDetail = (_a) => {
|
|
|
114
115
|
!botFlow.flowIsEnd &&
|
|
115
116
|
botFlow.shouldShowButtons &&
|
|
116
117
|
botFlow.currentButtonsBlock ? (_jsx(BotButtonMessage, { buttons: botFlow.currentButtonsBlock.data.buttons, disabled: botFlow.isProcessing, onSelect: botFlow.selectButton, onRestart: botFlow.restart })) : null;
|
|
117
|
-
return (_jsxs("div", { "data-testid": "conversation-detail-root", className: clsx("relative flex h-full w-full flex-col overflow-hidden bg-white", className), children: [_jsx(ConversationDetailHeader, { conversation: conversation, onBack: handleBack, onProfileClick: openProfile }), _jsx(PinnedMessageBar, {}), _jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [children !== null && children !== void 0 ? children : (_jsx(ConversationMessageList, { bottomSlot: botButtonsSlot, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked })), _jsx(TypingIndicatorBar, { conversationId: conversation.conversationID })] }), footer, isBotThread && (_jsxs(_Fragment, { children: [_jsx(BotMenuSheet, { open: isMenuOpen, items: botFlow.menuItems, disabled: botFlow.isProcessing, onClose: closeMenu, onSelect: botFlow.selectMenuOption }), _jsx(CsSessionConfirmModal, { open: botFlow.isCsConfirmOpen, loading: botFlow.isProcessing, onCancel: botFlow.cancelMenuOption, onConfirm: botFlow.confirmEndCsSession })] })), _jsx(ThreadProfilePanel, { open: isProfileOpen, conversation: conversation, onClose: closeProfile, onSelectResource: setResourceTab }), _jsx(MediaResourcePanel, { open: resourceTab !== null, initialTab: resourceTab !== null && resourceTab !== void 0 ? resourceTab : MediaResourceTabKey.Image, onClose: () => setResourceTab(null) })] }));
|
|
118
|
+
return (_jsxs("div", { "data-testid": "conversation-detail-root", className: clsx("relative flex h-full w-full flex-col overflow-hidden bg-white", className), children: [_jsx(ConversationDetailHeader, { conversation: conversation, onBack: handleBack, onProfileClick: openProfile }), _jsx(PinnedMessageBar, {}), _jsxs("div", { [COMPOSER_DISMISS_ZONE_ATTR]: "", className: "relative flex min-h-0 flex-1 flex-col", children: [children !== null && children !== void 0 ? children : (_jsx(ConversationMessageList, { bottomSlot: botButtonsSlot, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked })), _jsx(TypingIndicatorBar, { conversationId: conversation.conversationID })] }), footer, isBotThread && (_jsxs(_Fragment, { children: [_jsx(BotMenuSheet, { open: isMenuOpen, items: botFlow.menuItems, disabled: botFlow.isProcessing, onClose: closeMenu, onSelect: botFlow.selectMenuOption }), _jsx(CsSessionConfirmModal, { open: botFlow.isCsConfirmOpen, loading: botFlow.isProcessing, onCancel: botFlow.cancelMenuOption, onConfirm: botFlow.confirmEndCsSession })] })), _jsx(ThreadProfilePanel, { open: isProfileOpen, conversation: conversation, onClose: closeProfile, onSelectResource: setResourceTab }), _jsx(MediaResourcePanel, { open: resourceTab !== null, initialTab: resourceTab !== null && resourceTab !== void 0 ? resourceTab : MediaResourceTabKey.Image, onClose: () => setResourceTab(null) })] }));
|
|
118
119
|
};
|
|
119
120
|
export default DChatConversationDetail;
|