@docsearch/react 4.6.3 → 5.0.0-beta.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.
Files changed (79) hide show
  1. package/README.md +0 -2
  2. package/dist/esm/AskAiScreenState-D0IZsCMJ.d.ts +106 -0
  3. package/dist/esm/DocSearch-Dq5Utfyb.d.ts +295 -0
  4. package/dist/esm/DocSearchAskAiModal-BwbMrrHv.d.ts +48 -0
  5. package/dist/esm/DocSearchAskAiModal-CCrk6YLb.js +954 -0
  6. package/dist/esm/DocSearchAskAiModal-CCrk6YLb.js.map +1 -0
  7. package/dist/esm/DocSearchButton-CRlNPf5k.d.ts +18 -0
  8. package/dist/esm/DocSearchButton-CaxxOzQU.js +71 -0
  9. package/dist/esm/DocSearchButton-CaxxOzQU.js.map +1 -0
  10. package/dist/esm/DocSearchModal-CpvDjo1O.js +250 -0
  11. package/dist/esm/DocSearchModal-CpvDjo1O.js.map +1 -0
  12. package/dist/esm/DocSearchTheme-DvL4mf0D.d.ts +5 -0
  13. package/dist/esm/askaiModal.d.ts +2 -0
  14. package/dist/esm/askaiModal.js +3 -0
  15. package/dist/esm/button.d.ts +2 -0
  16. package/dist/esm/button.js +3 -0
  17. package/dist/esm/docsearchAi.d.ts +220 -0
  18. package/dist/esm/docsearchAi.js +34 -0
  19. package/dist/esm/docsearchAi.js.map +1 -0
  20. package/dist/esm/index-Dl8FMlR5.d.ts +223 -0
  21. package/dist/esm/index.d.ts +9 -655
  22. package/dist/esm/index.js +35 -3
  23. package/dist/esm/index.js.map +1 -0
  24. package/dist/esm/keyboard-BkSdCzTU.js +9 -0
  25. package/dist/esm/keyboard-BkSdCzTU.js.map +1 -0
  26. package/dist/esm/keyboardShortcuts-C-lx6Xt7.js +25 -0
  27. package/dist/esm/keyboardShortcuts-C-lx6Xt7.js.map +1 -0
  28. package/dist/esm/modal.d.ts +2 -0
  29. package/dist/esm/modal.js +3 -0
  30. package/dist/esm/normalizeDocSearchIndexes-DAzlMybx.js +1240 -0
  31. package/dist/esm/normalizeDocSearchIndexes-DAzlMybx.js.map +1 -0
  32. package/dist/esm/objectSpread2-BNmiQYyW.js +67 -0
  33. package/dist/esm/objectWithoutProperties-phqYxDS0.js +53 -0
  34. package/dist/esm/objectWithoutProperties-phqYxDS0.js.map +1 -0
  35. package/dist/esm/sidepanel.d.ts +395 -0
  36. package/dist/esm/sidepanel.js +773 -0
  37. package/dist/esm/sidepanel.js.map +1 -0
  38. package/dist/esm/useDocSearchKeyboardEvents-68G8dw6c.d.ts +43 -0
  39. package/dist/esm/useDocSearchKeyboardEvents.d.ts +2 -41
  40. package/dist/esm/useDocSearchKeyboardEvents.js +43 -1
  41. package/dist/esm/useDocSearchKeyboardEvents.js.map +1 -0
  42. package/dist/esm/useSearchClient-mIHVB6ga.js +433 -0
  43. package/dist/esm/useSearchClient-mIHVB6ga.js.map +1 -0
  44. package/dist/esm/useSuggestedQuestions-D2TGVPsI.js +1112 -0
  45. package/dist/esm/useSuggestedQuestions-D2TGVPsI.js.map +1 -0
  46. package/dist/esm/useTheme.d.ts +7 -6
  47. package/dist/esm/useTheme.js +21 -1
  48. package/dist/esm/useTheme.js.map +1 -0
  49. package/dist/esm/version.d.ts +4 -2
  50. package/dist/esm/version.js +6 -1
  51. package/dist/esm/version.js.map +1 -0
  52. package/dist/umd/index.js +175 -5
  53. package/dist/umd/index.js.map +1 -1
  54. package/package.json +31 -34
  55. package/style/askai.js +1 -0
  56. package/button.js +0 -1
  57. package/dist/esm/DocSearchButton.d.ts +0 -18
  58. package/dist/esm/DocSearchButton.js +0 -1
  59. package/dist/esm/DocSearchModal.d.ts +0 -444
  60. package/dist/esm/DocSearchModal.js +0 -3
  61. package/dist/esm/Sidepanel.d.ts +0 -371
  62. package/dist/esm/Sidepanel.js +0 -3
  63. package/dist/umd/DocSearchModal.js +0 -5
  64. package/dist/umd/DocSearchModal.js.map +0 -1
  65. package/dist/umd/DocsearchButton.js +0 -3
  66. package/dist/umd/DocsearchButton.js.map +0 -1
  67. package/dist/umd/Sidepanel.js +0 -5
  68. package/dist/umd/Sidepanel.js.map +0 -1
  69. package/dist/umd/useDocSearchKeyboardEvents.js +0 -3
  70. package/dist/umd/useDocSearchKeyboardEvents.js.map +0 -1
  71. package/dist/umd/useTheme.js +0 -3
  72. package/dist/umd/useTheme.js.map +0 -1
  73. package/dist/umd/version.js +0 -3
  74. package/dist/umd/version.js.map +0 -1
  75. package/modal.js +0 -1
  76. package/sidepanel.js +0 -1
  77. package/useDocSearchKeyboardEvents.js +0 -1
  78. package/useTheme.js +0 -1
  79. package/version.js +0 -1
