instantsearch-ui-components
Version:
Common UI components for InstantSearch.
279 lines (276 loc) • 15.2 kB
JavaScript
import { _ as _$1 } from '@swc/helpers/esm/_object_spread.js';
import { _ as _$2 } from '@swc/helpers/esm/_object_spread_props.js';
import { _ } from '@swc/helpers/esm/_object_without_properties.js';
import { _ as _$3 } from '@swc/helpers/esm/_to_consumable_array.js';
import { isPartText, isPartTool, findTool, hasTextContent, getTextContent } from '../../lib/utils/chat.js';
import { createButtonComponent } from '../Button.js';
import { createChatMessageComponent } from './ChatMessage.js';
import { createChatMessageErrorComponent } from './ChatMessageError.js';
import { createChatMessageLoaderComponent } from './ChatMessageLoader.js';
import { ChevronDownIcon, CopyIcon, ReloadIcon, LoadingSpinnerIcon, CheckIcon, ThumbsUpIcon, ThumbsDownIcon } from './icons.js';
import { cx } from '../../lib/cx.js';
var copyToClipboard = function copyToClipboard(message) {
navigator.clipboard.writeText(getTextContent(message));
};
function createDefaultMessageComponent(param) {
var createElement = param.createElement, Fragment = param.Fragment;
var ChatMessage = createChatMessageComponent({
createElement: createElement,
Fragment: Fragment
});
return function DefaultMessage(param) {
var message = param.message, status = param.status, userMessageProps = param.userMessageProps, assistantMessageProps = param.assistantMessageProps, tools = param.tools, indexUiState = param.indexUiState, setIndexUiState = param.setIndexUiState, onReload = param.onReload, onClose = param.onClose, onFeedback = param.onFeedback, feedbackState = param.feedbackState, actionsComponent = param.actionsComponent, classNames = param.classNames, messageTranslations = param.messageTranslations, translations = param.translations, suggestionsElement = param.suggestionsElement;
var defaultAssistantActions = _$3(hasTextContent(message) ? [
{
title: translations.copyToClipboardLabel,
icon: function icon() {
return /*#__PURE__*/ createElement(CopyIcon, {
createElement: createElement
});
},
onClick: copyToClipboard
}
] : []).concat([
{
title: translations.regenerateLabel,
icon: function icon() {
return /*#__PURE__*/ createElement(ReloadIcon, {
createElement: createElement
});
},
onClick: function onClick(m) {
return onReload(m.id);
}
}
]);
var messageFeedback = feedbackState === null || feedbackState === void 0 ? void 0 : feedbackState[message.id];
var hasVoted = messageFeedback !== undefined;
if (onFeedback) {
var isSending = messageFeedback === 'sending';
if (isSending) {
defaultAssistantActions.push({
title: translations.sendingFeedbackLabel,
icon: function icon() {
return /*#__PURE__*/ createElement("span", {
className: "ais-ChatMessage-feedbackSpinner"
}, /*#__PURE__*/ createElement(LoadingSpinnerIcon, {
createElement: createElement
}));
},
disabled: true
});
} else if (hasVoted) {
defaultAssistantActions.push({
title: translations.feedbackThankYouText,
icon: function icon() {
return /*#__PURE__*/ createElement("span", {
className: "ais-ChatMessage-feedbackCheck"
}, /*#__PURE__*/ createElement(CheckIcon, {
createElement: createElement
}), /*#__PURE__*/ createElement("span", {
className: "ais-ChatMessage-feedbackText"
}, translations.feedbackThankYouText));
},
disabled: true
});
} else {
defaultAssistantActions.push({
title: translations.thumbsUpLabel,
icon: function icon() {
return /*#__PURE__*/ createElement(ThumbsUpIcon, {
createElement: createElement
});
},
onClick: function onClick(m) {
return onFeedback(m.id, 1);
}
}, {
title: translations.thumbsDownLabel,
icon: function icon() {
return /*#__PURE__*/ createElement(ThumbsDownIcon, {
createElement: createElement
});
},
onClick: function onClick(m) {
return onFeedback(m.id, 0);
}
});
}
}
var messageProps = message.role === 'user' ? userMessageProps : assistantMessageProps;
var defaultActions = message.role === 'user' ? undefined : defaultAssistantActions;
return /*#__PURE__*/ createElement(ChatMessage, _$1({
side: message.role === 'user' ? 'right' : 'left',
variant: message.role === 'user' ? 'neutral' : 'subtle',
message: message,
status: status,
tools: tools,
indexUiState: indexUiState,
setIndexUiState: setIndexUiState,
onClose: onClose,
actions: defaultActions,
actionsComponent: actionsComponent,
"data-role": message.role,
classNames: classNames,
translations: messageTranslations,
suggestionsElement: suggestionsElement
}, messageProps));
};
}
function createChatMessagesComponent(param) {
var createElement = param.createElement, Fragment = param.Fragment;
var Button = createButtonComponent({
createElement: createElement
});
var DefaultMessageComponent = createDefaultMessageComponent({
createElement: createElement,
Fragment: Fragment
});
var DefaultLoaderComponent = createChatMessageLoaderComponent({
createElement: createElement
});
var DefaultErrorComponent = createChatMessageErrorComponent({
createElement: createElement
});
return function ChatMessages(userProps) {
var _lastMessage_parts;
var _userProps_classNames = userProps.classNames, classNames = _userProps_classNames === void 0 ? {} : _userProps_classNames, _userProps_messageClassNames = userProps.messageClassNames, messageClassNames = _userProps_messageClassNames === void 0 ? {} : _userProps_messageClassNames, messageTranslations = userProps.messageTranslations, _userProps_messages = userProps.messages, messages = _userProps_messages === void 0 ? [] : _userProps_messages, MessageComponent = userProps.messageComponent, LoaderComponent = userProps.loaderComponent, ErrorComponent = userProps.errorComponent, EmptyComponent = userProps.emptyComponent, ActionsComponent = userProps.actionsComponent, tools = userProps.tools, indexUiState = userProps.indexUiState, setIndexUiState = userProps.setIndexUiState, _userProps_status = userProps.status, status = _userProps_status === void 0 ? 'ready' : _userProps_status, error = userProps.error, _userProps_hideScrollToBottom = userProps.hideScrollToBottom, hideScrollToBottom = _userProps_hideScrollToBottom === void 0 ? false : _userProps_hideScrollToBottom, onReload = userProps.onReload, onNewConversation = userProps.onNewConversation, onClose = userProps.onClose, sendMessage = userProps.sendMessage, setInput = userProps.setInput, userTranslations = userProps.translations, userMessageProps = userProps.userMessageProps, assistantMessageProps = userProps.assistantMessageProps, _userProps_isClearing = userProps.isClearing, isClearing = _userProps_isClearing === void 0 ? false : _userProps_isClearing, onClearTransitionEnd = userProps.onClearTransitionEnd, isScrollAtBottom = userProps.isScrollAtBottom, scrollRef = userProps.scrollRef, contentRef = userProps.contentRef, onScrollToBottom = userProps.onScrollToBottom, suggestionsElement = userProps.suggestionsElement, onFeedback = userProps.onFeedback, feedbackState = userProps.feedbackState, props = _(userProps, [
"classNames",
"messageClassNames",
"messageTranslations",
"messages",
"messageComponent",
"loaderComponent",
"errorComponent",
"emptyComponent",
"actionsComponent",
"tools",
"indexUiState",
"setIndexUiState",
"status",
"error",
"hideScrollToBottom",
"onReload",
"onNewConversation",
"onClose",
"sendMessage",
"setInput",
"translations",
"userMessageProps",
"assistantMessageProps",
"isClearing",
"onClearTransitionEnd",
"isScrollAtBottom",
"scrollRef",
"contentRef",
"onScrollToBottom",
"suggestionsElement",
"onFeedback",
"feedbackState"
]);
var translations = _$1({
scrollToBottomLabel: 'Scroll to bottom',
copyToClipboardLabel: 'Copy to clipboard',
regenerateLabel: 'Regenerate',
thumbsUpLabel: 'Like',
thumbsDownLabel: 'Dislike',
feedbackThankYouText: 'Thanks for your feedback!',
sendingFeedbackLabel: 'Sending feedback...'
}, userTranslations);
var cssClasses = {
root: cx('ais-ChatMessages', classNames.root),
scroll: cx('ais-ChatMessages-scroll ais-Scrollbar', classNames.scroll),
content: cx('ais-ChatMessages-content', classNames.content),
scrollToBottom: cx('ais-ChatMessages-scrollToBottom', classNames.scrollToBottom),
scrollToBottomHidden: cx('ais-ChatMessages-scrollToBottom--hidden', classNames.scrollToBottomHidden)
};
var lastMessage = messages[messages.length - 1];
var lastPart = lastMessage === null || lastMessage === void 0 ? void 0 : (_lastMessage_parts = lastMessage.parts) === null || _lastMessage_parts === void 0 ? void 0 : _lastMessage_parts[lastMessage.parts.length - 1];
var showLoader = getShowLoader(status, lastPart, tools);
var showEmpty = messages.length === 0 && !showLoader && !isClearing && status !== 'error';
var DefaultMessage = MessageComponent || DefaultMessageComponent;
var DefaultLoader = LoaderComponent || DefaultLoaderComponent;
var DefaultError = ErrorComponent || DefaultErrorComponent;
return /*#__PURE__*/ createElement("div", _$2(_$1({}, props), {
className: cx(cssClasses.root, props.className),
role: "log",
"aria-live": "polite"
}), /*#__PURE__*/ createElement("div", {
className: cx(cssClasses.scroll),
ref: scrollRef
}, /*#__PURE__*/ createElement("div", {
className: cx(cssClasses.content, isClearing && 'ais-ChatMessages-content--clearing'),
ref: contentRef,
onTransitionEnd: function onTransitionEnd(e) {
if (e.target === e.currentTarget && e.propertyName === 'opacity' && isClearing) {
onClearTransitionEnd === null || onClearTransitionEnd === void 0 ? void 0 : onClearTransitionEnd();
}
}
}, showEmpty && EmptyComponent && /*#__PURE__*/ createElement(EmptyComponent, {
sendMessage: sendMessage,
setInput: setInput,
status: status,
onClose: onClose
}), messages.map(function(message, index) {
return /*#__PURE__*/ createElement(DefaultMessage, {
key: message.id,
message: message,
status: status,
userMessageProps: userMessageProps,
assistantMessageProps: assistantMessageProps,
tools: tools,
indexUiState: indexUiState,
setIndexUiState: setIndexUiState,
onReload: onReload,
onFeedback: onFeedback,
feedbackState: feedbackState,
actionsComponent: ActionsComponent,
onClose: onClose,
translations: translations,
classNames: messageClassNames,
messageTranslations: messageTranslations,
suggestionsElement: status === 'ready' && message.role === 'assistant' && index === messages.length - 1 ? suggestionsElement : undefined
});
}), showLoader && /*#__PURE__*/ createElement(DefaultLoader, {
translations: {
loaderText: translations.loaderText
}
}), status === 'error' && /*#__PURE__*/ createElement(DefaultError, {
onNewConversation: onNewConversation,
errorMessage: error === null || error === void 0 ? void 0 : error.message,
translations: // Guardrail violations come with a service-authored
// `fallbackResponse` that's safe to display verbatim; for
// every other error we keep hiding the raw `error.message`
// behind the friendly default. Detection is by `error.name`
// to avoid coupling this package to `instantsearch.js`.
(error === null || error === void 0 ? void 0 : error.name) === 'GuardrailViolationError' ? {
errorMessage: function errorMessage(param) {
var rawMessage = param.errorMessage;
return rawMessage !== null && rawMessage !== void 0 ? rawMessage : '';
}
} : undefined
}))), /*#__PURE__*/ createElement(Button, {
variant: "outline",
size: "sm",
iconOnly: true,
className: cx(cssClasses.scrollToBottom, (hideScrollToBottom || isScrollAtBottom) && cssClasses.scrollToBottomHidden),
onClick: onScrollToBottom,
"aria-label": translations.scrollToBottomLabel,
tabIndex: isScrollAtBottom ? -1 : 0
}, /*#__PURE__*/ createElement(ChevronDownIcon, {
createElement: createElement
})));
};
}
var getShowLoader = function getShowLoader(status, lastPart, tools) {
if (status !== 'submitted' && status !== 'streaming') return false;
if (status === 'submitted') return true;
if (!lastPart) return true;
if (isPartText(lastPart)) return false;
if (isPartTool(lastPart) && lastPart.state === 'input-streaming') {
var tool = findTool(lastPart.type, tools);
return !(tool === null || tool === void 0 ? void 0 : tool.streamInput);
}
return true;
};
export { createChatMessagesComponent };