react-instantsearch
Version:
⚡ Lightning-fast search for React, by Algolia
382 lines (380 loc) • 19.6 kB
JavaScript
'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);