@@ -0,0 +1,954 @@
1
+ import { t as _objectSpread2 } from "./objectSpread2-BNmiQYyW.js";
2
+ import { C as noop, D as getCollection, E as SOURCE_IDS, S as scrollTo, T as identity, _ as Hit, a as NoResultsScreen, b as SearchBoxForm, c as Results, d as useRefreshOnInitialQuery, f as useModalRefs, g as useDocSearchFacets, h as useSendItemClickEvent, i as ResultsScreen, l as useStoredDocSearches, m as useInitialModalQuery, n as buildNoQuerySources, o as ErrorScreen, p as useModalEnvironment, r as buildQuerySources, s as StoredSearchesSections, t as normalizeDocSearchIndexes, u as useSaveRecentSearch, v as Footer, w as isModifierEvent, x as FacetBar, y as ModalShell } from "./normalizeDocSearchIndexes-DAzlMybx.js";
3
+ import { n as SearchIcon, t as _objectWithoutProperties } from "./objectWithoutProperties-phqYxDS0.js";
4
+ import { l as CloseIcon, m as LoadingIcon, p as SparklesIcon, t as useSearchClient } from "./useSearchClient-mIHVB6ga.js";
5
+ import { S as AlertIcon, _ as BackIcon, a as MemoizedMarkdown, b as MoreVerticalIcon, c as buildDummyAskAiHit, d as getMessageContent, f as isAIToolPart, g as ConversationPromptSuggestions, h as FeedbackActions, i as groupConsecutiveToolResults, l as extractLinksFromMessage, m as SourcesPanel, n as useAskAi, o as ToolCall, p as isThreadDepthError, r as Menu, s as EMPTY_TOOLS, t as useSuggestedQuestions, u as getAgentPromptSuggestions, v as NewConversationIcon, x as StopIcon, y as ConversationHistoryIcon } from "./useSuggestedQuestions-D2TGVPsI.js";
6
+ import React, { Fragment, useMemo } from "react";
7
+ import { createAutocomplete } from "@algolia/autocomplete-core";
8
+
9
+ //#region src/icons/MessageIcon.tsx
10
+ function MessageIcon() {
11
+ return /* @__PURE__ */ React.createElement("svg", {
12
+ xmlns: "http://www.w3.org/2000/svg",
13
+ width: "13",
14
+ height: "13",
15
+ viewBox: "0 0 24 24",
16
+ fill: "none",
17
+ stroke: "currentColor",
18
+ strokeWidth: "2",
19
+ strokeLinecap: "round",
20
+ strokeLinejoin: "round"
21
+ }, /* @__PURE__ */ React.createElement("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }));
22
+ }
23
+
24
+ //#endregion
25
+ //#region src/AggregatedSearchBlock.tsx
26
+ const defaultAggregatedToolCallParts = {
27
+ before: "Searched for ",
28
+ separator: ", ",
29
+ lastSeparator: " and ",
30
+ after: ""
31
+ };
32
+ function AggregatedSearchBlock({ queries, translations, onSearchQueryClick }) {
33
+ if (queries.length === 0) return null;
34
+ if (typeof translations.aggregatedToolCallNode === "function") return /* @__PURE__ */ React.createElement(React.Fragment, null, translations.aggregatedToolCallNode(queries, onSearchQueryClick));
35
+ const { before = "", separator = ", ", lastSeparator = " and ", after = "" } = (translations.aggregatedToolCallText ? translations.aggregatedToolCallText(queries) : defaultAggregatedToolCallParts) || {};
36
+ return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent-Tool Tool--AggregatedResult" }, /* @__PURE__ */ React.createElement(SearchIcon, { size: 18 }), /* @__PURE__ */ React.createElement("span", null, before && /* @__PURE__ */ React.createElement("span", null, before), queries.map((q, idx) => /* @__PURE__ */ React.createElement(Fragment, { key: q + idx }, /* @__PURE__ */ React.createElement("span", {
37
+ role: "button",
38
+ tabIndex: 0,
39
+ className: "DocSearch-AskAiScreen-MessageContent-Tool-Query",
40
+ onKeyDown: (e) => {
41
+ if (e.key === "enter" || e.key === " ") {
42
+ e.preventDefault();
43
+ onSearchQueryClick(q);
44
+ }
45
+ },
46
+ onClick: () => onSearchQueryClick(q)
47
+ }, "\"", q, "\""), idx < queries.length - 2 && separator, idx === queries.length - 2 && lastSeparator)), after && /* @__PURE__ */ React.createElement("span", null, after)));
48
+ }
49
+
50
+ //#endregion
51
+ //#region src/AskAiScreen.tsx
52
+ const _excluded$6 = ["translations"];
53
+ /**
54
+ * Maps AskAiScreen's public translation keys to the shared
55
+ * `ToolCallTranslations` shape consumed by the `ToolCall` component, applying
56
+ * default English values.
57
+ */
58
+ function toToolCallTranslations(translations) {
59
+ const { preToolCallText = "Searching...", duringToolCallText = "Searching...", afterToolCallText = "Searched for", savedMemoryToolResultText = "Saved to memory", memoryToolResultText = "Used memory to enhance results" } = translations;
60
+ return {
61
+ preToolCallText,
62
+ searchingText: duringToolCallText,
63
+ toolCallResultText: afterToolCallText,
64
+ savedMemoryToolResultText,
65
+ memoryToolResultText
66
+ };
67
+ }
68
+ function AskAiScreenDisclaimer({ disclaimerText }) {
69
+ return /* @__PURE__ */ React.createElement("p", { className: "DocSearch-AskAiScreen-Disclaimer" }, /* @__PURE__ */ React.createElement(SparklesIcon, null), " ", disclaimerText);
70
+ }
71
+ function AskAiExchangeCard({ exchange, askAiError, isLastExchange, loadingStatus, onSearchQueryClick, translations, tools, conversations, onFeedback, memoryEnabled, onSelectPromptSuggestion }) {
72
+ var _userMessage$metadata, _assistantMessage$met, _userContent$text;
73
+ const { userMessage, assistantMessage } = exchange;
74
+ const { stoppedStreamingText = "You stopped this response", errorTitleText = "Chat error", relatedSourcesText, suggestedPromptsTitleText = "Suggested prompts" } = translations;
75
+ const toolCallTranslations = useMemo(() => toToolCallTranslations(translations), [translations]);
76
+ const isThreadDepth = isThreadDepthError(askAiError);
77
+ const assistantContent = useMemo(() => getMessageContent(assistantMessage), [assistantMessage]);
78
+ const userContent = useMemo(() => getMessageContent(userMessage), [userMessage]);
79
+ const urlsToDisplay = React.useMemo(() => extractLinksFromMessage(assistantMessage), [assistantMessage]);
80
+ const displayParts = React.useMemo(() => {
81
+ return groupConsecutiveToolResults((assistantMessage === null || assistantMessage === void 0 ? void 0 : assistantMessage.parts) || []);
82
+ }, [assistantMessage]);
83
+ const promptSuggestions = useMemo(() => {
84
+ if (!isLastExchange) return [];
85
+ return getAgentPromptSuggestions((assistantMessage === null || assistantMessage === void 0 ? void 0 : assistantMessage.parts) || []);
86
+ }, [assistantMessage, isLastExchange]);
87
+ const wasStopped = ((_userMessage$metadata = userMessage.metadata) === null || _userMessage$metadata === void 0 ? void 0 : _userMessage$metadata.stopped) || (assistantMessage === null || assistantMessage === void 0 || (_assistantMessage$met = assistantMessage.metadata) === null || _assistantMessage$met === void 0 ? void 0 : _assistantMessage$met.stopped);
88
+ const showActions = !wasStopped && (!isLastExchange || isLastExchange && loadingStatus === "ready" && Boolean(assistantMessage));
89
+ const isThinking = ["submitted", "streaming"].includes(loadingStatus) && isLastExchange && !displayParts.some((part) => part.type !== "step-start");
90
+ const messageId = (assistantMessage === null || assistantMessage === void 0 ? void 0 : assistantMessage.id) || exchange.id;
91
+ return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Response-Container" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Response" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--user" }, /* @__PURE__ */ React.createElement("p", { className: "DocSearch-AskAiScreen-Query" }, (_userContent$text = userContent === null || userContent === void 0 ? void 0 : userContent.text) !== null && _userContent$text !== void 0 ? _userContent$text : "")), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Message DocSearch-AskAiScreen-Message--assistant" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent" }, loadingStatus === "error" && askAiError && isLastExchange && !isThreadDepth && /* @__PURE__ */ React.createElement("div", {
92
+ className: "DocSearch-AskAiScreen-Error",
93
+ role: "alert"
94
+ }, /* @__PURE__ */ React.createElement(AlertIcon, { "aria-hidden": "true" }), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Error-Content" }, /* @__PURE__ */ React.createElement("h4", { className: "DocSearch-AskAiScreen-Error-Title" }, errorTitleText), /* @__PURE__ */ React.createElement(MemoizedMarkdown, {
95
+ content: askAiError.message,
96
+ copyButtonText: "",
97
+ copyButtonCopiedText: "",
98
+ isStreaming: false
99
+ }))), isThinking && /* @__PURE__ */ React.createElement("div", {
100
+ className: "DocSearch-AskAiScreen-MessageContent-Thinking",
101
+ role: "status"
102
+ }, /* @__PURE__ */ React.createElement("span", { className: "shimmer" }, translations.thinkingText || "Thinking..."), /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAi-Thinking-Skeleton shimmer" }), /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAi-Thinking-Skeleton DocSearch-AskAi-Thinking-Skeleton--short shimmer" })), displayParts.map((part, idx) => {
103
+ const index = idx;
104
+ if (typeof part === "string") return /* @__PURE__ */ React.createElement(MemoizedMarkdown, {
105
+ key: index,
106
+ content: part,
107
+ copyButtonText: translations.copyButtonText || "Copy",
108
+ copyButtonCopiedText: translations.copyButtonCopiedText || "Copied!",
109
+ isStreaming: loadingStatus === "streaming"
110
+ });
111
+ if (isAIToolPart(part)) return /* @__PURE__ */ React.createElement(ToolCall, {
112
+ key: index,
113
+ translations: toolCallTranslations,
114
+ part,
115
+ tools,
116
+ memoryEnabled,
117
+ onSearchQueryClick
118
+ });
119
+ if (part.type === "aggregated-tool-call") return /* @__PURE__ */ React.createElement(AggregatedSearchBlock, {
120
+ key: index,
121
+ queries: part.queries,
122
+ translations,
123
+ onSearchQueryClick
124
+ });
125
+ if (part.type === "reasoning" && part.state === "streaming") return /* @__PURE__ */ React.createElement("div", {
126
+ key: index,
127
+ className: "DocSearch-AskAiScreen-MessageContent-Reasoning shimmer"
128
+ }, /* @__PURE__ */ React.createElement(LoadingIcon, { className: "DocSearch-AskAiScreen-SmallerLoadingIcon" }), /* @__PURE__ */ React.createElement("span", { className: "shimmer" }, "Reasoning..."));
129
+ if (part.type === "text") return /* @__PURE__ */ React.createElement(MemoizedMarkdown, {
130
+ key: index,
131
+ content: part.text,
132
+ copyButtonText: translations.copyButtonText || "Copy",
133
+ copyButtonCopiedText: translations.copyButtonCopiedText || "Copied!",
134
+ isStreaming: part.state === "streaming"
135
+ });
136
+ return null;
137
+ })), wasStopped && /* @__PURE__ */ React.createElement("p", { className: "DocSearck-AskAiScreen-MessageContent-Stopped" }, stoppedStreamingText)), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Answer-Footer" }, /* @__PURE__ */ React.createElement(SourcesPanel, {
138
+ links: urlsToDisplay,
139
+ titleText: relatedSourcesText
140
+ }), /* @__PURE__ */ React.createElement(FeedbackActions, {
141
+ id: messageId,
142
+ showActions,
143
+ latestAssistantMessageContent: (assistantContent === null || assistantContent === void 0 ? void 0 : assistantContent.text) || null,
144
+ translations,
145
+ conversations,
146
+ onFeedback
147
+ })), promptSuggestions.length > 0 && /* @__PURE__ */ React.createElement(ConversationPromptSuggestions, {
148
+ title: suggestedPromptsTitleText,
149
+ suggestions: promptSuggestions,
150
+ onSelectPromptSuggestion
151
+ })));
152
+ }
153
+ function AskAiScreen(_ref) {
154
+ let { translations = {} } = _ref, props = _objectWithoutProperties(_ref, _excluded$6);
155
+ const { disclaimerText = "Answers are generated with AI which can make mistakes.", threadDepthExceededMessage = "This conversation is now closed to keep responses accurate.", startNewConversationButtonText = "Start a new conversation" } = translations;
156
+ const { messages, tools, askAiError, status, memoryEnabled } = props;
157
+ const hasThreadDepthError = useMemo(() => {
158
+ return status === "error" && isThreadDepthError(askAiError);
159
+ }, [status, askAiError]);
160
+ const exchanges = useMemo(() => {
161
+ const grouped = [];
162
+ for (let i = 0; i < messages.length; i++) if (messages[i].role === "user") {
163
+ var _messages;
164
+ const userMessage = messages[i];
165
+ const assistantMessage = ((_messages = messages[i + 1]) === null || _messages === void 0 ? void 0 : _messages.role) === "assistant" ? messages[i + 1] : null;
166
+ grouped.push({
167
+ id: userMessage.id,
168
+ userMessage,
169
+ assistantMessage
170
+ });
171
+ if (assistantMessage) i++;
172
+ }
173
+ if (hasThreadDepthError && grouped.length > 0) {
174
+ if (!grouped[grouped.length - 1].assistantMessage) grouped.pop();
175
+ }
176
+ return grouped;
177
+ }, [messages, hasThreadDepthError]);
178
+ const handleSearchQueryClick = (query) => {
179
+ props.onAskAiToggle(false);
180
+ props.setQuery(query);
181
+ };
182
+ const showThreadDepthError = hasThreadDepthError && messages.some((m) => m.role === "assistant");
183
+ return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen DocSearch-AskAiScreen-Container" }, showThreadDepthError && /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-MessageContent DocSearch-AskAiScreen-Error DocSearch-AskAiScreen-Error--ThreadDepth" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Error-Content" }, /* @__PURE__ */ React.createElement("p", null, threadDepthExceededMessage, " ", /* @__PURE__ */ React.createElement("button", {
184
+ type: "button",
185
+ className: "DocSearch-ThreadDepthError-Link",
186
+ onClick: props.onNewConversation
187
+ }, startNewConversationButtonText), " ", "to continue."))), /* @__PURE__ */ React.createElement(AskAiScreenDisclaimer, { disclaimerText }), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Body" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-ExchangesList" }, exchanges.slice().reverse().map((exchange, index) => /* @__PURE__ */ React.createElement(AskAiExchangeCard, {
188
+ key: exchange.id,
189
+ exchange,
190
+ askAiError: props.askAiError,
191
+ isLastExchange: index === 0,
192
+ loadingStatus: props.status,
193
+ translations,
194
+ tools,
195
+ conversations: props.conversations,
196
+ memoryEnabled,
197
+ onSearchQueryClick: handleSearchQueryClick,
198
+ onFeedback: props.onFeedback,
199
+ onSelectPromptSuggestion: props.onSelectPromptSuggestion
200
+ })))));
201
+ }
202
+
203
+ //#endregion
204
+ //#region src/components/ui/RecentConversationsResults.tsx
205
+ const _excluded$5 = ["translations"];
206
+ function RecentConversationsResults(_ref) {
207
+ let { translations = {} } = _ref, props = _objectWithoutProperties(_ref, _excluded$5);
208
+ const { recentConversationsTitle = "Resume AI conversations", removeRecentConversationButtonTitle = "Remove this conversation from history" } = translations;
209
+ const recentConversations = getCollection(props.state, "recentConversations");
210
+ if (!recentConversations) return null;
211
+ return /* @__PURE__ */ React.createElement(Results, _objectSpread2(_objectSpread2({}, props), {}, {
212
+ title: recentConversationsTitle,
213
+ collection: recentConversations,
214
+ renderIcon: () => /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Hit-icon DocSearch-Hit-icon--small" }, /* @__PURE__ */ React.createElement(MessageIcon, null)),
215
+ renderAction: ({ item }) => /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Hit-action" }, /* @__PURE__ */ React.createElement("button", {
216
+ className: "DocSearch-Hit-action-button",
217
+ title: removeRecentConversationButtonTitle,
218
+ type: "submit",
219
+ onClick: (event) => {
220
+ event.preventDefault();
221
+ event.stopPropagation();
222
+ props.conversations.remove(item);
223
+ props.refresh();
224
+ }
225
+ }, /* @__PURE__ */ React.createElement(CloseIcon, null)))
226
+ }));
227
+ }
228
+
229
+ //#endregion
230
+ //#region src/components/AskAiStartScreen.tsx
231
+ const _excluded$4 = ["translations"];
232
+ function AskAiStartScreen(_ref) {
233
+ let { translations = {} } = _ref, props = _objectWithoutProperties(_ref, _excluded$4);
234
+ return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Dropdown-Container" }, /* @__PURE__ */ React.createElement(RecentConversationsResults, _objectSpread2(_objectSpread2({}, props), {}, { translations })), /* @__PURE__ */ React.createElement(StoredSearchesSections, _objectSpread2(_objectSpread2({}, props), {}, { translations })));
235
+ }
236
+
237
+ //#endregion
238
+ //#region src/ConversationHistoryScreen.tsx
239
+ const _excluded$3 = ["onAskAiToggle"];
240
+ function ConversationHistoryScreen(_ref) {
241
+ let { onAskAiToggle } = _ref, props = _objectWithoutProperties(_ref, _excluded$3);
242
+ const collection = React.useMemo(() => getCollection(props.state, "recentConversations"), [props.state]);
243
+ React.useEffect(() => {
244
+ if (!collection || collection.items.length === 0) onAskAiToggle(true);
245
+ }, [collection, onAskAiToggle]);
246
+ if (!collection) return null;
247
+ return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Dropdown-Container DocSearch-Conversation-History" }, /* @__PURE__ */ React.createElement(Results, _objectSpread2(_objectSpread2({}, props), {}, {
248
+ key: collection.source.sourceId,
249
+ title: "",
250
+ translations: props.translations,
251
+ collection,
252
+ renderIcon: () => /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Hit-icon" }, /* @__PURE__ */ React.createElement(SparklesIcon, null)),
253
+ renderAction: ({ item }) => /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Hit-action" }, /* @__PURE__ */ React.createElement("button", {
254
+ type: "button",
255
+ className: "DocSearch-Hit-action-button",
256
+ onClick: (e) => {
257
+ e.preventDefault();
258
+ e.stopPropagation();
259
+ props.conversations.remove(item);
260
+ props.refresh();
261
+ }
262
+ }, /* @__PURE__ */ React.createElement(CloseIcon, null)))
263
+ })));
264
+ }
265
+
266
+ //#endregion
267
+ //#region src/NewConversationScreen.tsx
268
+ function NewConversationScreen({ translations = {}, suggestedQuestions = [], selectSuggestedQuestion }) {
269
+ const { newConversationTitle = "How can I help you today?", newConversationDescription = "I search through your documentation to help you find setup guides, feature details and troubleshooting tips, fast." } = translations;
270
+ return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-NewConversationScreen" }, /* @__PURE__ */ React.createElement("h3", { className: "DocSearch-NewConversationScreen-Title" }, newConversationTitle), /* @__PURE__ */ React.createElement("p", { className: "DocSearch-NewConversationScreen-Description" }, newConversationDescription), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-NewConversationScreen-SuggestedQuestions" }, suggestedQuestions.map((question) => /* @__PURE__ */ React.createElement("button", {
271
+ key: question.objectID,
272
+ type: "button",
273
+ className: "DocSearch-NewConversationScreen-SuggestedQuestion",
274
+ onClick: () => selectSuggestedQuestion(question)
275
+ }, question.question))));
276
+ }
277
+
278
+ //#endregion
279
+ //#region src/AskAiScreenState.tsx
280
+ const _excluded$2 = ["translations", "selectAskAiQuestion"];
281
+ const AskAiScreenState = React.memo((_ref) => {
282
+ var _props$state;
283
+ let { translations = {}, selectAskAiQuestion } = _ref, props = _objectWithoutProperties(_ref, _excluded$2);
284
+ const handleSelectPromptSuggestion = React.useCallback((prompt) => {
285
+ selectAskAiQuestion(true, prompt);
286
+ }, [selectAskAiQuestion]);
287
+ if (props.canHandleAskAi && props.isAskAiActive && props.askAiState === "conversation-history") return /* @__PURE__ */ React.createElement(ConversationHistoryScreen, _objectSpread2({ selectAskAiQuestion }, props));
288
+ if (props.canHandleAskAi && props.isAskAiActive && props.askAiState === "new-conversation") return /* @__PURE__ */ React.createElement(NewConversationScreen, {
289
+ translations: translations === null || translations === void 0 ? void 0 : translations.newConversation,
290
+ selectSuggestedQuestion: props.selectSuggestedQuestion,
291
+ suggestedQuestions: props.suggestedQuestions
292
+ });
293
+ if (props.isAskAiActive && props.canHandleAskAi) return /* @__PURE__ */ React.createElement(AskAiScreen, _objectSpread2(_objectSpread2({}, props), {}, {
294
+ messages: props.messages,
295
+ tools: props.tools,
296
+ status: props.status,
297
+ askAiError: props.askAiError,
298
+ translations: translations === null || translations === void 0 ? void 0 : translations.askAiScreen,
299
+ memoryEnabled: props.memoryEnabled,
300
+ selectAskAiQuestion,
301
+ onSelectPromptSuggestion: handleSelectPromptSuggestion
302
+ }));
303
+ if (((_props$state = props.state) === null || _props$state === void 0 ? void 0 : _props$state.status) === "error") return /* @__PURE__ */ React.createElement(ErrorScreen, { translations: translations === null || translations === void 0 ? void 0 : translations.errorScreen });
304
+ if (!props.state.query) return /* @__PURE__ */ React.createElement(AskAiStartScreen, _objectSpread2(_objectSpread2({}, props), {}, {
305
+ hasCollections: props.hasCollections,
306
+ translations: translations === null || translations === void 0 ? void 0 : translations.startScreen,
307
+ selectAskAiQuestion
308
+ }));
309
+ if (!props.hasCollections && !props.canHandleAskAi) return /* @__PURE__ */ React.createElement(NoResultsScreen, _objectSpread2(_objectSpread2({}, props), {}, { translations: translations === null || translations === void 0 ? void 0 : translations.noResultsScreen }));
310
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ResultsScreen, _objectSpread2(_objectSpread2({}, props), {}, { translations: translations === null || translations === void 0 ? void 0 : translations.resultsScreen })), props.canHandleAskAi && !props.hasCollections && /* @__PURE__ */ React.createElement(NoResultsScreen, _objectSpread2(_objectSpread2({}, props), {}, { translations: translations === null || translations === void 0 ? void 0 : translations.noResultsScreen })));
311
+ }, function areEqual(_prevProps, nextProps) {
312
+ return nextProps.state.status === "loading" || nextProps.state.status === "stalled";
313
+ });
314
+
315
+ //#endregion
316
+ //#region src/ModalHeading.tsx
317
+ function ModalHeading({ heading, shimmer = false }) {
318
+ return /* @__PURE__ */ React.createElement("span", { className: `DocSearch-Modal-heading${shimmer ? " shimmer" : ""}` }, heading);
319
+ }
320
+
321
+ //#endregion
322
+ //#region src/components/AskAiSearchBox.tsx
323
+ const _excluded$1 = [
324
+ "translations",
325
+ "askAiState",
326
+ "onAskAiToggle",
327
+ "setAskAiState"
328
+ ];
329
+ function AskAiSearchBox(_ref) {
330
+ let { translations = {}, askAiState, onAskAiToggle, setAskAiState } = _ref, props = _objectWithoutProperties(_ref, _excluded$1);
331
+ const { clearButtonTitle = "Clear", clearButtonAriaLabel = "Clear the query", closeButtonText = "Close", closeButtonAriaLabel = "Close", searchInputLabel = "Search", backToKeywordSearchButtonText = "Back to keyword search", backToKeywordSearchButtonAriaLabel = "Back to keyword search", placeholderTextAskAiStreaming = "Answering...", newConversationPlaceholder = "Ask a question", conversationHistoryTitle = "My conversation history", startNewConversationText = "Start a new conversation", viewConversationHistoryText = "Conversation history", threadDepthErrorPlaceholder = "Conversation limit reached" } = translations;
332
+ const hasRecentConversations = React.useMemo(() => {
333
+ const askAiSource = getCollection(props.state, "recentConversations");
334
+ if (!askAiSource) return false;
335
+ return askAiSource.items.length > 0;
336
+ }, [props.state]);
337
+ const baseInputProps = props.getInputProps({
338
+ inputElement: props.inputRef.current,
339
+ autoFocus: props.autoFocus
340
+ });
341
+ const blockedKeys = /* @__PURE__ */ new Set([
342
+ "ArrowUp",
343
+ "ArrowDown",
344
+ "Enter"
345
+ ]);
346
+ const origOnKeyDown = baseInputProps.onKeyDown;
347
+ const origOnChange = baseInputProps.onChange;
348
+ const isAskAiStreaming = props.askAiStatus === "streaming" || props.askAiStatus === "submitted";
349
+ const renderMoreOptions = props.isAskAiActive && askAiState !== "conversation-history";
350
+ const isThreadDepthError = props.isThreadDepthError || false;
351
+ let searchPlaceholder = props.placeholder;
352
+ if (askAiState === "new-conversation") searchPlaceholder = newConversationPlaceholder;
353
+ if (isThreadDepthError && props.isAskAiActive) searchPlaceholder = threadDepthErrorPlaceholder;
354
+ let heading = null;
355
+ if (isAskAiStreaming) heading = placeholderTextAskAiStreaming;
356
+ if (askAiState === "conversation-history") heading = conversationHistoryTitle;
357
+ React.useEffect(() => {
358
+ if (props.askAiStatus !== "streaming" && props.askAiStatus !== "submitted" && props.inputRef.current) props.inputRef.current.focus();
359
+ }, [props.askAiStatus, props.inputRef]);
360
+ /**
361
+ * We need to block the default behavior of the input when Ask AI is active.
362
+ * This is because the input is used to ask another question when the user
363
+ * presses enter.
364
+ *
365
+ * Learn more on default autocomplete behavior:
366
+ * https://github.com/algolia/autocomplete/blob/next/packages/autocomplete-core/src/getDefaultProps.ts.
367
+ */
368
+ const inputProps = {
369
+ enterKeyHint: props.isAskAiActive ? "enter" : "search",
370
+ onKeyDown: (e) => {
371
+ let askAiHandled = false;
372
+ if (props.isAskAiActive && blockedKeys.has(e.key)) {
373
+ if (e.key === "Enter" && !isAskAiStreaming && props.state.query) props.onAskAgain(props.state.query);
374
+ askAiHandled = true;
375
+ }
376
+ if (askAiHandled) {
377
+ e.preventDefault();
378
+ e.stopPropagation();
379
+ return;
380
+ }
381
+ origOnKeyDown === null || origOnKeyDown === void 0 || origOnKeyDown(e);
382
+ },
383
+ onChange: (e) => {
384
+ if (props.isAskAiActive) {
385
+ props.setQuery(e.currentTarget.value);
386
+ e.preventDefault();
387
+ e.stopPropagation();
388
+ return;
389
+ }
390
+ origOnChange === null || origOnChange === void 0 || origOnChange(e);
391
+ },
392
+ disabled: isAskAiStreaming || isThreadDepthError && props.isAskAiActive
393
+ };
394
+ const handleAskAiBackClick = React.useCallback(() => {
395
+ if (isThreadDepthError) {
396
+ props.onNewConversation();
397
+ return;
398
+ }
399
+ if (askAiState === "conversation-history") {
400
+ onAskAiToggle(true);
401
+ setAskAiState("initial");
402
+ return;
403
+ }
404
+ onAskAiToggle(false);
405
+ }, [
406
+ askAiState,
407
+ isThreadDepthError,
408
+ onAskAiToggle,
409
+ setAskAiState,
410
+ props
411
+ ]);
412
+ const leadingElement = props.isAskAiActive ? /* @__PURE__ */ React.createElement("button", {
413
+ type: "button",
414
+ tabIndex: 0,
415
+ className: "DocSearch-Action DocSearch-AskAi-Return",
416
+ title: backToKeywordSearchButtonText,
417
+ "aria-label": backToKeywordSearchButtonAriaLabel,
418
+ onClick: handleAskAiBackClick
419
+ }, /* @__PURE__ */ React.createElement(BackIcon, null)) : void 0;
420
+ const inputOverlay = heading ? /* @__PURE__ */ React.createElement(ModalHeading, {
421
+ heading,
422
+ shimmer: isAskAiStreaming
423
+ }) : null;
424
+ const actionsBeforeClose = /* @__PURE__ */ React.createElement(React.Fragment, null, !props.isAskAiActive && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", {
425
+ className: "DocSearch-Clear",
426
+ type: "reset",
427
+ "aria-label": clearButtonAriaLabel,
428
+ hidden: !props.state.query,
429
+ tabIndex: props.state.query ? 0 : -1,
430
+ "aria-hidden": !props.state.query ? "true" : "false"
431
+ }, clearButtonTitle), props.state.query && /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Divider" })), isAskAiStreaming && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", {
432
+ type: "button",
433
+ className: "DocSearch-Action DocSearch-StopStreaming",
434
+ onClick: props.onStopAskAiStreaming
435
+ }, /* @__PURE__ */ React.createElement(StopIcon, null)), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Divider" })), renderMoreOptions && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Menu, null, /* @__PURE__ */ React.createElement(Menu.Trigger, { className: "DocSearch-Action" }, /* @__PURE__ */ React.createElement(MoreVerticalIcon, null)), /* @__PURE__ */ React.createElement(Menu.Content, null, /* @__PURE__ */ React.createElement(Menu.Item, { onClick: props.onNewConversation }, /* @__PURE__ */ React.createElement(NewConversationIcon, null), startNewConversationText), hasRecentConversations && /* @__PURE__ */ React.createElement(Menu.Item, { onClick: props.onViewConversationHistory }, /* @__PURE__ */ React.createElement(ConversationHistoryIcon, null), viewConversationHistoryText))), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Divider" })));
436
+ return /* @__PURE__ */ React.createElement(SearchBoxForm, _objectSpread2(_objectSpread2({}, props), {}, {
437
+ placeholder: searchPlaceholder,
438
+ clearButtonTitle,
439
+ clearButtonAriaLabel,
440
+ closeButtonText,
441
+ closeButtonAriaLabel,
442
+ searchInputLabel,
443
+ leadingElement,
444
+ inputOverlay,
445
+ hideInput: Boolean(heading),
446
+ actionsBeforeClose,
447
+ inputProps
448
+ }));
449
+ }
450
+
451
+ //#endregion
452
+ //#region src/utils/createAskAiSources.ts
453
+ const MAX_RECENT_CONVERSATIONS_DISPLAYED = 3;
454
+ const EMPTY_RESULT_CONTENT = {
455
+ value: "",
456
+ matchLevel: "none",
457
+ matchedWords: []
458
+ };
459
+ const EMPTY_HIERARCHY_HIGHLIGHT_RESULT = {
460
+ lvl0: EMPTY_RESULT_CONTENT,
461
+ lvl1: EMPTY_RESULT_CONTENT,
462
+ lvl2: EMPTY_RESULT_CONTENT,
463
+ lvl3: EMPTY_RESULT_CONTENT,
464
+ lvl4: EMPTY_RESULT_CONTENT,
465
+ lvl5: EMPTY_RESULT_CONTENT,
466
+ lvl6: EMPTY_RESULT_CONTENT
467
+ };
468
+ const EMPTY_HIGHLIGHT_RESULT = {
469
+ content: EMPTY_RESULT_CONTENT,
470
+ hierarchy: EMPTY_HIERARCHY_HIGHLIGHT_RESULT,
471
+ hierarchy_camel: []
472
+ };
473
+ const EMPTY_SNIPPET_RESULT = {
474
+ content: EMPTY_RESULT_CONTENT,
475
+ hierarchy: EMPTY_HIERARCHY_HIGHLIGHT_RESULT,
476
+ hierarchy_camel: []
477
+ };
478
+ function buildRecentConversationSources({ conversations, disableUserPersonalization, setMessages, onAskAiToggle }) {
479
+ return [{
480
+ sourceId: SOURCE_IDS.recentConversations,
481
+ getItems() {
482
+ if (disableUserPersonalization) return [];
483
+ return conversations.getAll().slice(0, MAX_RECENT_CONVERSATIONS_DISPLAYED);
484
+ },
485
+ onSelect({ item }) {
486
+ if (item.messages) {
487
+ setMessages(item.messages);
488
+ onAskAiToggle(true);
489
+ }
490
+ }
491
+ }];
492
+ }
493
+ function createAskAiHit({ query, objectID, lvl0 }) {
494
+ return {
495
+ type: "askAI",
496
+ query,
497
+ url_without_anchor: "",
498
+ objectID,
499
+ content: null,
500
+ url: "",
501
+ anchor: null,
502
+ hierarchy: {
503
+ lvl0,
504
+ lvl1: query,
505
+ lvl2: null,
506
+ lvl3: null,
507
+ lvl4: null,
508
+ lvl5: null,
509
+ lvl6: null
510
+ },
511
+ _highlightResult: EMPTY_HIGHLIGHT_RESULT,
512
+ _snippetResult: EMPTY_SNIPPET_RESULT,
513
+ __docsearch_parent: null
514
+ };
515
+ }
516
+ async function getPromptSuggestions({ query, indexName, searchClient, hitsPerPage = 3 }) {
517
+ try {
518
+ const { results } = await searchClient.search({ requests: [{
519
+ query,
520
+ indexName,
521
+ hitsPerPage,
522
+ attributesToRetrieve: ["prompt"]
523
+ }] });
524
+ return results[0].hits.map((hit) => createAskAiHit({
525
+ query: hit.prompt,
526
+ objectID: hit.objectID,
527
+ lvl0: "Prompt Suggestions"
528
+ }));
529
+ } catch (_unused) {
530
+ return [];
531
+ }
532
+ }
533
+ async function buildAskAiActionSources({ query, handleSelectAskAiQuestion, promptSuggestionsOptions, searchClient }) {
534
+ const promptSuggestions = promptSuggestionsOptions ? await getPromptSuggestions({
535
+ query,
536
+ indexName: promptSuggestionsOptions.indexName,
537
+ hitsPerPage: promptSuggestionsOptions.hitsPerPage,
538
+ searchClient
539
+ }) : [];
540
+ return [{
541
+ sourceId: SOURCE_IDS.askAI,
542
+ getItems() {
543
+ return [createAskAiHit({
544
+ query,
545
+ objectID: "ask-ai-button",
546
+ lvl0: "Ask AI"
547
+ }), ...promptSuggestions];
548
+ },
549
+ onSelect({ item }) {
550
+ if (item.type === "askAI" && item.query) handleSelectAskAiQuestion(true, item.query);
551
+ }
552
+ }];
553
+ }
554
+
555
+ //#endregion
556
+ //#region src/DocSearchAskAiModal.tsx
557
+ const _excluded = [
558
+ "appId",
559
+ "apiKey",
560
+ "askAi",
561
+ "maxResultsPerGroup",
562
+ "theme",
563
+ "onClose",
564
+ "transformItems",
565
+ "hitComponent",
566
+ "resultsFooterComponent",
567
+ "navigator",
568
+ "initialScrollY",
569
+ "transformSearchClient",
570
+ "disableUserPersonalization",
571
+ "initialQuery",
572
+ "translations",
573
+ "getMissingResultsUrl",
574
+ "insights",
575
+ "onAskAiToggle",
576
+ "interceptAskAiEvent",
577
+ "isAskAiActive",
578
+ "recentSearchesLimit",
579
+ "recentSearchesWithFavoritesLimit",
580
+ "indices",
581
+ "indexName",
582
+ "searchParameters",
583
+ "facets",
584
+ "isHybridModeSupported"
585
+ ];
586
+ const _excluded2 = [
587
+ "footer",
588
+ "searchBox",
589
+ "facets"
590
+ ];
591
+ function DocSearchAskAiModal(_ref) {
592
+ var _translations$searchB, _askAiConfig$memory$e, _askAiConfig$memory, _askAiConfig$tools;
593
+ let { appId, apiKey, askAi, maxResultsPerGroup, theme, onClose = noop, transformItems = identity, hitComponent = Hit, resultsFooterComponent = () => null, navigator, initialScrollY = 0, transformSearchClient = identity, disableUserPersonalization = false, initialQuery: initialQueryFromProp = "", translations = {}, getMissingResultsUrl, insights = false, onAskAiToggle, interceptAskAiEvent, isAskAiActive = false, recentSearchesLimit = 7, recentSearchesWithFavoritesLimit = 4, indices = [], indexName, searchParameters, facets, isHybridModeSupported = false } = _ref, props = _objectWithoutProperties(_ref, _excluded);
594
+ const { footer: footerTranslations, searchBox: searchBoxTranslations, facets: facetBarTranslations } = translations, screenStateTranslations = _objectWithoutProperties(translations, _excluded2);
595
+ const [state, setState] = React.useState({
596
+ query: "",
597
+ collections: [],
598
+ completion: null,
599
+ context: {},
600
+ isOpen: false,
601
+ activeItemId: null,
602
+ status: "idle"
603
+ });
604
+ const canHandleAskAi = Boolean(askAi);
605
+ let placeholder = (translations === null || translations === void 0 || (_translations$searchB = translations.searchBox) === null || _translations$searchB === void 0 ? void 0 : _translations$searchB.placeholderText) || props.placeholder || "Search docs";
606
+ if (canHandleAskAi) {
607
+ var _translations$searchB2;
608
+ placeholder = (translations === null || translations === void 0 || (_translations$searchB2 = translations.searchBox) === null || _translations$searchB2 === void 0 ? void 0 : _translations$searchB2.placeholderText) || "Search docs or ask AI a question";
609
+ }
610
+ if (isAskAiActive) {
611
+ var _translations$searchB3;
612
+ placeholder = (translations === null || translations === void 0 || (_translations$searchB3 = translations.searchBox) === null || _translations$searchB3 === void 0 ? void 0 : _translations$searchB3.placeholderTextAskAi) || "Ask another question...";
613
+ }
614
+ const { containerRef, modalRef, formElementRef, dropdownRef, inputRef, snippetLength } = useModalRefs();
615
+ const { initialQuery, initialQueryFromSelection } = useInitialModalQuery(initialQueryFromProp);
616
+ const searchClient = useSearchClient(appId, apiKey, transformSearchClient);
617
+ const askAiConfig = typeof askAi === "object" ? askAi : null;
618
+ const askAiConfigurationId = askAiConfig ? askAiConfig.assistantId : askAi;
619
+ const askAiSearchParameters = askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.searchParameters;
620
+ const [askAiState, setAskAiState] = React.useState("initial");
621
+ const suggestedQuestions = useSuggestedQuestions({
622
+ assistantId: askAiConfigurationId,
623
+ searchClient,
624
+ suggestedQuestionsEnabled: askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.suggestedQuestions
625
+ });
626
+ const memoryEnabled = (_askAiConfig$memory$e = askAiConfig === null || askAiConfig === void 0 || (_askAiConfig$memory = askAiConfig.memory) === null || _askAiConfig$memory === void 0 ? void 0 : _askAiConfig$memory.enabled) !== null && _askAiConfig$memory$e !== void 0 ? _askAiConfig$memory$e : false;
627
+ const tools = (_askAiConfig$tools = askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.tools) !== null && _askAiConfig$tools !== void 0 ? _askAiConfig$tools : EMPTY_TOOLS;
628
+ const indexes = React.useMemo(() => normalizeDocSearchIndexes({
629
+ indexName,
630
+ indices,
631
+ searchParameters
632
+ }), [
633
+ indexName,
634
+ indices,
635
+ searchParameters
636
+ ]);
637
+ const defaultIndexName = indexes[0].name;
638
+ const autocompleteRef = React.useRef(void 0);
639
+ const { visibleFacets, facetSelections, facetSelectionsRef, handleFacetSelectionChange, clearFacetSelections } = useDocSearchFacets({
640
+ facets,
641
+ indexes,
642
+ searchClient,
643
+ onSelectionsChange: () => {
644
+ var _autocompleteRef$curr;
645
+ return (_autocompleteRef$curr = autocompleteRef.current) === null || _autocompleteRef$curr === void 0 ? void 0 : _autocompleteRef$curr.refresh();
646
+ }
647
+ });
648
+ const { favoriteSearches, recentSearches } = useStoredDocSearches({
649
+ defaultIndexName,
650
+ recentSearchesLimit,
651
+ recentSearchesWithFavoritesLimit
652
+ });
653
+ const [stoppedStream, setStoppedStream] = React.useState(false);
654
+ const { chatId, messages, status, setMessages, sendMessage, stopAskAiStreaming, askAiError, sendFeedback, conversations, startNewConversation, restoreConversation } = useAskAi({
655
+ assistantId: askAiConfigurationId,
656
+ apiKey: (askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.apiKey) || apiKey,
657
+ appId: (askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.appId) || appId,
658
+ indexName: (askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.indexName) || defaultIndexName,
659
+ searchParameters: askAiSearchParameters,
660
+ tools,
661
+ memory: askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.memory,
662
+ indices: askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.indices
663
+ });
664
+ const prevStatus = React.useRef(status);
665
+ React.useEffect(() => {
666
+ if (disableUserPersonalization) return;
667
+ if (prevStatus.current === "streaming" && status === "ready") {
668
+ if (stoppedStream && messages.at(-1)) messages.at(-1).metadata = { stopped: true };
669
+ for (const part of messages[0].parts) if (part.type === "text") conversations.add(buildDummyAskAiHit(part.text, messages, chatId));
670
+ }
671
+ prevStatus.current = status;
672
+ }, [
673
+ status,
674
+ messages,
675
+ conversations,
676
+ disableUserPersonalization,
677
+ stoppedStream,
678
+ chatId
679
+ ]);
680
+ const hasThreadDepthError = React.useMemo(() => {
681
+ return status === "error" && isThreadDepthError(askAiError);
682
+ }, [status, askAiError]);
683
+ const saveRecentSearch = useSaveRecentSearch({
684
+ favoriteSearches,
685
+ recentSearches,
686
+ disableUserPersonalization
687
+ });
688
+ const sendItemClickEvent = useSendItemClickEvent(state);
689
+ const handleSelectAskAiQuestion = React.useCallback((toggle, query, suggestedQuestion = void 0) => {
690
+ if (toggle) {
691
+ const initialMessage = {
692
+ query,
693
+ suggestedQuestionId: suggestedQuestion === null || suggestedQuestion === void 0 ? void 0 : suggestedQuestion.objectID
694
+ };
695
+ if (interceptAskAiEvent === null || interceptAskAiEvent === void 0 ? void 0 : interceptAskAiEvent(initialMessage)) {
696
+ if (autocompleteRef.current) autocompleteRef.current.setQuery("");
697
+ return;
698
+ }
699
+ }
700
+ if (toggle && askAiState === "new-conversation") setAskAiState("initial");
701
+ onAskAiToggle(toggle, {
702
+ query,
703
+ suggestedQuestionId: suggestedQuestion === null || suggestedQuestion === void 0 ? void 0 : suggestedQuestion.objectID
704
+ });
705
+ if (isHybridModeSupported) return;
706
+ setStoppedStream(false);
707
+ const messageOptions = {};
708
+ if (suggestedQuestion) messageOptions.body = { suggestedQuestionId: suggestedQuestion.objectID };
709
+ sendMessage({
710
+ role: "user",
711
+ parts: [{
712
+ type: "text",
713
+ text: query
714
+ }]
715
+ }, messageOptions);
716
+ if (dropdownRef.current) {
717
+ const el = dropdownRef.current;
718
+ if (typeof el.scrollTo === "function") el.scrollTo({
719
+ top: 0,
720
+ behavior: "smooth"
721
+ });
722
+ else el.scrollTop = 0;
723
+ }
724
+ if (autocompleteRef.current) autocompleteRef.current.setQuery("");
725
+ }, [
726
+ askAiState,
727
+ onAskAiToggle,
728
+ isHybridModeSupported,
729
+ sendMessage,
730
+ dropdownRef,
731
+ interceptAskAiEvent
732
+ ]);
733
+ const handleFeedbackSubmit = React.useCallback(async (messageId, feedback) => {
734
+ if (!askAiConfigurationId || !appId) return;
735
+ await sendFeedback(messageId, feedback);
736
+ }, [
737
+ askAiConfigurationId,
738
+ appId,
739
+ sendFeedback
740
+ ]);
741
+ if (!autocompleteRef.current) autocompleteRef.current = createAutocomplete({
742
+ id: "docsearch",
743
+ defaultActiveItemId: 0,
744
+ openOnFocus: true,
745
+ initialState: {
746
+ query: initialQuery,
747
+ context: { searchSuggestions: [] }
748
+ },
749
+ insights: Boolean(insights),
750
+ navigator,
751
+ onStateChange(changes) {
752
+ setState(changes.state);
753
+ },
754
+ async getSources({ query, state: sourcesState, setContext, setStatus }) {
755
+ if (!query) {
756
+ const noQuerySources = buildNoQuerySources({
757
+ recentSearches,
758
+ favoriteSearches,
759
+ saveRecentSearch,
760
+ onClose,
761
+ disableUserPersonalization
762
+ });
763
+ return [...canHandleAskAi ? buildRecentConversationSources({
764
+ conversations,
765
+ disableUserPersonalization,
766
+ setMessages,
767
+ onAskAiToggle
768
+ }) : [], ...noQuerySources];
769
+ }
770
+ const algoliaSourcesPromise = buildQuerySources({
771
+ query,
772
+ state: { context: sourcesState.context },
773
+ setContext,
774
+ setStatus,
775
+ searchClient,
776
+ indexes,
777
+ snippetLength,
778
+ insights: Boolean(insights),
779
+ appId,
780
+ apiKey,
781
+ maxResultsPerGroup,
782
+ transformItems,
783
+ saveRecentSearch,
784
+ onClose,
785
+ facetSelections: facetSelectionsRef
786
+ });
787
+ const askAiSourcesPromise = canHandleAskAi ? buildAskAiActionSources({
788
+ query,
789
+ handleSelectAskAiQuestion,
790
+ promptSuggestionsOptions: askAiConfig === null || askAiConfig === void 0 ? void 0 : askAiConfig.promptSuggestions,
791
+ searchClient
792
+ }) : Promise.resolve([]);
793
+ const [askAiSources, algoliaSources] = await Promise.all([askAiSourcesPromise, algoliaSourcesPromise]);
794
+ return [...askAiSources, ...algoliaSources];
795
+ }
796
+ });
797
+ const autocomplete = autocompleteRef.current;
798
+ const { getEnvironmentProps, getRootProps, refresh } = autocomplete;
799
+ useModalEnvironment({
800
+ getEnvironmentProps,
801
+ containerRef,
802
+ dropdownRef,
803
+ formElementRef,
804
+ inputRef,
805
+ initialScrollY,
806
+ modalRef,
807
+ snippetLength,
808
+ theme
809
+ });
810
+ React.useEffect(() => {
811
+ if (dropdownRef.current && !isAskAiActive) scrollTo(dropdownRef.current);
812
+ }, [
813
+ state.query,
814
+ isAskAiActive,
815
+ dropdownRef
816
+ ]);
817
+ useRefreshOnInitialQuery({
818
+ initialQuery,
819
+ inputRef,
820
+ refresh
821
+ });
822
+ const hasCurrentMessages = messages.length > 0;
823
+ React.useEffect(() => {
824
+ if (!isAskAiActive) {
825
+ autocomplete.refresh();
826
+ if (hasCurrentMessages) startNewConversation();
827
+ }
828
+ }, [
829
+ isAskAiActive,
830
+ autocomplete,
831
+ startNewConversation,
832
+ hasCurrentMessages
833
+ ]);
834
+ React.useEffect(() => {
835
+ setAskAiState("initial");
836
+ }, [isAskAiActive, setAskAiState]);
837
+ const onStopAskAiStreaming = async () => {
838
+ setStoppedStream(true);
839
+ await stopAskAiStreaming();
840
+ };
841
+ const handleNewConversation = () => {
842
+ startNewConversation();
843
+ setAskAiState("new-conversation");
844
+ };
845
+ const handleViewConversationHistory = () => {
846
+ setAskAiState("conversation-history");
847
+ };
848
+ const selectSuggestedQuestion = (suggestedQuestion) => {
849
+ handleSelectAskAiQuestion(true, suggestedQuestion.question, suggestedQuestion);
850
+ };
851
+ let showDocsearchDropdown = true;
852
+ const hasCollections = state.collections.some((collection) => collection.source.sourceId !== SOURCE_IDS.askAI && collection.items.length > 0);
853
+ if (state.status === "idle" && hasCollections === false && state.query.length === 0 && !isAskAiActive) showDocsearchDropdown = false;
854
+ return /* @__PURE__ */ React.createElement(ModalShell, {
855
+ state,
856
+ containerRef,
857
+ modalRef,
858
+ formElementRef,
859
+ dropdownRef,
860
+ getRootProps,
861
+ showDropdown: showDocsearchDropdown,
862
+ searchBox: /* @__PURE__ */ React.createElement(AskAiSearchBox, _objectSpread2(_objectSpread2({}, autocomplete), {}, {
863
+ state,
864
+ placeholder: placeholder || "Search docs",
865
+ autoFocus: initialQuery.length === 0,
866
+ inputRef,
867
+ isFromSelection: Boolean(initialQuery) && initialQuery === initialQueryFromSelection,
868
+ translations: searchBoxTranslations,
869
+ isAskAiActive,
870
+ askAiStatus: status,
871
+ askAiError,
872
+ askAiState,
873
+ setAskAiState,
874
+ isThreadDepthError: hasThreadDepthError && askAiState !== "new-conversation",
875
+ onClose,
876
+ onAskAiToggle,
877
+ onAskAgain: (query) => {
878
+ handleSelectAskAiQuestion(true, query);
879
+ },
880
+ onStopAskAiStreaming,
881
+ onNewConversation: handleNewConversation,
882
+ onViewConversationHistory: handleViewConversationHistory
883
+ })),
884
+ filterBar: !isAskAiActive && state.query !== "" ? /* @__PURE__ */ React.createElement(FacetBar, {
885
+ facets: visibleFacets,
886
+ selections: facetSelections,
887
+ translations: facetBarTranslations,
888
+ clearSelections: clearFacetSelections,
889
+ onSelectionChange: handleFacetSelectionChange
890
+ }) : null,
891
+ screenState: /* @__PURE__ */ React.createElement(AskAiScreenState, _objectSpread2(_objectSpread2({}, autocomplete), {}, {
892
+ indexName: defaultIndexName,
893
+ state,
894
+ hitComponent,
895
+ resultsFooterComponent,
896
+ disableUserPersonalization,
897
+ recentSearches,
898
+ favoriteSearches,
899
+ conversations,
900
+ inputRef,
901
+ translations: screenStateTranslations,
902
+ getMissingResultsUrl,
903
+ isAskAiActive,
904
+ canHandleAskAi,
905
+ messages,
906
+ tools,
907
+ askAiError,
908
+ status,
909
+ hasCollections,
910
+ askAiState,
911
+ selectAskAiQuestion: handleSelectAskAiQuestion,
912
+ suggestedQuestions,
913
+ selectSuggestedQuestion,
914
+ memoryEnabled,
915
+ resultBadgeKey: props.resultBadgeKey,
916
+ onAskAiToggle,
917
+ onNewConversation: handleNewConversation,
918
+ onItemClick: (item, event) => {
919
+ if (item.type === "askAI" && item.query) {
920
+ if (item.anchor === "stored" && "messages" in item) {
921
+ const hitMessages = item.messages;
922
+ restoreConversation(hitMessages, item.chatId);
923
+ const initialMessage = {
924
+ query: item.query,
925
+ messageId: hitMessages[0].id
926
+ };
927
+ if (interceptAskAiEvent === null || interceptAskAiEvent === void 0 ? void 0 : interceptAskAiEvent(initialMessage)) {
928
+ if (autocompleteRef.current) autocompleteRef.current.setQuery("");
929
+ event.preventDefault();
930
+ return;
931
+ }
932
+ onAskAiToggle(true, initialMessage);
933
+ } else handleSelectAskAiQuestion(true, item.query);
934
+ setAskAiState("initial");
935
+ event.preventDefault();
936
+ return;
937
+ }
938
+ sendItemClickEvent(item);
939
+ saveRecentSearch(item);
940
+ if (!isModifierEvent(event)) onClose();
941
+ },
942
+ onFeedback: handleFeedbackSubmit
943
+ })),
944
+ footer: /* @__PURE__ */ React.createElement(Footer, {
945
+ translations: footerTranslations,
946
+ isAskAiActive
947
+ }),
948
+ onClose
949
+ });
950
+ }
951
+
952
+ //#endregion
953
+ export { DocSearchAskAiModal as t };
954
+ //# sourceMappingURL=DocSearchAskAiModal-CCrk6YLb.js.map