@k2b/ui 0.25.0 → 0.27.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.
- package/dist/browser/actions/GestureMenu.js +2 -2
- package/dist/browser/actions/GestureMenu.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +811 -406
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/chat-behavior.js +4 -0
- package/dist/browser/chat/chat-behavior.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +14 -0
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/command-search.js +170 -0
- package/dist/browser/chat/command-search.js.map +1 -0
- package/dist/browser/chat/composer-document.js +1 -1
- package/dist/browser/chat/composer-document.js.map +1 -1
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/content/Calendar.js +8 -7
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/CalendarDayView.js +32 -6
- package/dist/browser/content/CalendarDayView.js.map +1 -1
- package/dist/browser/content/CalendarWeekView.js +4 -3
- package/dist/browser/content/CalendarWeekView.js.map +1 -1
- package/dist/browser/content/Timeline.js +3 -3
- package/dist/browser/content/Timeline.js.map +1 -1
- package/dist/browser/content/calendar-time-view.js +0 -1
- package/dist/browser/content/calendar-time-view.js.map +1 -1
- package/dist/browser/index.js +1 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/inputs/Combobox.js +26 -5
- package/dist/browser/inputs/Combobox.js.map +1 -1
- package/dist/browser/inputs/QrScanner.js +2 -1
- package/dist/browser/inputs/QrScanner.js.map +1 -1
- package/dist/browser/inputs/SelectChip.js +43 -12
- package/dist/browser/inputs/SelectChip.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +720 -528
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/BottomSheet.js +8 -0
- package/dist/browser/layout/BottomSheet.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +159 -27
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/app-workspace-state.js +5 -1
- package/dist/browser/layout/app-workspace-state.js.map +1 -1
- package/dist/browser/layout/index.js +1 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/layout/scroll-fade.js +14 -9
- package/dist/browser/layout/scroll-fade.js.map +1 -1
- package/dist/browser/layout/sidebar-scroll-memory.js +38 -0
- package/dist/browser/layout/sidebar-scroll-memory.js.map +1 -0
- package/dist/browser/motion.js +7 -0
- package/dist/browser/motion.js.map +1 -0
- package/dist/ssr/actions/GestureMenu.js +2 -2
- package/dist/ssr/actions/GestureMenu.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +410 -93
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/chat-behavior.js +4 -0
- package/dist/ssr/chat/chat-behavior.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +14 -0
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/command-search.js +170 -0
- package/dist/ssr/chat/command-search.js.map +1 -0
- package/dist/ssr/chat/composer-document.js +1 -1
- package/dist/ssr/chat/composer-document.js.map +1 -1
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/content/Calendar.js +8 -7
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/CalendarDayView.js +32 -6
- package/dist/ssr/content/CalendarDayView.js.map +1 -1
- package/dist/ssr/content/CalendarWeekView.js +4 -3
- package/dist/ssr/content/CalendarWeekView.js.map +1 -1
- package/dist/ssr/content/Timeline.js +3 -3
- package/dist/ssr/content/Timeline.js.map +1 -1
- package/dist/ssr/content/calendar-time-view.js +0 -1
- package/dist/ssr/content/calendar-time-view.js.map +1 -1
- package/dist/ssr/index.js +1 -0
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/inputs/Combobox.js +22 -5
- package/dist/ssr/inputs/Combobox.js.map +1 -1
- package/dist/ssr/inputs/QrScanner.js +2 -1
- package/dist/ssr/inputs/QrScanner.js.map +1 -1
- package/dist/ssr/inputs/SelectChip.js +35 -11
- package/dist/ssr/inputs/SelectChip.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +254 -118
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/BottomSheet.js +8 -0
- package/dist/ssr/layout/BottomSheet.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +159 -27
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/app-workspace-state.js +5 -1
- package/dist/ssr/layout/app-workspace-state.js.map +1 -1
- package/dist/ssr/layout/index.js +1 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/layout/scroll-fade.js +14 -9
- package/dist/ssr/layout/scroll-fade.js.map +1 -1
- package/dist/ssr/layout/sidebar-scroll-memory.js +38 -0
- package/dist/ssr/layout/sidebar-scroll-memory.js.map +1 -0
- package/dist/ssr/motion.js +7 -0
- package/dist/ssr/motion.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/types/chat/ChatComposer.d.ts +44 -2
- package/dist/types/chat/chat-behavior.d.ts +4 -0
- package/dist/types/chat/chat-messages.d.ts +7 -0
- package/dist/types/chat/command-search.d.ts +39 -0
- package/dist/types/chat/index.d.ts +1 -1
- package/dist/types/content/calendar-time-view.d.ts +0 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/inputs/Combobox.d.ts +1 -0
- package/dist/types/inputs/SelectChip.d.ts +4 -0
- package/dist/types/layout/AppWorkspace.d.ts +13 -1
- package/dist/types/layout/BottomSheet.d.ts +8 -0
- package/dist/types/layout/index.d.ts +1 -1
- package/dist/types/layout/scroll-fade.d.ts +2 -0
- package/dist/types/layout/sidebar-scroll-memory.d.ts +6 -0
- package/dist/types/motion.d.ts +6 -0
- package/package.json +4 -4
|
@@ -17,33 +17,41 @@ var _tmpl$ = ["<span><strong", ">", "</strong></span>"],
|
|
|
17
17
|
_tmpl$0 = "<textarea class=\"k2b-chat-composer__measure\" rows=\"1\" tabindex=\"-1\" aria-hidden=\"true\" readonly></textarea>",
|
|
18
18
|
_tmpl$1 = ["<div class=\"k2b-chat-composer__input\" role=\"group\"", ">", "<textarea class=\"", "\" rows=\"1\"", "", "></textarea>", "</div>"],
|
|
19
19
|
_tmpl$10 = ["<span class=\"", "\">", "</span>"],
|
|
20
|
-
_tmpl$11 = ["<
|
|
21
|
-
_tmpl$12 = ["<
|
|
22
|
-
_tmpl$13 = ["<
|
|
23
|
-
_tmpl$14 = ["<div role=\"
|
|
24
|
-
_tmpl$15 = ["<div class=\"k2b-chat-
|
|
25
|
-
_tmpl$16 = ["<div
|
|
26
|
-
_tmpl$17 = ["<div
|
|
27
|
-
_tmpl$18 = ["<div class=\"k2b-chat-
|
|
28
|
-
_tmpl$19 = ["<div class=\"k2b-chat-
|
|
29
|
-
_tmpl$20 = ["<div class=\"k2b-chat-
|
|
30
|
-
_tmpl$21 = ["<div class=\"k2b-chat-
|
|
31
|
-
_tmpl$22 = ["<
|
|
32
|
-
_tmpl$23 = ["<
|
|
33
|
-
_tmpl$24 = ["<
|
|
34
|
-
_tmpl$25 = ["<span class=\"k2b-chat-
|
|
35
|
-
_tmpl$26 = ["<
|
|
36
|
-
_tmpl$27 =
|
|
37
|
-
_tmpl$28 =
|
|
38
|
-
_tmpl$29 = ["<div class=\"k2b-chat-
|
|
39
|
-
_tmpl$30 = ["<
|
|
40
|
-
_tmpl$31 = ["<
|
|
41
|
-
_tmpl$32 = ["<
|
|
42
|
-
_tmpl$33 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-
|
|
43
|
-
_tmpl$34 = ["<
|
|
44
|
-
_tmpl$35 = ["<
|
|
45
|
-
_tmpl$36 = ["<div class=\"k2b-chat-
|
|
46
|
-
|
|
20
|
+
_tmpl$11 = ["<small", ">", "</small>"],
|
|
21
|
+
_tmpl$12 = ["<button class=\"k2b-chat-composer__command\"", " type=\"button\" role=\"option\" tabindex=\"-1\"", "><i", " aria-hidden=\"true\"></i><span class=\"k2b-chat-composer__command-text\"><strong>", "</strong>", "</span></button>"],
|
|
22
|
+
_tmpl$13 = ["<b>", "</b>"],
|
|
23
|
+
_tmpl$14 = ["<div class=\"k2b-chat-composer-accessory\"><div", " class=\"k2b-chat-composer__commands\" role=\"listbox\"", ">", "</div></div>"],
|
|
24
|
+
_tmpl$15 = ["<div role=\"status\" class=\"k2b-chat-composer__loading\"><i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i><strong>", "</strong></div>"],
|
|
25
|
+
_tmpl$16 = ["<div role=\"status\"><i class=\"ti ti-alert-circle\"></i> ", "</div>"],
|
|
26
|
+
_tmpl$17 = ["<div role=\"status\">", "</div>"],
|
|
27
|
+
_tmpl$18 = ["<div class=\"k2b-chat-composer-accessory\"><div", " class=\"k2b-chat-composer__commands\" role=\"listbox\"", ">", "", "", "", "</div></div>"],
|
|
28
|
+
_tmpl$19 = ["<div class=\"k2b-chat-composer-slot\"", "><div style=\"", "\"", ">", "</div>", "", "</div>"],
|
|
29
|
+
_tmpl$20 = ["<div class=\"k2b-chat-composer__hint\" aria-live=\"polite\">", "</div>"],
|
|
30
|
+
_tmpl$21 = ["<div class=\"k2b-chat-composer__attachments\" role=\"list\"", " tabindex=\"0\">", "</div>"],
|
|
31
|
+
_tmpl$22 = ["<div class=\"k2b-chat-composer__error\" role=\"alert\"><i class=\"ti ti-alert-circle\" aria-hidden=\"true\"></i>", "</div>"],
|
|
32
|
+
_tmpl$23 = ["<div class=\"k2b-chat-composer__row\">", "", "<div class=\"k2b-chat-composer__field\">", "<div class=\"k2b-chat-composer__field-tools\">", "", "", "</div></div>", "</div>"],
|
|
33
|
+
_tmpl$24 = ["<div class=\"k2b-chat-composer-shell\">", "<section class=\"", "\"", " role=\"group\"", ">", "", "", "", "</section><div class=\"k2b-sr-only\" role=\"status\" aria-live=\"polite\">", "</div><div class=\"k2b-chat-composer__status\" role=\"status\">", "", "</div></div>"],
|
|
34
|
+
_tmpl$25 = ["<button id=\"", "\" type=\"button\" role=\"option\" tabindex=\"-1\"", "><span class=\"k2b-chat-composer__emoji-glyph\" aria-hidden=\"true\">", "</span><strong>", "</strong>", "</button>"],
|
|
35
|
+
_tmpl$26 = ["<small>:", ":</small>"],
|
|
36
|
+
_tmpl$27 = "<i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i>",
|
|
37
|
+
_tmpl$28 = "<div class=\"k2b-chat-composer__command-placeholder\" aria-hidden=\"true\"><span></span><span><span></span><span></span></span></div>",
|
|
38
|
+
_tmpl$29 = ["<div class=\"k2b-chat-composer__command-group\" role=\"group\"", "><div class=\"k2b-chat-composer__command-heading\"", " role=\"presentation\"><span>", "</span>", "</div>", "", "</div>"],
|
|
39
|
+
_tmpl$30 = ["<span class=\"k2b-chat-composer__hint-text\">", "</span>"],
|
|
40
|
+
_tmpl$31 = ["<span class=\"k2b-chat-composer__dictation\"", "><i", " aria-hidden=\"true\"></i><span>", "</span></span>"],
|
|
41
|
+
_tmpl$32 = ["<button type=\"button\" class=\"k2b-chat-composer__hint-action\"", ">", "</button>"],
|
|
42
|
+
_tmpl$33 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-remove\"", "", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
|
|
43
|
+
_tmpl$34 = ["<div class=\"k2b-chat-composer__attachment\" role=\"listitem\"><div class=\"", "\">", "", "</div>", "</div>"],
|
|
44
|
+
_tmpl$35 = ["<img", ">"],
|
|
45
|
+
_tmpl$36 = ["<div class=\"k2b-chat-composer__attachment-identity\">", "", "</div>"],
|
|
46
|
+
_tmpl$37 = ["<a class=\"k2b-chat-composer__attachment-link\"", " target=\"_blank\" rel=\"noopener noreferrer\"", ">", "", "</a>"],
|
|
47
|
+
_tmpl$38 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-action\"", ">", "", "</button>"],
|
|
48
|
+
_tmpl$39 = ["<footer class=\"k2b-chat-composer__footer\">", "</footer>"],
|
|
49
|
+
_tmpl$40 = ["<div class=\"k2b-chat-composer__tools\">", "", "", "", "", "", "", "</div>"],
|
|
50
|
+
_tmpl$41 = ["<div class=\"k2b-chat-composer__submit\">", "", "", "", "", "</div>"],
|
|
51
|
+
_tmpl$42 = ["<span>", "</span>"],
|
|
52
|
+
_tmpl$43 = ["<div class=\"k2b-chat-composer__status-line\"", "><i aria-hidden=\"true\"", "></i><span>", "</span></div>"],
|
|
53
|
+
_tmpl$44 = ["<span class=\"k2b-sr-only\">", "</span>"];
|
|
54
|
+
import { batch, children, createEffect, createMemo, createSignal, createUniqueId, For, onCleanup, onMount, Show, untrack } from "solid-js";
|
|
47
55
|
import { Dropdown } from "../actions/Dropdown";
|
|
48
56
|
import { Tooltip } from "../feedback/Tooltip";
|
|
49
57
|
import { replaceTextareaRange } from "../inputs/editor-dom";
|
|
@@ -57,14 +65,25 @@ import { useSelectMessages } from "../inputs/select-messages";
|
|
|
57
65
|
import { useLocale } from "../intl/locale";
|
|
58
66
|
import { useUiMessages } from "../intl/messages";
|
|
59
67
|
import { ChatContextUsage as ContextUsage } from "./ChatPrimitives";
|
|
60
|
-
import { conversationEnterAction, executeChatAction, nextChatCommandIndex, reportChatFailure, runChatSubmission } from "./chat-behavior";
|
|
68
|
+
import { chatCommandKey, conversationEnterAction, executeChatAction, nextChatCommandIndex, reportChatFailure, runChatSubmission } from "./chat-behavior";
|
|
61
69
|
import { useChatMessages } from "./chat-messages";
|
|
70
|
+
import { chatCommandListModel, parseChatCommandQuery } from "./command-search";
|
|
62
71
|
import { chatCommandQuery, chatMentionSegments, reconcileChatMentions } from "./composer-document";
|
|
63
72
|
const composerMaxInputHeight = 309;
|
|
73
|
+
const commandDoneMs = 3_000;
|
|
64
74
|
/** Emoji suggestions for a `:shortcode`, as many as fit the list without scrolling on a phone. */
|
|
65
75
|
const emojiSuggestionLimit = 8;
|
|
66
76
|
// Keep editor undo text within approximately 2 MiB, plus the current edit.
|
|
67
77
|
const composerUndoBudgetChars = 1_000_000;
|
|
78
|
+
|
|
79
|
+
/** An action can cancel and restore its token, or report a short completion message. */
|
|
80
|
+
|
|
81
|
+
/** A fixed place in the slash list. Sections keep the given order, also while searching. */
|
|
82
|
+
|
|
83
|
+
/** First-word narrowing; Tab writes `words[0]` followed by a space. */
|
|
84
|
+
|
|
85
|
+
/** Passed as the third argument to `searchCommands`. */
|
|
86
|
+
|
|
68
87
|
/** The row stays short: what a chat message needs. Other Markdown, typed by hand, keeps working. */
|
|
69
88
|
const formatTools = [{
|
|
70
89
|
id: "bold",
|
|
@@ -107,7 +126,36 @@ export function ChatComposer(props) {
|
|
|
107
126
|
const selectMessages = useSelectMessages();
|
|
108
127
|
const commandListId = `k2b-chat-commands-${createUniqueId().replace(/[^A-Za-z0-9_-]/g, "-")}`;
|
|
109
128
|
const formatGroupId = `${commandListId}-format`;
|
|
129
|
+
// Emoji suggestions keep their index-based selection and ids.
|
|
110
130
|
const [selectedCommandIndex, setSelectedCommandIndex] = createSignal(0);
|
|
131
|
+
const [activeCommandKey, setActiveCommandKey] = createSignal();
|
|
132
|
+
const [commandMoved, setCommandMoved] = createSignal(false);
|
|
133
|
+
const commandIds = new Map();
|
|
134
|
+
let commandIdCounter = 0;
|
|
135
|
+
const commandOptionId = command => {
|
|
136
|
+
const key = chatCommandKey(command);
|
|
137
|
+
if (!commandIds.has(key)) commandIds.set(key, commandIdCounter++);
|
|
138
|
+
return `${commandListId}-c${commandIds.get(key)}`;
|
|
139
|
+
};
|
|
140
|
+
const [closedAt, setClosedAt] = createSignal();
|
|
141
|
+
// Where the pending native edit starts; a selection replaced as a whole starts at its beginning.
|
|
142
|
+
let inputStart;
|
|
143
|
+
const [commandStatus, setCommandStatus] = createSignal();
|
|
144
|
+
const [announcement, setAnnouncement] = createSignal();
|
|
145
|
+
let statusTimer;
|
|
146
|
+
let disposed = false;
|
|
147
|
+
const showCommandStatus = status => {
|
|
148
|
+
if (disposed) return;
|
|
149
|
+
clearTimeout(statusTimer);
|
|
150
|
+
setCommandStatus(status);
|
|
151
|
+
if (status?.tone === "done") {
|
|
152
|
+
statusTimer = setTimeout(() => setCommandStatus(undefined), commandDoneMs);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
onCleanup(() => {
|
|
156
|
+
disposed = true;
|
|
157
|
+
clearTimeout(statusTimer);
|
|
158
|
+
});
|
|
111
159
|
const [addingFiles, setAddingFiles] = createSignal(false);
|
|
112
160
|
const [submitting, setSubmitting] = createSignal(false);
|
|
113
161
|
let composerRef;
|
|
@@ -131,6 +179,9 @@ export function ChatComposer(props) {
|
|
|
131
179
|
const [dismissed, setDismissed] = createSignal(false);
|
|
132
180
|
const [composing, setComposing] = createSignal(false);
|
|
133
181
|
const [searchResults, setSearchResults] = createSignal([]);
|
|
182
|
+
const [searchResultsQuery, setSearchResultsQuery] = createSignal();
|
|
183
|
+
const [searchResultsScope, setSearchResultsScope] = createSignal();
|
|
184
|
+
const [suggestionAnnouncement, setSuggestionAnnouncement] = createSignal();
|
|
134
185
|
const [searching, setSearching] = createSignal(false);
|
|
135
186
|
const [searchError, setSearchError] = createSignal(false);
|
|
136
187
|
const [executing, setExecuting] = createSignal(false);
|
|
@@ -150,13 +201,51 @@ export function ChatComposer(props) {
|
|
|
150
201
|
return token && index ? suggestEmoji(index, token.query, emojiSuggestionLimit) : [];
|
|
151
202
|
});
|
|
152
203
|
const emojiOpen = () => emojiMatches().length > 0;
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
204
|
+
const caretCommandToken = createMemo(() => chatCommandQuery(props.value, caret(), selectionEnd()));
|
|
205
|
+
const caretCommandStart = createMemo(() => caretCommandToken()?.start);
|
|
206
|
+
// Retained server rows belong to one `/`: they go when it does or when another `/` starts.
|
|
207
|
+
createEffect(() => {
|
|
208
|
+
caretCommandStart();
|
|
209
|
+
setSearchResults([]);
|
|
210
|
+
setSearchResultsQuery(undefined);
|
|
211
|
+
});
|
|
212
|
+
// Escape closes the list for one `/` character, wherever the caret or selection goes; only that `/` going away ends it.
|
|
213
|
+
createEffect(() => {
|
|
214
|
+
const closed = closedAt();
|
|
215
|
+
if (closed !== undefined && props.value[closed] !== "/") setClosedAt(undefined);
|
|
216
|
+
});
|
|
217
|
+
const commandQuery = createMemo(() => {
|
|
218
|
+
const token = caretCommandToken();
|
|
219
|
+
return dismissed() || composing() || token?.start === closedAt() ? null : token;
|
|
220
|
+
});
|
|
221
|
+
const parsedCommandQuery = createMemo(() => parseChatCommandQuery(commandQuery()?.query ?? "", props.commandScopes ?? []));
|
|
222
|
+
const currentCommandScope = createMemo(() => parsedCommandQuery().scope?.id);
|
|
223
|
+
createEffect(() => {
|
|
224
|
+
currentCommandScope();
|
|
225
|
+
setSearchResults([]);
|
|
226
|
+
setSearchResultsQuery(undefined);
|
|
227
|
+
});
|
|
228
|
+
const localCommands = createMemo(() => props.commands ?? []);
|
|
229
|
+
const commandModel = createMemo(() => chatCommandListModel({
|
|
230
|
+
query: commandQuery()?.query ?? "",
|
|
231
|
+
scopes: props.commandScopes,
|
|
232
|
+
sections: props.commandSections,
|
|
233
|
+
commands: localCommands(),
|
|
234
|
+
searchResults: searchResultsScope() === parsedCommandQuery().scope?.id ? searchResults() : [],
|
|
235
|
+
searchResultsFresh: searchResultsQuery() === commandQuery()?.query && searchResultsScope() === parsedCommandQuery().scope?.id,
|
|
236
|
+
searchSettled: searchResultsQuery() !== undefined && searchResultsScope() === parsedCommandQuery().scope?.id,
|
|
237
|
+
searching: searching()
|
|
238
|
+
}));
|
|
239
|
+
const commandMatches = createMemo(() => commandQuery() ? commandModel().rows.map(row => row.command) : []);
|
|
240
|
+
const currentCommandQuery = createMemo(() => caretCommandToken()?.query);
|
|
241
|
+
// Arrow marking belongs to one token in one draft; another draft or `/` starts at the top row again.
|
|
242
|
+
createEffect(() => {
|
|
243
|
+
props.draftKey;
|
|
244
|
+
caretCommandStart();
|
|
245
|
+
currentCommandQuery();
|
|
246
|
+
setCommandMoved(false);
|
|
158
247
|
});
|
|
159
|
-
const commandsOpen = () => Boolean(!emojiOpen() && commandQuery() && (
|
|
248
|
+
const commandsOpen = () => Boolean(!emojiOpen() && commandQuery() && (localCommands().length || props.searchCommands));
|
|
160
249
|
const suggestionsOpen = () => commandsOpen() || emojiOpen();
|
|
161
250
|
createEffect(() => {
|
|
162
251
|
if (!suggestionsOpen()) return;
|
|
@@ -184,20 +273,33 @@ export function ChatComposer(props) {
|
|
|
184
273
|
});
|
|
185
274
|
});
|
|
186
275
|
createEffect(() => {
|
|
276
|
+
props.draftKey;
|
|
187
277
|
const token = commandQuery();
|
|
188
|
-
setSearchResults([]);
|
|
189
278
|
setSearchError(false);
|
|
190
279
|
if (!token || !props.searchCommands) {
|
|
191
280
|
setSearching(false);
|
|
192
281
|
return;
|
|
193
282
|
}
|
|
283
|
+
const parsed = parsedCommandQuery();
|
|
194
284
|
const abort = new AbortController();
|
|
195
285
|
setSearching(true);
|
|
196
286
|
const timer = setTimeout(() => {
|
|
197
|
-
Promise.resolve(props.searchCommands(
|
|
198
|
-
|
|
287
|
+
Promise.resolve().then(() => props.searchCommands(parsed.query, abort.signal, {
|
|
288
|
+
scope: parsed.scope?.id
|
|
289
|
+
})).then(results => {
|
|
290
|
+
if (!abort.signal.aborted) {
|
|
291
|
+
batch(() => {
|
|
292
|
+
setSearchResults(results);
|
|
293
|
+
setSearchResultsQuery(token.query);
|
|
294
|
+
setSearchResultsScope(parsed.scope?.id);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
199
297
|
}).catch(() => {
|
|
200
|
-
if (!abort.signal.aborted)
|
|
298
|
+
if (!abort.signal.aborted) {
|
|
299
|
+
setSearchResults([]);
|
|
300
|
+
setSearchResultsQuery(undefined);
|
|
301
|
+
setSearchError(true);
|
|
302
|
+
}
|
|
201
303
|
}).finally(() => {
|
|
202
304
|
if (!abort.signal.aborted) setSearching(false);
|
|
203
305
|
});
|
|
@@ -207,6 +309,52 @@ export function ChatComposer(props) {
|
|
|
207
309
|
abort.abort();
|
|
208
310
|
});
|
|
209
311
|
});
|
|
312
|
+
let settledEmpty;
|
|
313
|
+
createEffect(() => {
|
|
314
|
+
const token = commandQuery();
|
|
315
|
+
if (!token || parsedCommandQuery().scope || searchError()) {
|
|
316
|
+
settledEmpty = undefined;
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const previous = settledEmpty;
|
|
320
|
+
if (/\s$/.test(token.query) && previous?.start === token.start && previous.query.trimEnd() === token.query.trimEnd()) {
|
|
321
|
+
setClosedAt(token.start);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const settled = !searching() && (!props.searchCommands || searchResultsQuery() === token.query);
|
|
325
|
+
if (settled && commandModel().empty) {
|
|
326
|
+
settledEmpty = {
|
|
327
|
+
start: token.start,
|
|
328
|
+
query: token.query
|
|
329
|
+
};
|
|
330
|
+
if (/\s$/.test(token.query)) setClosedAt(token.start);
|
|
331
|
+
} else if (!searching()) settledEmpty = undefined;
|
|
332
|
+
});
|
|
333
|
+
let lastSuggestion;
|
|
334
|
+
createEffect(() => {
|
|
335
|
+
const model = commandModel();
|
|
336
|
+
const query = commandQuery()?.query;
|
|
337
|
+
if (!commandsOpen()) {
|
|
338
|
+
setSuggestionAnnouncement(undefined);
|
|
339
|
+
lastSuggestion = undefined;
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (searching() || searchError() || props.searchCommands && searchResultsQuery() !== query) return;
|
|
343
|
+
const text = chatMessages().commandSuggestions({
|
|
344
|
+
count: model.rows.length
|
|
345
|
+
});
|
|
346
|
+
const timer = setTimeout(() => {
|
|
347
|
+
if (lastSuggestion && lastSuggestion.query === query && lastSuggestion.text === text) return;
|
|
348
|
+
lastSuggestion = {
|
|
349
|
+
query: query ?? "",
|
|
350
|
+
text
|
|
351
|
+
};
|
|
352
|
+
setSuggestionAnnouncement({
|
|
353
|
+
text
|
|
354
|
+
});
|
|
355
|
+
}, 350);
|
|
356
|
+
onCleanup(() => clearTimeout(timer));
|
|
357
|
+
});
|
|
210
358
|
const history = [];
|
|
211
359
|
let historyIndex = -1;
|
|
212
360
|
createEffect(() => {
|
|
@@ -215,6 +363,11 @@ export function ChatComposer(props) {
|
|
|
215
363
|
history.length = 0;
|
|
216
364
|
historyIndex = -1;
|
|
217
365
|
setDismissed(true);
|
|
366
|
+
setClosedAt(undefined);
|
|
367
|
+
setSearchResults([]);
|
|
368
|
+
setSearchResultsQuery(undefined);
|
|
369
|
+
// A failure belongs to the draft it happened in; success notes may follow a command into the chat it opened.
|
|
370
|
+
if (commandStatus()?.tone === "error") showCommandStatus();
|
|
218
371
|
});
|
|
219
372
|
});
|
|
220
373
|
const snapshot = () => ({
|
|
@@ -233,6 +386,15 @@ export function ChatComposer(props) {
|
|
|
233
386
|
}
|
|
234
387
|
};
|
|
235
388
|
const edit = (value, nextMentions = reconcileChatMentions(props.value, value, mentions())) => {
|
|
389
|
+
if (commandStatus()?.tone === "error") showCommandStatus();
|
|
390
|
+
// An edit that starts at or before the closed `/` (select all, then type `/`) replaces it; the new `/` may open again.
|
|
391
|
+
const closed = closedAt();
|
|
392
|
+
if (closed !== undefined) {
|
|
393
|
+
let same = 0;
|
|
394
|
+
while (same <= closed && props.value[same] === value[same]) same++;
|
|
395
|
+
if (Math.min(same, inputStart ?? same) <= closed) setClosedAt(undefined);
|
|
396
|
+
}
|
|
397
|
+
inputStart = undefined;
|
|
236
398
|
record();
|
|
237
399
|
props.onValueChange(value);
|
|
238
400
|
props.onMentionsChange?.(nextMentions);
|
|
@@ -252,10 +414,25 @@ export function ChatComposer(props) {
|
|
|
252
414
|
});
|
|
253
415
|
};
|
|
254
416
|
const syncCaret = () => {
|
|
255
|
-
|
|
256
|
-
|
|
417
|
+
// One update, so no effect sees a half-moved selection (it would read as "no `/` here" and reopen a closed list).
|
|
418
|
+
batch(() => {
|
|
419
|
+
setCaret(textareaRef?.selectionStart ?? props.value.length);
|
|
420
|
+
setSelectionEnd(textareaRef?.selectionEnd ?? props.value.length);
|
|
421
|
+
});
|
|
257
422
|
};
|
|
258
|
-
const selectedCommand = () =>
|
|
423
|
+
const selectedCommand = createMemo(() => {
|
|
424
|
+
const rows = commandMatches();
|
|
425
|
+
return commandMoved() && rows.find(command => chatCommandKey(command) === activeCommandKey()) || rows[0];
|
|
426
|
+
});
|
|
427
|
+
const selectedCommandKey = createMemo(() => {
|
|
428
|
+
const command = selectedCommand();
|
|
429
|
+
return command ? chatCommandKey(command) : undefined;
|
|
430
|
+
});
|
|
431
|
+
createEffect(() => {
|
|
432
|
+
if (!commandsOpen()) commandIds.clear();
|
|
433
|
+
selectedCommandKey();
|
|
434
|
+
setAnnouncement(undefined);
|
|
435
|
+
});
|
|
259
436
|
const busy = () => Boolean(props.disabled || stopping() || state() === "submitting" || executing() || addingFiles());
|
|
260
437
|
const blocked = () => busy() || submitting();
|
|
261
438
|
/** The conversation field stays editable while a message is sent, so it keeps the focus and a phone its keyboard. */
|
|
@@ -318,21 +495,23 @@ export function ChatComposer(props) {
|
|
|
318
495
|
}
|
|
319
496
|
});
|
|
320
497
|
createEffect(() => {
|
|
321
|
-
commandMatches();
|
|
322
498
|
emojiMatches();
|
|
323
499
|
setSelectedCommandIndex(0);
|
|
324
500
|
});
|
|
325
501
|
createEffect(() => {
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
emojiMatches();
|
|
502
|
+
const command = selectedCommand();
|
|
503
|
+
const id = emojiOpen() ? `${commandListId}-${selectedCommandIndex()}` : command ? commandOptionId(command) : undefined;
|
|
329
504
|
queueMicrotask(() => {
|
|
330
505
|
const list = commandListRef;
|
|
331
|
-
const item = list?.querySelector(`[id="${
|
|
506
|
+
const item = id ? list?.querySelector(`[id="${id}"]`) : undefined;
|
|
332
507
|
if (!list || !item?.isConnected) return;
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
508
|
+
// Measured against the visible part of the list: a sticky section heading covers the top of it.
|
|
509
|
+
const heading = item.closest(".k2b-chat-composer__command-group")?.querySelector(".k2b-chat-composer__command-heading");
|
|
510
|
+
const listTop = list.getBoundingClientRect().top + list.clientTop;
|
|
511
|
+
const box = item.getBoundingClientRect();
|
|
512
|
+
const top = box.top - listTop - (heading?.offsetHeight ?? 0);
|
|
513
|
+
const bottom = box.bottom - listTop - list.clientHeight;
|
|
514
|
+
if (top < 0) list.scrollTop += top;else if (bottom > 0) list.scrollTop += bottom;
|
|
336
515
|
});
|
|
337
516
|
});
|
|
338
517
|
createEffect(() => {
|
|
@@ -422,9 +601,26 @@ export function ChatComposer(props) {
|
|
|
422
601
|
});
|
|
423
602
|
}
|
|
424
603
|
};
|
|
425
|
-
const
|
|
604
|
+
const narrowCommand = command => {
|
|
605
|
+
const scope = props.commandScopes?.find(scope => scope.id === command.scope);
|
|
606
|
+
const word = scope?.words[0];
|
|
426
607
|
const token = commandQuery();
|
|
427
|
-
if (!
|
|
608
|
+
if (!word || !token || !textareaRef) return false;
|
|
609
|
+
replaceTextareaRange(textareaRef, token.start + 1, token.end, `${word} `);
|
|
610
|
+
syncCaret();
|
|
611
|
+
return true;
|
|
612
|
+
};
|
|
613
|
+
const executeCommand = async (command, tab = false) => {
|
|
614
|
+
const token = commandQuery();
|
|
615
|
+
if (!token || blocked()) return;
|
|
616
|
+
if (command.disabled || command.reason) {
|
|
617
|
+
// A new object each time, so choosing the same row again inserts and announces its reason again.
|
|
618
|
+
setAnnouncement(command.reason ? {
|
|
619
|
+
text: command.reason
|
|
620
|
+
} : undefined);
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
if (command.scope && (tab || !command.action && !command.mention) && narrowCommand(command)) return;
|
|
428
624
|
const previous = snapshot();
|
|
429
625
|
const key = props.draftKey;
|
|
430
626
|
const replacement = command.mention ? command.mention.name + " " : "";
|
|
@@ -435,32 +631,66 @@ export function ChatComposer(props) {
|
|
|
435
631
|
end: token.start + command.mention.name.length,
|
|
436
632
|
attachment: command.mention
|
|
437
633
|
});
|
|
634
|
+
// A cancelled or failed command leaves no undo step behind: restoring puts the history back as well.
|
|
635
|
+
const previousHistory = {
|
|
636
|
+
entries: [...history],
|
|
637
|
+
index: historyIndex
|
|
638
|
+
};
|
|
438
639
|
edit(nextValue, nextMentions);
|
|
439
640
|
setDismissed(true);
|
|
440
641
|
setExecuting(true);
|
|
441
642
|
let submitRequested = false;
|
|
643
|
+
let restored = false;
|
|
644
|
+
const restore = () => {
|
|
645
|
+
if (props.draftKey !== key || props.value !== nextValue) return;
|
|
646
|
+
setDismissed(true);
|
|
647
|
+
props.onValueChange(previous.value);
|
|
648
|
+
props.onMentionsChange?.(previous.mentions);
|
|
649
|
+
history.splice(0, history.length, ...previousHistory.entries);
|
|
650
|
+
historyIndex = previousHistory.index;
|
|
651
|
+
restored = true;
|
|
652
|
+
};
|
|
653
|
+
showCommandStatus(command.busyLabel ? {
|
|
654
|
+
tone: "busy",
|
|
655
|
+
text: command.busyLabel
|
|
656
|
+
} : undefined);
|
|
442
657
|
try {
|
|
443
|
-
await command.action?.({
|
|
658
|
+
const result = await command.action?.({
|
|
444
659
|
setValue: value => edit(value),
|
|
445
660
|
submit: () => {
|
|
446
661
|
submitRequested = true;
|
|
447
662
|
},
|
|
448
663
|
focus
|
|
449
664
|
});
|
|
665
|
+
if (result === "cancelled") {
|
|
666
|
+
submitRequested = false;
|
|
667
|
+
restore();
|
|
668
|
+
showCommandStatus();
|
|
669
|
+
} else if (result) {
|
|
670
|
+
showCommandStatus({
|
|
671
|
+
tone: "done",
|
|
672
|
+
text: result.done
|
|
673
|
+
});
|
|
674
|
+
}
|
|
450
675
|
} catch (error) {
|
|
451
676
|
submitRequested = false;
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
677
|
+
restore();
|
|
678
|
+
// An unmounted composer has no status line left; the app's error channel keeps the failure from going silent.
|
|
679
|
+
if (disposed) props.onError?.(error);else showCommandStatus({
|
|
680
|
+
tone: "error",
|
|
681
|
+
text: error instanceof Error && error.message ? error.message : chatMessages().commandFailed
|
|
682
|
+
});
|
|
457
683
|
} finally {
|
|
684
|
+
if (commandStatus()?.tone === "busy") showCommandStatus();
|
|
458
685
|
setExecuting(false);
|
|
459
686
|
}
|
|
460
687
|
if (submitRequested && props.draftKey === key) await submit();
|
|
461
688
|
queueMicrotask(() => {
|
|
462
689
|
if (props.draftKey !== key) return;
|
|
463
|
-
|
|
690
|
+
if (restored || props.value === nextValue) {
|
|
691
|
+
const position = restored ? token.end : token.start + replacement.length;
|
|
692
|
+
textareaRef?.setSelectionRange(position, position);
|
|
693
|
+
}
|
|
464
694
|
syncCaret();
|
|
465
695
|
autoResize();
|
|
466
696
|
focus();
|
|
@@ -538,19 +768,28 @@ export function ChatComposer(props) {
|
|
|
538
768
|
if (commandsOpen()) {
|
|
539
769
|
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
540
770
|
event.preventDefault();
|
|
541
|
-
|
|
771
|
+
const index = matches.indexOf(selectedCommand());
|
|
772
|
+
const next = matches[nextChatCommandIndex(index, matches.length, event.key === "ArrowUp" ? -1 : 1)];
|
|
773
|
+
setActiveCommandKey(next ? chatCommandKey(next) : undefined);
|
|
774
|
+
setCommandMoved(true);
|
|
775
|
+
setAnnouncement(undefined);
|
|
542
776
|
return;
|
|
543
777
|
}
|
|
544
778
|
// Ctrl/⌘+Enter sends, also while suggestions are open.
|
|
545
|
-
|
|
779
|
+
const plain = !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
780
|
+
if (plain && (event.key === "Tab" || event.key === "Enter") && matches.length > 0) {
|
|
546
781
|
event.preventDefault();
|
|
547
782
|
const command = selectedCommand();
|
|
548
|
-
|
|
783
|
+
// A server row answering an earlier query may no longer match; wait for fresh results. Local rows match now.
|
|
784
|
+
const row = commandModel().rows.find(row => chatCommandKey(row.command) === selectedCommandKey());
|
|
785
|
+
const staleServerRow = row?.server && (searchResultsQuery() !== commandQuery()?.query || searchResultsScope() !== parsedCommandQuery().scope?.id);
|
|
786
|
+
if (staleServerRow) return;
|
|
787
|
+
if (command) void executeCommand(command, event.key === "Tab");
|
|
549
788
|
return;
|
|
550
789
|
}
|
|
551
790
|
if (event.key === "Escape") {
|
|
552
791
|
event.preventDefault();
|
|
553
|
-
|
|
792
|
+
setClosedAt(commandQuery()?.start);
|
|
554
793
|
return;
|
|
555
794
|
}
|
|
556
795
|
}
|
|
@@ -964,7 +1203,7 @@ export function ChatComposer(props) {
|
|
|
964
1203
|
children: part => _$ssr(_tmpl$10, Boolean(part.mention) ? "k2b-chat-composer__mention" : "", _$escape(part.text))
|
|
965
1204
|
})));
|
|
966
1205
|
}
|
|
967
|
-
})), mentions().length > 0 ? "k2b-chat-composer__textarea--highlighted" : "", _$ssrAttribute("value", _$escape(props.value, true), false), _$ssrAttribute("disabled", editBlocked(), true) + _$ssrAttribute("enterkeyhint", conversation() ? "enter" : _$escape(undefined, true), false) + _$ssrAttribute("placeholder", _$escape(props.placeholder ?? (running() ? chatMessages().addGuidance : conversation() ? chatMessages().writeConversationMessage : chatMessages().writeMessage), true), false) + _$ssrAttribute("aria-label", _$escape(props.inputLabel ?? messages().message, true), false) + _$ssrAttribute("role", suggestionsOpen() ? "combobox" : _$escape(undefined, true), false) + _$ssrAttribute("aria-autocomplete", suggestionsOpen() ? "list" : _$escape(undefined, true), false) + _$ssrAttribute("aria-controls", suggestionsOpen() ? _$escape(commandListId, true) : _$escape(undefined, true), false) + _$ssrAttribute("aria-expanded", suggestionsOpen() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("aria-activedescendant",
|
|
1206
|
+
})), mentions().length > 0 ? "k2b-chat-composer__textarea--highlighted" : "", _$ssrAttribute("value", _$escape(props.value, true), false), _$ssrAttribute("disabled", editBlocked(), true) + _$ssrAttribute("enterkeyhint", conversation() ? "enter" : _$escape(undefined, true), false) + _$ssrAttribute("placeholder", _$escape(props.placeholder ?? (running() ? chatMessages().addGuidance : conversation() ? chatMessages().writeConversationMessage : chatMessages().writeMessage), true), false) + _$ssrAttribute("aria-label", _$escape(props.inputLabel ?? messages().message, true), false) + _$ssrAttribute("role", suggestionsOpen() ? "combobox" : _$escape(undefined, true), false) + _$ssrAttribute("aria-autocomplete", suggestionsOpen() ? "list" : _$escape(undefined, true), false) + _$ssrAttribute("aria-controls", suggestionsOpen() ? _$escape(commandListId, true) : _$escape(undefined, true), false) + _$ssrAttribute("aria-expanded", suggestionsOpen() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("aria-activedescendant", emojiOpen() ? `${_$escape(commandListId, true)}-${_$escape(selectedCommandIndex(), true)}` : selectedCommand() ? _$escape(commandOptionId(selectedCommand()), true) : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
|
|
968
1207
|
get when() {
|
|
969
1208
|
return conversation();
|
|
970
1209
|
},
|
|
@@ -972,25 +1211,47 @@ export function ChatComposer(props) {
|
|
|
972
1211
|
return _$ssr(_tmpl$0);
|
|
973
1212
|
}
|
|
974
1213
|
})));
|
|
975
|
-
|
|
1214
|
+
const commandRowMap = createMemo(() => new Map(commandModel().rows.map(row => [row.command, row])));
|
|
1215
|
+
const commandGroupKey = group => group.scopeTitle ? "scope" : group.section ? `section:${group.section.id}` : "flat";
|
|
1216
|
+
const renderCommandRow = command => {
|
|
1217
|
+
const highlight = () => commandRowMap().get(command)?.highlight;
|
|
1218
|
+
const title = () => command.label ?? command.name;
|
|
1219
|
+
return _$ssr(_tmpl$12, _$ssrAttribute("id", _$escape(commandOptionId(command), true), false), _$ssrAttribute("aria-selected", _$escape(selectedCommand(), true) === _$escape(command, true), false) + _$ssrAttribute("aria-disabled", _$escape(Boolean(command.disabled || command.reason), true), false) + _$ssrAttribute("aria-describedby", command.reason ? `${_$escape(commandOptionId(command), true)}-reason` : _$escape(undefined, true), false) + _$ssrAttribute("data-reason", command.reason ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-active", selectedCommand() === command ? "true" : _$escape(undefined, true), false), _$ssrAttribute("class", _$escape(command.icon ?? "ti ti-slash", true), false), _$escape(_$createComponent(Show, {
|
|
1220
|
+
get when() {
|
|
1221
|
+
return highlight();
|
|
1222
|
+
},
|
|
1223
|
+
get fallback() {
|
|
1224
|
+
return title();
|
|
1225
|
+
},
|
|
1226
|
+
children: range => [title().slice(0, range()[0]), _$ssr(_tmpl$13, _$escape(title().slice(range()[0], range()[1]))), title().slice(range()[1])]
|
|
1227
|
+
})), _$escape(_$createComponent(Show, {
|
|
1228
|
+
get when() {
|
|
1229
|
+
return command.reason ?? command.description;
|
|
1230
|
+
},
|
|
1231
|
+
get children() {
|
|
1232
|
+
return _$ssr(_tmpl$11, _$ssrAttribute("id", command.reason ? `${_$escape(commandOptionId(command), true)}-reason` : _$escape(undefined, true), false), _$escape(command.reason ?? command.description));
|
|
1233
|
+
}
|
|
1234
|
+
})));
|
|
1235
|
+
};
|
|
1236
|
+
return _$ssr(_tmpl$24, _$escape(_$createComponent(Show, {
|
|
976
1237
|
get when() {
|
|
977
1238
|
return suggestionsOpen() || hasAccessory();
|
|
978
1239
|
},
|
|
979
1240
|
get children() {
|
|
980
|
-
return _$ssr(_tmpl$
|
|
1241
|
+
return _$ssr(_tmpl$19, _$ssrAttribute("data-overlay", hasAccessory() ? _$escape(undefined, true) : "true", false), _$ssrStyleProperty("visibility:", suggestionsOpen() ? "hidden" : _$escape(undefined, true)), _$ssrAttribute("inert", suggestionsOpen(), true), _$escape(accessory()), _$escape(_$createComponent(Show, {
|
|
981
1242
|
get when() {
|
|
982
1243
|
return emojiOpen();
|
|
983
1244
|
},
|
|
984
1245
|
get children() {
|
|
985
|
-
return _$ssr(_tmpl$
|
|
1246
|
+
return _$ssr(_tmpl$14, _$ssrAttribute("id", _$escape(commandListId, true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().emojiSuggestions, true), false), _$escape(_$createComponent(For, {
|
|
986
1247
|
get each() {
|
|
987
1248
|
return emojiMatches();
|
|
988
1249
|
},
|
|
989
|
-
children: (entry, index) => _$ssr(_tmpl$
|
|
1250
|
+
children: (entry, index) => _$ssr(_tmpl$25, `${_$escape(commandListId, true)}-${_$escape(index(), true)}`, _$ssrAttribute("aria-selected", _$escape(index(), true) === _$escape(selectedCommandIndex(), true), false) + _$ssrAttribute("aria-label", _$escape(emojiName(entry, locale()), true), false) + _$ssrAttribute("data-active", index() === selectedCommandIndex() ? "true" : _$escape(undefined, true), false), _$escape(emojiInTone(entry, props.emoji?.skinTone ?? 0)), _$escape(emojiName(entry, locale())), _$escape(_$createComponent(Show, {
|
|
990
1251
|
get when() {
|
|
991
1252
|
return entry.shortcodes[0];
|
|
992
1253
|
},
|
|
993
|
-
children: code => _$ssr(_tmpl$
|
|
1254
|
+
children: code => _$ssr(_tmpl$26, _$escape(code()))
|
|
994
1255
|
})))
|
|
995
1256
|
})));
|
|
996
1257
|
}
|
|
@@ -999,31 +1260,70 @@ export function ChatComposer(props) {
|
|
|
999
1260
|
return commandsOpen();
|
|
1000
1261
|
},
|
|
1001
1262
|
get children() {
|
|
1002
|
-
return _$ssr(_tmpl$
|
|
1263
|
+
return _$ssr(_tmpl$18, _$ssrAttribute("id", _$escape(commandListId, true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().commands, true), false) + _$ssrAttribute("aria-busy", searching() ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(For, {
|
|
1003
1264
|
get each() {
|
|
1004
|
-
return
|
|
1265
|
+
return commandModel().groups.map(commandGroupKey);
|
|
1005
1266
|
},
|
|
1006
|
-
children:
|
|
1267
|
+
children: key => {
|
|
1268
|
+
const group = createMemo(() => commandModel().groups.find(group => commandGroupKey(group) === key));
|
|
1269
|
+
const headingId = () => `${commandListId}-g-${key === "scope" ? "scope" : props.commandSections?.findIndex(section => section.id === group()?.section?.id)}`;
|
|
1270
|
+
const rows = () => group()?.rows.map(row => row.command) ?? [];
|
|
1271
|
+
return _$createComponent(Show, {
|
|
1272
|
+
when: key !== "flat",
|
|
1273
|
+
get fallback() {
|
|
1274
|
+
return _$createComponent(For, {
|
|
1275
|
+
get each() {
|
|
1276
|
+
return rows();
|
|
1277
|
+
},
|
|
1278
|
+
children: renderCommandRow
|
|
1279
|
+
});
|
|
1280
|
+
},
|
|
1281
|
+
get children() {
|
|
1282
|
+
return _$ssr(_tmpl$29, _$ssrAttribute("aria-labelledby", _$escape(headingId(), true), false), _$ssrAttribute("id", _$escape(headingId(), true), false), _$escape(group()?.scopeTitle ?? group()?.section?.label), _$escape(_$createComponent(Show, {
|
|
1283
|
+
get when() {
|
|
1284
|
+
return group()?.loading;
|
|
1285
|
+
},
|
|
1286
|
+
get children() {
|
|
1287
|
+
return _$ssr(_tmpl$27);
|
|
1288
|
+
}
|
|
1289
|
+
})), _$escape(_$createComponent(For, {
|
|
1290
|
+
get each() {
|
|
1291
|
+
return rows();
|
|
1292
|
+
},
|
|
1293
|
+
children: renderCommandRow
|
|
1294
|
+
})), _$escape(_$createComponent(Show, {
|
|
1295
|
+
get when() {
|
|
1296
|
+
return group()?.placeholder;
|
|
1297
|
+
},
|
|
1298
|
+
get children() {
|
|
1299
|
+
return _$ssr(_tmpl$28);
|
|
1300
|
+
}
|
|
1301
|
+
})));
|
|
1302
|
+
}
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1007
1305
|
})), _$escape(_$createComponent(Show, {
|
|
1008
1306
|
get when() {
|
|
1009
|
-
return searching();
|
|
1307
|
+
return _$memo(() => !!(searching() && commandMatches().length === 0))() && !commandModel().groups.some(group => group.section || group.scopeTitle);
|
|
1010
1308
|
},
|
|
1011
1309
|
get children() {
|
|
1012
|
-
return _$ssr(_tmpl$
|
|
1310
|
+
return _$ssr(_tmpl$15, _$escape(messages().loading));
|
|
1013
1311
|
}
|
|
1014
1312
|
})), _$escape(_$createComponent(Show, {
|
|
1015
1313
|
get when() {
|
|
1016
1314
|
return searchError();
|
|
1017
1315
|
},
|
|
1018
1316
|
get children() {
|
|
1019
|
-
return _$ssr(_tmpl$
|
|
1317
|
+
return _$ssr(_tmpl$16, _$escape(messages().error));
|
|
1020
1318
|
}
|
|
1021
1319
|
})), _$escape(_$createComponent(Show, {
|
|
1022
1320
|
get when() {
|
|
1023
1321
|
return _$memo(() => !!(!searching() && !searchError()))() && commandMatches().length === 0;
|
|
1024
1322
|
},
|
|
1025
1323
|
get children() {
|
|
1026
|
-
return _$ssr(_tmpl$
|
|
1324
|
+
return _$ssr(_tmpl$17, !parsedCommandQuery().query.trim() ? _$escape(messages().noResults) : _$escape(chatMessages().commandsNothingFound({
|
|
1325
|
+
query: parsedCommandQuery().query.trim()
|
|
1326
|
+
})));
|
|
1027
1327
|
}
|
|
1028
1328
|
})));
|
|
1029
1329
|
}
|
|
@@ -1034,18 +1334,18 @@ export function ChatComposer(props) {
|
|
|
1034
1334
|
return showHint();
|
|
1035
1335
|
},
|
|
1036
1336
|
get children() {
|
|
1037
|
-
return _$ssr(_tmpl$
|
|
1337
|
+
return _$ssr(_tmpl$20, _$escape(_$createComponent(Show, {
|
|
1038
1338
|
get when() {
|
|
1039
1339
|
return dictationStatus();
|
|
1040
1340
|
},
|
|
1041
1341
|
get fallback() {
|
|
1042
|
-
return _$ssr(_tmpl$
|
|
1342
|
+
return _$ssr(_tmpl$30, _$escape(hint()));
|
|
1043
1343
|
},
|
|
1044
|
-
children: status => [_$ssr(_tmpl$
|
|
1344
|
+
children: status => [_$ssr(_tmpl$31, _$ssrAttribute("data-state", _$escape(dictation() ?? undefined, true), false), _$ssrAttribute("class", _$escape(status().icon, true), false), _$escape(status().text)), _$createComponent(Show, {
|
|
1045
1345
|
get when() {
|
|
1046
1346
|
return _$memo(() => dictation() === "refined")() ? props.microphone?.onRestoreOriginal : undefined;
|
|
1047
1347
|
},
|
|
1048
|
-
children: restore => _$ssr(_tmpl$
|
|
1348
|
+
children: restore => _$ssr(_tmpl$32, _$ssrAttribute("disabled", microphoneDisabled(), true), _$escape(chatMessages().restoreOriginal))
|
|
1049
1349
|
})]
|
|
1050
1350
|
})));
|
|
1051
1351
|
}
|
|
@@ -1054,16 +1354,16 @@ export function ChatComposer(props) {
|
|
|
1054
1354
|
return attachments().length > 0;
|
|
1055
1355
|
},
|
|
1056
1356
|
get children() {
|
|
1057
|
-
return _$ssr(_tmpl$
|
|
1357
|
+
return _$ssr(_tmpl$21, _$ssrAttribute("aria-label", _$escape(chatMessages().attachments, true), false), _$escape(_$createComponent(For, {
|
|
1058
1358
|
get each() {
|
|
1059
1359
|
return attachments();
|
|
1060
1360
|
},
|
|
1061
|
-
children: attachment => _$ssr(_tmpl$
|
|
1361
|
+
children: attachment => _$ssr(_tmpl$34, `k2b-chat-composer__attachment-content ${Boolean(attachment.action) ? "k2b-chat-composer__attachment-content--action" : ""}`, _$escape(_$createComponent(Show, {
|
|
1062
1362
|
get when() {
|
|
1063
1363
|
return attachment.href;
|
|
1064
1364
|
},
|
|
1065
1365
|
get fallback() {
|
|
1066
|
-
return _$ssr(_tmpl$
|
|
1366
|
+
return _$ssr(_tmpl$36, _$escape(_$createComponent(Show, {
|
|
1067
1367
|
get when() {
|
|
1068
1368
|
return _$memo(() => attachment.kind === "image")() && attachment.previewUrl;
|
|
1069
1369
|
},
|
|
@@ -1071,11 +1371,11 @@ export function ChatComposer(props) {
|
|
|
1071
1371
|
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
|
|
1072
1372
|
},
|
|
1073
1373
|
get children() {
|
|
1074
|
-
return _$ssr(_tmpl$
|
|
1374
|
+
return _$ssr(_tmpl$35, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
|
|
1075
1375
|
}
|
|
1076
1376
|
})), _$escape(renderAttachmentCopy(attachment)));
|
|
1077
1377
|
},
|
|
1078
|
-
children: href => _$ssr(_tmpl$
|
|
1378
|
+
children: href => _$ssr(_tmpl$37, _$ssrAttribute("href", _$escape(href(), true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().openInNewTab({
|
|
1079
1379
|
name: attachment.name
|
|
1080
1380
|
}), true), false), _$escape(_$createComponent(Show, {
|
|
1081
1381
|
get when() {
|
|
@@ -1085,14 +1385,14 @@ export function ChatComposer(props) {
|
|
|
1085
1385
|
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
|
|
1086
1386
|
},
|
|
1087
1387
|
get children() {
|
|
1088
|
-
return _$ssr(_tmpl$
|
|
1388
|
+
return _$ssr(_tmpl$35, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
|
|
1089
1389
|
}
|
|
1090
1390
|
})), _$escape(renderAttachmentCopy(attachment)))
|
|
1091
1391
|
})), _$escape(_$createComponent(Show, {
|
|
1092
1392
|
get when() {
|
|
1093
1393
|
return attachment.action;
|
|
1094
1394
|
},
|
|
1095
|
-
children: action => _$ssr(_tmpl$
|
|
1395
|
+
children: action => _$ssr(_tmpl$38, _$ssrAttribute("disabled", blocked() || action().disabled, true), _$escape(_$createComponent(Show, {
|
|
1096
1396
|
get when() {
|
|
1097
1397
|
return action().icon;
|
|
1098
1398
|
},
|
|
@@ -1103,7 +1403,7 @@ export function ChatComposer(props) {
|
|
|
1103
1403
|
return props.onAttachmentsChange;
|
|
1104
1404
|
},
|
|
1105
1405
|
get children() {
|
|
1106
|
-
return _$ssr(_tmpl$
|
|
1406
|
+
return _$ssr(_tmpl$33, _$ssrAttribute("aria-label", _$escape(selectMessages().removeNamed({
|
|
1107
1407
|
name: attachment.name
|
|
1108
1408
|
}), true), false), _$ssrAttribute("disabled", blocked(), true));
|
|
1109
1409
|
}
|
|
@@ -1120,14 +1420,14 @@ export function ChatComposer(props) {
|
|
|
1120
1420
|
return props.error;
|
|
1121
1421
|
},
|
|
1122
1422
|
get children() {
|
|
1123
|
-
return _$ssr(_tmpl$
|
|
1423
|
+
return _$ssr(_tmpl$22, _$escape(props.error));
|
|
1124
1424
|
}
|
|
1125
|
-
}), formatRow(), _$ssr(_tmpl$
|
|
1425
|
+
}), formatRow(), _$ssr(_tmpl$39, _$escape(_$createComponent(Show, {
|
|
1126
1426
|
get when() {
|
|
1127
1427
|
return props.footerContent;
|
|
1128
1428
|
},
|
|
1129
1429
|
get fallback() {
|
|
1130
|
-
return [_$ssr(_tmpl$
|
|
1430
|
+
return [_$ssr(_tmpl$40, _$escape(props.footerTools), _$escape(_$createComponent(Show, {
|
|
1131
1431
|
get when() {
|
|
1132
1432
|
return hasAddMenu();
|
|
1133
1433
|
},
|
|
@@ -1168,7 +1468,7 @@ export function ChatComposer(props) {
|
|
|
1168
1468
|
}
|
|
1169
1469
|
});
|
|
1170
1470
|
}
|
|
1171
|
-
})), _$escape(props.modelDetails)), _$ssr(_tmpl$
|
|
1471
|
+
})), _$escape(props.modelDetails)), _$ssr(_tmpl$41, _$escape(_$createComponent(For, {
|
|
1172
1472
|
get each() {
|
|
1173
1473
|
return props.contextActions;
|
|
1174
1474
|
},
|
|
@@ -1218,9 +1518,9 @@ export function ChatComposer(props) {
|
|
|
1218
1518
|
return props.error;
|
|
1219
1519
|
},
|
|
1220
1520
|
get children() {
|
|
1221
|
-
return _$ssr(_tmpl$
|
|
1521
|
+
return _$ssr(_tmpl$22, _$escape(props.error));
|
|
1222
1522
|
}
|
|
1223
|
-
}), formatRow(), _$ssr(_tmpl$
|
|
1523
|
+
}), formatRow(), _$ssr(_tmpl$23, _$escape(attachControl()), _$escape(fileInput()), _$escape(field()), _$escape(formatToggle()), _$escape(emojiButton()), _$escape(microphoneControl()), _$escape(sendControl()))];
|
|
1224
1524
|
}
|
|
1225
1525
|
})), _$escape(_$createComponent(Show, {
|
|
1226
1526
|
get when() {
|
|
@@ -1241,6 +1541,23 @@ export function ChatComposer(props) {
|
|
|
1241
1541
|
},
|
|
1242
1542
|
onDrop: files => void runFiles(files)
|
|
1243
1543
|
})
|
|
1544
|
+
})), _$escape(_$createComponent(Show, {
|
|
1545
|
+
get when() {
|
|
1546
|
+
return suggestionAnnouncement();
|
|
1547
|
+
},
|
|
1548
|
+
keyed: true,
|
|
1549
|
+
children: announced => _$ssr(_tmpl$42, _$escape(announced.text))
|
|
1550
|
+
})), _$escape(_$createComponent(Show, {
|
|
1551
|
+
get when() {
|
|
1552
|
+
return _$memo(() => !!!suggestionsOpen())() && commandStatus();
|
|
1553
|
+
},
|
|
1554
|
+
children: status => _$ssr(_tmpl$43, _$ssrAttribute("data-tone", _$escape(status().tone, true), false), _$ssrAttribute("class", status().tone === "busy" ? "ti ti-loader-2 k2b-spin" : status().tone === "done" ? "ti ti-check" : "ti ti-alert-circle", false), _$escape(status().text))
|
|
1555
|
+
})), _$escape(_$createComponent(Show, {
|
|
1556
|
+
get when() {
|
|
1557
|
+
return _$memo(() => !!suggestionsOpen())() && announcement();
|
|
1558
|
+
},
|
|
1559
|
+
keyed: true,
|
|
1560
|
+
children: announced => _$ssr(_tmpl$44, _$escape(announced.text))
|
|
1244
1561
|
})));
|
|
1245
1562
|
}
|
|
1246
1563
|
//# sourceMappingURL=ChatComposer.js.map
|