UNPKG

react-instantsearch

Version:
382 lines (380 loc) 19.6 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: Object.getOwnPropertyDescriptor(all, name).get }); } _export(exports, { get Chat () { return Chat; }, get DisplayResultsToolType () { return _chat.DisplayResultsToolType; }, get GroupedResultsToolType () { return _chat.GroupedResultsToolType; }, get MemorizeToolType () { return _chat.MemorizeToolType; }, get MemorySearchToolType () { return _chat.MemorySearchToolType; }, get PonderToolType () { return _chat.PonderToolType; }, get RecommendToolType () { return _chat.RecommendToolType; }, get SearchIndexToolType () { return _chat.SearchIndexToolType; }, get createDefaultTools () { return createDefaultTools; } }); var _call_super = require("@swc/helpers/_/_call_super"); var _class_call_check = require("@swc/helpers/_/_class_call_check"); var _create_class = require("@swc/helpers/_/_create_class"); var _define_property = require("@swc/helpers/_/_define_property"); var _inherits = require("@swc/helpers/_/_inherits"); var _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard"); var _object_spread = require("@swc/helpers/_/_object_spread"); var _object_spread_props = require("@swc/helpers/_/_object_spread_props"); var _object_without_properties = require("@swc/helpers/_/_object_without_properties"); var _sliced_to_array = require("@swc/helpers/_/_sliced_to_array"); var _to_array = require("@swc/helpers/_/_to_array"); var _to_consumable_array = require("@swc/helpers/_/_to_consumable_array"); var _instantsearchuicomponents = require("instantsearch-ui-components"); var _chat = require("instantsearch.js/cjs/lib/chat"); var _focusAfterReveal = require("instantsearch.js/cjs/lib/chat/focusAfterReveal"); var _react = /*#__PURE__*/ _interop_require_wildcard._(require("react")); var _reactinstantsearchcore = require("react-instantsearch-core"); var _useStickToBottom = require("../lib/useStickToBottom"); var _DisplayResultsTool = require("./chat/tools/DisplayResultsTool"); var _SearchIndexTool = require("./chat/tools/SearchIndexTool"); var ChatUiComponent = (0, _instantsearchuicomponents.createChatComponent)({ createElement: _react.createElement, Fragment: _react.Fragment, useMemo: _react.useMemo, useState: _react.useState, useEffect: _react.useEffect }); function createDefaultTools(itemComponent, getSearchPageURL) { var _obj; return _obj = {}, _define_property._(_obj, _chat.SearchIndexToolType, _object_spread_props._(_object_spread._({}, (0, _SearchIndexTool.createCarouselTool)(true, itemComponent, getSearchPageURL)), { // The agent decides per turn whether the richer Grouped Results tool // takes over the rendering of the search results. shouldRender: isDisplayResultsDisabled })), _define_property._(_obj, _chat.RecommendToolType, (0, _SearchIndexTool.createCarouselTool)(false, itemComponent, getSearchPageURL)), _define_property._(_obj, _chat.DisplayResultsToolType, (0, _DisplayResultsTool.createGroupedResultsTool)(itemComponent)), _define_property._(_obj, _chat.GroupedResultsToolType, (0, _DisplayResultsTool.createGroupedResultsTool)(itemComponent)), _define_property._(_obj, _chat.MemorizeToolType, {}), _define_property._(_obj, _chat.MemorySearchToolType, {}), _define_property._(_obj, _chat.PonderToolType, {}), _obj; } /** * Whether the search tool renders its own results, i.e. the agent did not hand * the turn to the Grouped Results tool. Set on the message by the backend. */ function isDisplayResultsDisabled(param) { var parentMessage = param.parentMessage; var _parentMessage_metadata; return ((_parentMessage_metadata = parentMessage.metadata) === null || _parentMessage_metadata === void 0 ? void 0 : _parentMessage_metadata.displayResultsEnabled) !== true; } function mergeToolOptions(defaultTools, userTools) { if (!userTools) { return defaultTools; } var tools = _object_spread._({}, defaultTools, userTools); Object.keys(userTools).forEach(function(toolName) { var userTool = userTools[toolName]; var defaultTool = defaultTools[toolName]; var defaultStreamInput = defaultTool === null || defaultTool === void 0 ? void 0 : defaultTool.streamInput; if (userTool.layoutComponent !== undefined && userTool.streamInput === undefined && defaultStreamInput !== undefined) { tools[toolName] = _object_spread_props._(_object_spread._({}, tools[toolName]), { streamInput: defaultStreamInput }); } // Overriding a tool's rendering shouldn't opt it out of the conditions // under which the default renders at all. if (userTool.shouldRender === undefined && (defaultTool === null || defaultTool === void 0 ? void 0 : defaultTool.shouldRender)) { tools[toolName] = _object_spread_props._(_object_spread._({}, tools[toolName]), { shouldRender: defaultTool.shouldRender }); } }); return tools; } var AnimationSnapshot = /*#__PURE__*/ function(_React_Component) { _inherits._(AnimationSnapshot, _React_Component); function AnimationSnapshot() { _class_call_check._(this, AnimationSnapshot); return _call_super._(this, AnimationSnapshot, arguments); } _create_class._(AnimationSnapshot, [ { key: "getSnapshotBeforeUpdate", value: function getSnapshotBeforeUpdate() { return (0, _focusAfterReveal.getActiveContainerAnimations)(this.props.promptRef.current); } }, { key: "componentDidUpdate", value: function componentDidUpdate(_previousProps, _previousState, animationsBeforeReveal) { this.props.animationsBeforeReveal.current = animationsBeforeReveal; if (!_previousProps.open && this.props.open) { (0, _focusAfterReveal.holdContainerInertUntilReveal)(this.props.promptRef.current); } else if (this.props.open) { (0, _focusAfterReveal.restoreContainerInertUntilReveal)(this.props.promptRef.current); } } }, { key: "render", value: function render() { return null; } } ]); return AnimationSnapshot; }(_react.default.Component); function ChatInner(_0, _1) { var _ref = [ _0, _1 ], _ref1 = _to_array._(_ref), _ref2 = _ref1[0], _rest = _ref1.slice(1), userTools = _ref2.tools, headerProps = _ref2.headerProps, messagesProps = _ref2.messagesProps, promptProps = _ref2.promptProps, itemComponent = _ref2.itemComponent, layoutComponent = _ref2.layoutComponent, headerComponent = _ref2.headerComponent, headerTitleIconComponent = _ref2.headerTitleIconComponent, headerCloseIconComponent = _ref2.headerCloseIconComponent, headerMinimizeIconComponent = _ref2.headerMinimizeIconComponent, headerMaximizeIconComponent = _ref2.headerMaximizeIconComponent, loaderComponent = _ref2.loaderComponent, loaderPosition = _ref2.loaderPosition, shouldShowLoader = _ref2.shouldShowLoader, loaderShowDelay = _ref2.loaderShowDelay, loaderMinDuration = _ref2.loaderMinDuration, messagesErrorComponent = _ref2.messagesErrorComponent, promptComponent = _ref2.promptComponent, promptHeaderComponent = _ref2.promptHeaderComponent, promptFooterComponent = _ref2.promptFooterComponent, assistantMessageLeadingComponent = _ref2.assistantMessageLeadingComponent, assistantMessageFooterComponent = _ref2.assistantMessageFooterComponent, userMessageLeadingComponent = _ref2.userMessageLeadingComponent, userMessageFooterComponent = _ref2.userMessageFooterComponent, emptyComponent = _ref2.emptyComponent, actionsComponent = _ref2.actionsComponent, suggestionsComponent = _ref2.suggestionsComponent, classNames = _ref2.classNames, _ref_translations = _ref2.translations, translations = _ref_translations === void 0 ? {} : _ref_translations, title = _ref2.title, getSearchPageURL = _ref2.getSearchPageURL, _ref_disableTriggerValidation = _ref2.disableTriggerValidation, disableTriggerValidation = _ref_disableTriggerValidation === void 0 ? false : _ref_disableTriggerValidation, showReasoning = _ref2.showReasoning, reasoningComponent = _ref2.reasoningComponent, props = _object_without_properties._(_ref2, [ "tools", "headerProps", "messagesProps", "promptProps", "itemComponent", "layoutComponent", "headerComponent", "headerTitleIconComponent", "headerCloseIconComponent", "headerMinimizeIconComponent", "headerMaximizeIconComponent", "loaderComponent", "loaderPosition", "shouldShowLoader", "loaderShowDelay", "loaderMinDuration", "messagesErrorComponent", "promptComponent", "promptHeaderComponent", "promptFooterComponent", "assistantMessageLeadingComponent", "assistantMessageFooterComponent", "userMessageLeadingComponent", "userMessageFooterComponent", "emptyComponent", "actionsComponent", "suggestionsComponent", "classNames", "translations", "title", "getSearchPageURL", "disableTriggerValidation", "showReasoning", "reasoningComponent" ]), _rest1 = _sliced_to_array._(_rest, 1), ref = _rest1[0]; var _ref3; var promptTranslations = translations.prompt, headerTranslations = translations.header, messageTranslations = translations.message, messagesTranslations = translations.messages; var _useInstantSearch = (0, _reactinstantsearchcore.useInstantSearch)(), indexUiState = _useInstantSearch.indexUiState, setIndexUiState = _useInstantSearch.setIndexUiState; var _useState = _sliced_to_array._((0, _react.useState)(false), 2), maximized = _useState[0], setMaximized = _useState[1]; var promptRef = (0, _react.useRef)(null); var focusRequestId = (0, _react.useRef)(0); var animationsBeforeReveal = (0, _react.useRef)([]); var _useStickToBottom1 = (0, _useStickToBottom.useStickToBottom)({ initial: 'smooth', resize: 'smooth' }), scrollRef = _useStickToBottom1.scrollRef, contentRef = _useStickToBottom1.contentRef, scrollToBottom = _useStickToBottom1.scrollToBottom, isAtBottom = _useStickToBottom1.isAtBottom; var tools = (0, _react.useMemo)(function() { var defaults = createDefaultTools(itemComponent, getSearchPageURL); return mergeToolOptions(defaults, userTools); }, [ getSearchPageURL, itemComponent, userTools ]); // Inline layouts are always visible, so they don't require a `<ChatTrigger />` // (or AI mode) to be present. We detect this via a `$$inlineLayout` marker // set on the layout component, which is consistent across flavors. var isInlineLayoutComponent = typeof layoutComponent === 'function' && layoutComponent.$$inlineLayout === true; var effectiveDisableTriggerValidation = disableTriggerValidation || isInlineLayoutComponent; var chatState = (0, _reactinstantsearchcore.useChat)(_object_spread_props._(_object_spread._({}, props), { tools: tools, disableTriggerValidation: effectiveDisableTriggerValidation })); var messages = chatState.messages, sendMessage = chatState.sendMessage, status = chatState.status, regenerate = chatState.regenerate, stop = chatState.stop, error = chatState.error, input = chatState.input, setInput = chatState.setInput, open = chatState.open, setOpen = chatState.setOpen, clearMessages = chatState.clearMessages, toolsFromConnector = chatState.tools, suggestions = chatState.suggestions, onFeedback = chatState.sendChatMessageFeedback, feedbackState = chatState.feedbackState, consumeInputFocus = chatState['~consumeInputFocus'], isOpenStatePersistenceEnabled = chatState['~isOpenStatePersistenceEnabled']; var sendMessageAndScrollToBottom = (0, _react.useCallback)(function() { for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){ args[_key] = arguments[_key]; } scrollToBottom(); return sendMessage.apply(void 0, _to_consumable_array._(args)); }, [ scrollToBottom, sendMessage ]); (0, _react.useImperativeHandle)(ref, function() { return { setOpen: setOpen, sendMessage: function sendMessage(params) { return sendMessageAndScrollToBottom(params); }, setInput: setInput }; }); (0, _react.useEffect)(function() { if (!open) { focusRequestId.current++; return; } if (consumeInputFocus === null || consumeInputFocus === void 0 ? void 0 : consumeInputFocus()) { var currentFocusRequestId = ++focusRequestId.current; var previousAnimations = animationsBeforeReveal.current; (0, _focusAfterReveal.holdContainerInertUntilReveal)(promptRef.current); window.requestAnimationFrame(function() { var prompt = promptRef.current; (0, _focusAfterReveal.focusAfterReveal)(prompt, previousAnimations, function() { return focusRequestId.current === currentFocusRequestId && promptRef.current === prompt; }, function() { return focusRequestId.current === currentFocusRequestId; }); }); } }); // Keep the conversation pinned to the bottom while streaming. The stick-to- // bottom ResizeObserver only reacts to content *height* changes, but tool // results such as a horizontally-growing carousel stream in without changing // height — so we also re-pin on every message/status update. Passing // `preserveScrollPosition` reuses the existing "only if already at the // bottom" gate, so this never fights a user who has scrolled up to read. (0, _react.useEffect)(function() { if (status === 'streaming' || status === 'submitted') { scrollToBottom({ preserveScrollPosition: true }); } }, [ messages, status, scrollToBottom ]); var _ref4 = messagesProps !== null && messagesProps !== void 0 ? messagesProps : {}, callerAssistantMessageProps = _ref4.assistantMessageProps, callerUserMessageProps = _ref4.userMessageProps, restMessagesProps = _object_without_properties._(_ref4, [ "assistantMessageProps", "userMessageProps" ]); var chat = /*#__PURE__*/ _react.default.createElement(ChatUiComponent, { title: title, open: open, maximized: maximized, sendMessage: sendMessageAndScrollToBottom, regenerate: regenerate, stop: stop, error: error, layoutComponent: layoutComponent, headerComponent: headerComponent, promptComponent: promptComponent, suggestionsComponent: suggestionsComponent, headerProps: _object_spread._({ onClose: function onClose() { return setOpen(false); }, maximized: maximized, onToggleMaximize: function onToggleMaximize() { return setMaximized(!maximized); }, onClear: clearMessages, canClear: Boolean(messages === null || messages === void 0 ? void 0 : messages.length), titleIconComponent: headerTitleIconComponent, closeIconComponent: headerCloseIconComponent, minimizeIconComponent: headerMinimizeIconComponent, maximizeIconComponent: headerMaximizeIconComponent, translations: headerTranslations }, headerProps), messagesProps: _object_spread_props._(_object_spread._({ status: status, onReload: function onReload(messageId) { return regenerate({ messageId: messageId }); }, onNewConversation: clearMessages, onClose: function onClose() { return setOpen(false); }, sendMessage: sendMessageAndScrollToBottom, setInput: setInput, onFeedback: onFeedback, feedbackState: feedbackState, messages: messages, tools: toolsFromConnector, indexUiState: indexUiState, setIndexUiState: setIndexUiState, isScrollAtBottom: isAtBottom, scrollRef: scrollRef, contentRef: contentRef, onScrollToBottom: scrollToBottom, loaderComponent: loaderComponent, loaderPosition: loaderPosition, shouldShowLoader: shouldShowLoader, loaderShowDelay: loaderShowDelay, loaderMinDuration: loaderMinDuration, errorComponent: messagesErrorComponent, emptyComponent: emptyComponent, actionsComponent: actionsComponent, translations: messagesTranslations, messageTranslations: messageTranslations }, restMessagesProps), { assistantMessageProps: _object_spread._({ leadingComponent: assistantMessageLeadingComponent, footerComponent: assistantMessageFooterComponent, showReasoning: showReasoning, reasoningComponent: reasoningComponent }, callerAssistantMessageProps), userMessageProps: _object_spread._({ leadingComponent: userMessageLeadingComponent, footerComponent: userMessageFooterComponent }, callerUserMessageProps), error: error }), promptProps: _object_spread_props._(_object_spread._({ promptRef: promptRef, status: status, value: input, translations: promptTranslations, onInput: function onInput(event) { setInput(event.currentTarget.value); }, onSubmit: function onSubmit() { sendMessageAndScrollToBottom({ text: input }); setInput(''); }, onStop: function onStop() { stop(); }, headerComponent: promptHeaderComponent, footerComponent: promptFooterComponent }, promptProps), { autoFocus: (_ref3 = promptProps === null || promptProps === void 0 ? void 0 : promptProps.autoFocus) !== null && _ref3 !== void 0 ? _ref3 : !isOpenStatePersistenceEnabled || isInlineLayoutComponent }), suggestionsProps: { suggestions: suggestions, onSuggestionClick: function onSuggestionClick(suggestion) { sendMessageAndScrollToBottom({ text: suggestion }); } }, classNames: classNames }); return /*#__PURE__*/ _react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/ _react.default.createElement(AnimationSnapshot, { promptRef: promptRef, animationsBeforeReveal: animationsBeforeReveal, open: open }), chat); } var Chat = /*#__PURE__*/ _react.default.forwardRef(ChatInner);