@k2b/ui 0.27.0 → 0.28.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/README.md +1 -1
- package/dist/base.css +147 -2
- package/dist/browser/actions/ContextMenu.js +30 -4
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/Dropdown.js +184 -158
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/GestureMenu.js +71 -138
- package/dist/browser/actions/GestureMenu.js.map +1 -1
- package/dist/browser/actions/Toolbar.js +379 -48
- package/dist/browser/actions/Toolbar.js.map +1 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/actions/menu-rows.js +15 -0
- package/dist/browser/actions/menu-rows.js.map +1 -0
- package/dist/browser/actions/menu-sheet.js +154 -0
- package/dist/browser/actions/menu-sheet.js.map +1 -0
- package/dist/browser/actions/toolbar-messages.js +20 -0
- package/dist/browser/actions/toolbar-messages.js.map +1 -0
- package/dist/browser/chart-inspection.js +3 -0
- package/dist/browser/chart-inspection.js.map +1 -0
- package/dist/browser/chat/ChatComposer.js +581 -397
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +19 -1
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/command-search.js +3 -0
- package/dist/browser/chat/command-search.js.map +1 -1
- package/dist/browser/chat/index.js +2 -0
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/chat/reaction-people.js +15 -0
- package/dist/browser/chat/reaction-people.js.map +1 -0
- package/dist/browser/content/Chart.js +6 -15
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/ChartSnapshotView.js +7 -10
- package/dist/browser/content/ChartSnapshotView.js.map +1 -1
- package/dist/browser/content/MessageRow.js +330 -448
- package/dist/browser/content/MessageRow.js.map +1 -1
- package/dist/browser/content/ReactionBar.js +419 -0
- package/dist/browser/content/ReactionBar.js.map +1 -0
- package/dist/browser/content/chart-inspection-core.js +557 -0
- package/dist/browser/content/chart-inspection-core.js.map +1 -0
- package/dist/browser/content/chart-inspection.js +10 -445
- package/dist/browser/content/chart-inspection.js.map +1 -1
- package/dist/browser/content/chart-line-gaps.js +1 -1
- package/dist/browser/content/chart-line-gaps.js.map +1 -1
- package/dist/browser/content/chart-snapshot.js +1 -1
- package/dist/browser/content/chart-snapshot.js.map +1 -1
- package/dist/browser/content/index.js +1 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/feedback/dialog-core.js +135 -23
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/index.js +1 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/input-mode.js +40 -0
- package/dist/browser/input-mode.js.map +1 -0
- package/dist/browser/inputs/FileDropTarget.js +24 -9
- package/dist/browser/inputs/FileDropTarget.js.map +1 -1
- package/dist/browser/inputs/FileInputs.js +2 -2
- package/dist/browser/inputs/FileInputs.js.map +1 -1
- package/dist/browser/inputs/SelectChip.js +9 -0
- package/dist/browser/inputs/SelectChip.js.map +1 -1
- package/dist/browser/inputs/emoji/EmojiPicker.js +13 -0
- package/dist/browser/inputs/emoji/EmojiPicker.js.map +1 -1
- package/dist/browser/inputs/file-drop.js.map +1 -1
- package/dist/browser/layout/DetailPanel.js +283 -197
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/Discussion.js +233 -185
- package/dist/browser/layout/Discussion.js.map +1 -1
- package/dist/browser/layout/TableOfContents.js +10 -2
- package/dist/browser/layout/TableOfContents.js.map +1 -1
- package/dist/browser/layout/detail-panel-messages.js +35 -0
- package/dist/browser/layout/detail-panel-messages.js.map +1 -0
- package/dist/browser/surfaces/Avatar.js +50 -20
- package/dist/browser/surfaces/Avatar.js.map +1 -1
- package/dist/browser/surfaces/AvatarStack.js +406 -0
- package/dist/browser/surfaces/AvatarStack.js.map +1 -0
- package/dist/browser/surfaces/avatar-messages.js +8 -2
- package/dist/browser/surfaces/avatar-messages.js.map +1 -1
- package/dist/browser/surfaces/index.js +1 -0
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/ssr/actions/ContextMenu.js +21 -3
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +140 -72
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/GestureMenu.js +52 -106
- package/dist/ssr/actions/GestureMenu.js.map +1 -1
- package/dist/ssr/actions/Toolbar.js +294 -14
- package/dist/ssr/actions/Toolbar.js.map +1 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/actions/menu-rows.js +15 -0
- package/dist/ssr/actions/menu-rows.js.map +1 -0
- package/dist/ssr/actions/menu-sheet.js +138 -0
- package/dist/ssr/actions/menu-sheet.js.map +1 -0
- package/dist/ssr/actions/toolbar-messages.js +20 -0
- package/dist/ssr/actions/toolbar-messages.js.map +1 -0
- package/dist/ssr/chart-inspection.js +3 -0
- package/dist/ssr/chart-inspection.js.map +1 -0
- package/dist/ssr/chat/ChatComposer.js +263 -89
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +19 -1
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/command-search.js +3 -0
- package/dist/ssr/chat/command-search.js.map +1 -1
- package/dist/ssr/chat/index.js +2 -0
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/chat/reaction-people.js +15 -0
- package/dist/ssr/chat/reaction-people.js.map +1 -0
- package/dist/ssr/content/Chart.js +6 -15
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/ChartSnapshotView.js +7 -10
- package/dist/ssr/content/ChartSnapshotView.js.map +1 -1
- package/dist/ssr/content/MessageRow.js +98 -152
- package/dist/ssr/content/MessageRow.js.map +1 -1
- package/dist/ssr/content/ReactionBar.js +304 -0
- package/dist/ssr/content/ReactionBar.js.map +1 -0
- package/dist/ssr/content/chart-inspection-core.js +557 -0
- package/dist/ssr/content/chart-inspection-core.js.map +1 -0
- package/dist/ssr/content/chart-inspection.js +10 -445
- package/dist/ssr/content/chart-inspection.js.map +1 -1
- package/dist/ssr/content/chart-line-gaps.js +1 -1
- package/dist/ssr/content/chart-line-gaps.js.map +1 -1
- package/dist/ssr/content/chart-snapshot.js +1 -1
- package/dist/ssr/content/chart-snapshot.js.map +1 -1
- package/dist/ssr/content/index.js +1 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/feedback/dialog-core.js +135 -23
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/index.js +1 -0
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/input-mode.js +40 -0
- package/dist/ssr/input-mode.js.map +1 -0
- package/dist/ssr/inputs/FileDropTarget.js +17 -5
- package/dist/ssr/inputs/FileDropTarget.js.map +1 -1
- package/dist/ssr/inputs/FileInputs.js +2 -2
- package/dist/ssr/inputs/FileInputs.js.map +1 -1
- package/dist/ssr/inputs/SelectChip.js +9 -0
- package/dist/ssr/inputs/SelectChip.js.map +1 -1
- package/dist/ssr/inputs/emoji/EmojiPicker.js +12 -0
- package/dist/ssr/inputs/emoji/EmojiPicker.js.map +1 -1
- package/dist/ssr/inputs/file-drop.js.map +1 -1
- package/dist/ssr/layout/DetailPanel.js +112 -58
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/Discussion.js +63 -36
- package/dist/ssr/layout/Discussion.js.map +1 -1
- package/dist/ssr/layout/TableOfContents.js +10 -2
- package/dist/ssr/layout/TableOfContents.js.map +1 -1
- package/dist/ssr/layout/detail-panel-messages.js +35 -0
- package/dist/ssr/layout/detail-panel-messages.js.map +1 -0
- package/dist/ssr/surfaces/Avatar.js +20 -2
- package/dist/ssr/surfaces/Avatar.js.map +1 -1
- package/dist/ssr/surfaces/AvatarStack.js +286 -0
- package/dist/ssr/surfaces/AvatarStack.js.map +1 -0
- package/dist/ssr/surfaces/avatar-messages.js +8 -2
- package/dist/ssr/surfaces/avatar-messages.js.map +1 -1
- package/dist/ssr/surfaces/index.js +1 -0
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/ContextMenu.d.ts +8 -0
- package/dist/types/actions/Dropdown.d.ts +12 -5
- package/dist/types/actions/GestureMenu.d.ts +6 -4
- package/dist/types/actions/Toolbar.d.ts +20 -0
- package/dist/types/actions/index.d.ts +1 -1
- package/dist/types/actions/menu-rows.d.ts +5 -0
- package/dist/types/actions/menu-sheet.d.ts +22 -0
- package/dist/types/actions/toolbar-messages.d.ts +8 -0
- package/dist/types/chart-inspection.d.ts +2 -0
- package/dist/types/chat/ChatComposer.d.ts +7 -0
- package/dist/types/chat/chat-messages.d.ts +10 -2
- package/dist/types/chat/command-search.d.ts +2 -0
- package/dist/types/chat/index.d.ts +2 -0
- package/dist/types/chat/reaction-people.d.ts +9 -0
- package/dist/types/content/Chart.d.ts +2 -2
- package/dist/types/content/MessageRow.d.ts +3 -10
- package/dist/types/content/ReactionBar.d.ts +32 -0
- package/dist/types/content/chart-inspection-core.d.ts +61 -0
- package/dist/types/content/chart-inspection.d.ts +4 -20
- package/dist/types/content/chart-snapshot.d.ts +1 -1
- package/dist/types/content/index.d.ts +2 -1
- package/dist/types/feedback/dialog-core.d.ts +16 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/input-mode.d.ts +7 -0
- package/dist/types/inputs/FileDropTarget.d.ts +6 -3
- package/dist/types/inputs/SelectChip.d.ts +2 -0
- package/dist/types/inputs/file-drop.d.ts +2 -0
- package/dist/types/layout/DetailPanel.d.ts +11 -0
- package/dist/types/layout/Discussion.d.ts +8 -0
- package/dist/types/layout/TableOfContents.d.ts +2 -0
- package/dist/types/layout/detail-panel-messages.d.ts +15 -0
- package/dist/types/surfaces/Avatar.d.ts +12 -0
- package/dist/types/surfaces/AvatarStack.d.ts +41 -0
- package/dist/types/surfaces/avatar-messages.d.ts +3 -0
- package/dist/types/surfaces/index.d.ts +3 -1
- package/package.json +6 -1
|
@@ -18,41 +18,43 @@ var _tmpl$ = ["<span><strong", ">", "</strong></span>"],
|
|
|
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
20
|
_tmpl$11 = ["<small", ">", "</small>"],
|
|
21
|
-
_tmpl$12 = ["<
|
|
22
|
-
_tmpl$13 = ["<
|
|
23
|
-
_tmpl$14 = ["<
|
|
24
|
-
_tmpl$15 = ["<div
|
|
25
|
-
_tmpl$16 = ["<div role=\"status\"><i class=\"ti ti-
|
|
26
|
-
_tmpl$17 = ["<div role=\"status\">", "</div>"],
|
|
27
|
-
_tmpl$18 = ["<div
|
|
28
|
-
_tmpl$19 = ["<div class=\"k2b-chat-composer-
|
|
29
|
-
_tmpl$20 = ["<div class=\"k2b-chat-
|
|
30
|
-
_tmpl$21 = ["<div class=\"k2b-chat-
|
|
31
|
-
_tmpl$22 = ["<div class=\"k2b-chat-
|
|
32
|
-
_tmpl$23 = ["<div class=\"k2b-chat-
|
|
33
|
-
_tmpl$24 = ["<div class=\"k2b-chat-
|
|
34
|
-
_tmpl$25 = ["<
|
|
35
|
-
_tmpl$26 = ["<
|
|
36
|
-
_tmpl$27 = "<
|
|
37
|
-
_tmpl$28 = "<
|
|
38
|
-
_tmpl$29 =
|
|
39
|
-
_tmpl$30 = ["<
|
|
40
|
-
_tmpl$31 = ["<span class=\"k2b-chat-
|
|
41
|
-
_tmpl$32 = ["<
|
|
42
|
-
_tmpl$33 = ["<button type=\"button\" class=\"k2b-chat-
|
|
43
|
-
_tmpl$34 = ["<
|
|
44
|
-
_tmpl$35 = ["<
|
|
45
|
-
_tmpl$36 = ["<
|
|
46
|
-
_tmpl$37 = ["<
|
|
47
|
-
_tmpl$38 = ["<
|
|
48
|
-
_tmpl$39 = ["<
|
|
49
|
-
_tmpl$40 = ["<
|
|
50
|
-
_tmpl$41 = ["<div class=\"k2b-chat-
|
|
51
|
-
_tmpl$42 = ["<
|
|
52
|
-
_tmpl$43 = ["<
|
|
53
|
-
_tmpl$44 = ["<
|
|
21
|
+
_tmpl$12 = ["<span class=\"k2b-chat-composer__command-end\"><i class=\"ti ti-check\" aria-hidden=\"true\"></i><span class=\"k2b-sr-only\">", "</span></span>"],
|
|
22
|
+
_tmpl$13 = ["<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>"],
|
|
23
|
+
_tmpl$14 = ["<b>", "</b>"],
|
|
24
|
+
_tmpl$15 = ["<div class=\"k2b-chat-composer-accessory\"><div", " class=\"k2b-chat-composer__commands\" role=\"listbox\"", ">", "</div></div>"],
|
|
25
|
+
_tmpl$16 = ["<div role=\"status\" class=\"k2b-chat-composer__loading\"><i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i><strong>", "</strong></div>"],
|
|
26
|
+
_tmpl$17 = ["<div role=\"status\"><i class=\"ti ti-alert-circle\"></i> ", "</div>"],
|
|
27
|
+
_tmpl$18 = ["<div role=\"status\">", "</div>"],
|
|
28
|
+
_tmpl$19 = ["<div class=\"k2b-chat-composer-accessory\" data-commands><div", " class=\"k2b-chat-composer__commands\" role=\"listbox\"", ">", "", "", "", "</div></div>"],
|
|
29
|
+
_tmpl$20 = ["<div class=\"k2b-chat-composer-slot\"", "><div style=\"", "\"", ">", "</div>", "", "</div>"],
|
|
30
|
+
_tmpl$21 = ["<div class=\"k2b-chat-composer__hint\" aria-live=\"polite\">", "</div>"],
|
|
31
|
+
_tmpl$22 = ["<div class=\"k2b-chat-composer__attachments\" role=\"list\"", " tabindex=\"0\">", "</div>"],
|
|
32
|
+
_tmpl$23 = ["<div class=\"k2b-chat-composer__error\" role=\"alert\"><i class=\"ti ti-alert-circle\" aria-hidden=\"true\"></i>", "</div>"],
|
|
33
|
+
_tmpl$24 = ["<div class=\"k2b-chat-composer__row\">", "", "<div class=\"k2b-chat-composer__field\">", "<div class=\"k2b-chat-composer__field-tools\">", "", "", "</div></div>", "</div>"],
|
|
34
|
+
_tmpl$25 = ["<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>"],
|
|
35
|
+
_tmpl$26 = ["<button id=\"", "\" type=\"button\" role=\"option\" tabindex=\"-1\"", "><span class=\"k2b-chat-composer__emoji-glyph\" aria-hidden=\"true\">", "</span><strong>", "</strong>", "</button>"],
|
|
36
|
+
_tmpl$27 = ["<small>:", ":</small>"],
|
|
37
|
+
_tmpl$28 = "<i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i>",
|
|
38
|
+
_tmpl$29 = "<div class=\"k2b-chat-composer__command-placeholder\" aria-hidden=\"true\"><span></span><span><span></span><span></span></span></div>",
|
|
39
|
+
_tmpl$30 = ["<div class=\"k2b-chat-composer__command-group\" role=\"group\"", "><div class=\"k2b-chat-composer__command-heading\"", " role=\"presentation\"><span>", "</span>", "</div>", "", "</div>"],
|
|
40
|
+
_tmpl$31 = ["<span class=\"k2b-chat-composer__hint-text\">", "</span>"],
|
|
41
|
+
_tmpl$32 = ["<span class=\"k2b-chat-composer__dictation\"", "><i", " aria-hidden=\"true\"></i><span>", "</span></span>"],
|
|
42
|
+
_tmpl$33 = ["<button type=\"button\" class=\"k2b-chat-composer__hint-action\"", ">", "</button>"],
|
|
43
|
+
_tmpl$34 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-remove\"", "", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
|
|
44
|
+
_tmpl$35 = ["<div class=\"k2b-chat-composer__attachment\" role=\"listitem\"><div class=\"", "\">", "", "</div>", "</div>"],
|
|
45
|
+
_tmpl$36 = ["<img", ">"],
|
|
46
|
+
_tmpl$37 = ["<div class=\"k2b-chat-composer__attachment-identity\">", "", "</div>"],
|
|
47
|
+
_tmpl$38 = ["<a class=\"k2b-chat-composer__attachment-link\"", " target=\"_blank\" rel=\"noopener noreferrer\"", ">", "", "</a>"],
|
|
48
|
+
_tmpl$39 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-action\"", ">", "", "</button>"],
|
|
49
|
+
_tmpl$40 = ["<footer class=\"k2b-chat-composer__footer\">", "</footer>"],
|
|
50
|
+
_tmpl$41 = ["<div class=\"k2b-chat-composer__tools\">", "", "", "", "", "", "", "</div>"],
|
|
51
|
+
_tmpl$42 = ["<div class=\"k2b-chat-composer__submit\">", "", "", "", "", "</div>"],
|
|
52
|
+
_tmpl$43 = ["<span>", "</span>"],
|
|
53
|
+
_tmpl$44 = ["<div class=\"k2b-chat-composer__status-line\"", "><i aria-hidden=\"true\"", "></i><span>", "</span></div>"],
|
|
54
|
+
_tmpl$45 = ["<span class=\"k2b-sr-only\">", "</span>"];
|
|
54
55
|
import { batch, children, createEffect, createMemo, createSignal, createUniqueId, For, onCleanup, onMount, Show, untrack } from "solid-js";
|
|
55
56
|
import { Dropdown } from "../actions/Dropdown";
|
|
57
|
+
import { dialogHistorySettled, holdDialogHistory } from "../feedback/dialog-core";
|
|
56
58
|
import { Tooltip } from "../feedback/Tooltip";
|
|
57
59
|
import { replaceTextareaRange } from "../inputs/editor-dom";
|
|
58
60
|
import { completedEmojiShortcode, emojiInTone, emojiName, emojiShortcodeQuery, loadEmojiIndex, suggestEmoji } from "../inputs/emoji/emoji-index";
|
|
@@ -114,12 +116,40 @@ const isTouchOnly = () => typeof matchMedia === "function" && matchMedia(touchOn
|
|
|
114
116
|
const microphoneHoldMs = 500;
|
|
115
117
|
/** Keeps the field focused (and a phone's keyboard open) when a composer button is pressed with a mouse or finger. */
|
|
116
118
|
const keepFieldFocus = event => event.preventDefault();
|
|
119
|
+
/**
|
|
120
|
+
* Keeps one tap from reaching the page: its pointer, touch and mouse events stop at the window, and neither focus nor a
|
|
121
|
+
* click happens. A finger's tap ends with `touchend`, a scroll with `pointercancel`, a mouse's press with `click`.
|
|
122
|
+
*/
|
|
123
|
+
const swallowTap = down => {
|
|
124
|
+
const blocked = ["pointerup", "pointercancel", "touchstart", "touchend", "mousedown", "mouseup", "click", "contextmenu"];
|
|
125
|
+
const stop = () => {
|
|
126
|
+
window.removeEventListener("pointerdown", next, true);
|
|
127
|
+
for (const type of blocked) window.removeEventListener(type, block, true);
|
|
128
|
+
};
|
|
129
|
+
const block = event => {
|
|
130
|
+
event.stopPropagation();
|
|
131
|
+
if (event.type !== "pointercancel" && event.type !== "touchstart" && event.type !== "pointerup") event.preventDefault();
|
|
132
|
+
if (event.type === "click" || event.type === "touchend" || event.type === "pointercancel") stop();
|
|
133
|
+
};
|
|
134
|
+
// The next press is a new gesture, whatever became of this one.
|
|
135
|
+
const next = event => {
|
|
136
|
+
if (event !== down) stop();
|
|
137
|
+
};
|
|
138
|
+
down.stopPropagation();
|
|
139
|
+
down.preventDefault();
|
|
140
|
+
window.addEventListener("pointerdown", next, true);
|
|
141
|
+
for (const type of blocked) window.addEventListener(type, block, {
|
|
142
|
+
capture: true,
|
|
143
|
+
passive: false
|
|
144
|
+
});
|
|
145
|
+
};
|
|
117
146
|
const attachmentIcon = attachment => attachment.icon ?? (attachment.kind === "image" ? "ti ti-photo" : attachment.kind === "resource" ? "ti ti-link" : "ti ti-file");
|
|
118
147
|
const hasContent = items => items.some(item => item != null && typeof item !== "boolean" && item !== "");
|
|
119
148
|
export function ChatComposer(props) {
|
|
120
149
|
const accessory = children(() => props.accessory);
|
|
121
150
|
const hasAccessory = () => hasContent(accessory.toArray());
|
|
122
151
|
const hint = children(() => props.hint);
|
|
152
|
+
const footer = children(() => props.footerContent);
|
|
123
153
|
const messages = useUiMessages();
|
|
124
154
|
const markdownToolbarMessages = useMarkdownToolbarMessages();
|
|
125
155
|
const chatMessages = useChatMessages();
|
|
@@ -140,6 +170,7 @@ export function ChatComposer(props) {
|
|
|
140
170
|
const [closedAt, setClosedAt] = createSignal();
|
|
141
171
|
// Where the pending native edit starts; a selection replaced as a whole starts at its beginning.
|
|
142
172
|
let inputStart;
|
|
173
|
+
let inputEnd;
|
|
143
174
|
const [commandStatus, setCommandStatus] = createSignal();
|
|
144
175
|
const [announcement, setAnnouncement] = createSignal();
|
|
145
176
|
let statusTimer;
|
|
@@ -158,6 +189,7 @@ export function ChatComposer(props) {
|
|
|
158
189
|
});
|
|
159
190
|
const [addingFiles, setAddingFiles] = createSignal(false);
|
|
160
191
|
const [submitting, setSubmitting] = createSignal(false);
|
|
192
|
+
let shellRef;
|
|
161
193
|
let composerRef;
|
|
162
194
|
let textareaRef;
|
|
163
195
|
let fileInputRef;
|
|
@@ -185,6 +217,45 @@ export function ChatComposer(props) {
|
|
|
185
217
|
const [searching, setSearching] = createSignal(false);
|
|
186
218
|
const [searchError, setSearchError] = createSignal(false);
|
|
187
219
|
const [executing, setExecuting] = createSignal(false);
|
|
220
|
+
const [modelOpen, setModelOpen] = createSignal();
|
|
221
|
+
const [choosingModel, setChoosingModel] = createSignal(false);
|
|
222
|
+
let resolveModel;
|
|
223
|
+
const finishModelSelection = id => {
|
|
224
|
+
const resolve = resolveModel;
|
|
225
|
+
resolveModel = undefined;
|
|
226
|
+
if (choosingModel()) {
|
|
227
|
+
setModelOpen(false);
|
|
228
|
+
// Let the controlled close reach Dropdown before returning normal clicks to its own state.
|
|
229
|
+
queueMicrotask(() => {
|
|
230
|
+
if (!choosingModel()) setModelOpen(undefined);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
setChoosingModel(false);
|
|
234
|
+
resolve?.(id);
|
|
235
|
+
};
|
|
236
|
+
const blockedBesidesCommand = () => Boolean(props.disabled || stopping() || state() === "submitting" || addingFiles() || submitting());
|
|
237
|
+
const usableModelControl = () => !conversation() && !footer() && !blockedBesidesCommand() && !running() && Boolean(props.models?.length && props.onModelChange);
|
|
238
|
+
const openModelSelection = () => {
|
|
239
|
+
if (!usableModelControl()) return Promise.resolve(null);
|
|
240
|
+
finishModelSelection(null);
|
|
241
|
+
return new Promise(resolve => {
|
|
242
|
+
resolveModel = resolve;
|
|
243
|
+
setChoosingModel(true);
|
|
244
|
+
setModelOpen(true);
|
|
245
|
+
queueMicrotask(() => {
|
|
246
|
+
if (!choosingModel() || !modelOpen()) return;
|
|
247
|
+
// Start on the current model, as a click on the chip would show it checked.
|
|
248
|
+
const menu = composerRef?.querySelector(".k2b-chat-composer__model");
|
|
249
|
+
(menu?.querySelector('[role="menuitemradio"][aria-checked="true"]:not(:disabled)') ?? menu?.querySelector('[role="menuitemradio"]:not(:disabled)'))?.focus();
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
createEffect(() => {
|
|
254
|
+
if (!usableModelControl()) finishModelSelection(null);
|
|
255
|
+
});
|
|
256
|
+
onCleanup(() => finishModelSelection(null));
|
|
257
|
+
const [commandOpening, setCommandOpening] = createSignal(0);
|
|
258
|
+
let retrySearch = false;
|
|
188
259
|
let highlightRef;
|
|
189
260
|
let commandListRef;
|
|
190
261
|
const mentions = () => props.mentions ?? [];
|
|
@@ -218,6 +289,12 @@ export function ChatComposer(props) {
|
|
|
218
289
|
const token = caretCommandToken();
|
|
219
290
|
return dismissed() || composing() || token?.start === closedAt() ? null : token;
|
|
220
291
|
});
|
|
292
|
+
const openingStart = createMemo(() => commandQuery()?.start);
|
|
293
|
+
createEffect(() => {
|
|
294
|
+
props.draftKey;
|
|
295
|
+
const start = openingStart();
|
|
296
|
+
if (start !== undefined) setCommandOpening(opening => opening + 1);
|
|
297
|
+
});
|
|
221
298
|
const parsedCommandQuery = createMemo(() => parseChatCommandQuery(commandQuery()?.query ?? "", props.commandScopes ?? []));
|
|
222
299
|
const currentCommandScope = createMemo(() => parsedCommandQuery().scope?.id);
|
|
223
300
|
createEffect(() => {
|
|
@@ -246,20 +323,45 @@ export function ChatComposer(props) {
|
|
|
246
323
|
setCommandMoved(false);
|
|
247
324
|
});
|
|
248
325
|
const commandsOpen = () => Boolean(!emojiOpen() && commandQuery() && (localCommands().length || props.searchCommands));
|
|
326
|
+
const commandSheetHeld = createMemo(() => commandsOpen() && isTouchOnly());
|
|
327
|
+
createEffect(() => {
|
|
328
|
+
if (!commandSheetHeld()) return;
|
|
329
|
+
onCleanup(holdDialogHistory(() => setClosedAt(commandQuery()?.start)));
|
|
330
|
+
});
|
|
249
331
|
const suggestionsOpen = () => commandsOpen() || emojiOpen();
|
|
250
332
|
createEffect(() => {
|
|
251
333
|
if (!suggestionsOpen()) return;
|
|
252
334
|
let disposed = false;
|
|
253
335
|
const measure = () => {
|
|
254
336
|
if (disposed || !commandListRef) return;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
337
|
+
const accessory = commandListRef.parentElement;
|
|
338
|
+
const viewportTop = window.visualViewport?.offsetTop ?? 0;
|
|
339
|
+
let top = viewportTop;
|
|
340
|
+
// The column a phone sheet spans: the nearest ancestor that clips sideways, or the page.
|
|
341
|
+
let column;
|
|
342
|
+
for (let parent = accessory.parentElement; parent; parent = parent.parentElement) {
|
|
343
|
+
const style = window.getComputedStyle(parent);
|
|
344
|
+
if (/(auto|scroll|hidden|clip)/.test(style.overflowY)) {
|
|
258
345
|
top = Math.max(top, parent.getBoundingClientRect().top);
|
|
259
346
|
}
|
|
347
|
+
if (!column && /(auto|scroll|hidden|clip)/.test(style.overflowX)) {
|
|
348
|
+
const left = parent.getBoundingClientRect().left + parent.clientLeft;
|
|
349
|
+
column = {
|
|
350
|
+
left,
|
|
351
|
+
right: left + parent.clientWidth
|
|
352
|
+
};
|
|
353
|
+
}
|
|
260
354
|
}
|
|
261
|
-
const
|
|
355
|
+
const page = document.documentElement.clientWidth;
|
|
356
|
+
const left = Math.max(0, column?.left ?? 0);
|
|
357
|
+
const right = Math.min(page, column?.right ?? page);
|
|
358
|
+
const slot = accessory.parentElement.getBoundingClientRect();
|
|
359
|
+
const bottom = accessory.getBoundingClientRect().bottom;
|
|
262
360
|
commandListRef.style.setProperty("--k2b-chat-command-space", `${Math.max(40, bottom - top - 8)}px`);
|
|
361
|
+
// Only a list that reaches the screen's top edge keeps clear of a notch or the status bar.
|
|
362
|
+
commandListRef.style.setProperty("--k2b-chat-command-safe-top", top === viewportTop ? "env(safe-area-inset-top, 0px)" : "0px");
|
|
363
|
+
accessory.style.setProperty("--k2b-chat-command-reach-left", `${Math.max(0, slot.left - left)}px`);
|
|
364
|
+
accessory.style.setProperty("--k2b-chat-command-reach-right", `${Math.max(0, right - slot.right)}px`);
|
|
263
365
|
};
|
|
264
366
|
queueMicrotask(measure);
|
|
265
367
|
window.addEventListener("resize", measure);
|
|
@@ -272,6 +374,20 @@ export function ChatComposer(props) {
|
|
|
272
374
|
window.visualViewport?.removeEventListener("resize", measure);
|
|
273
375
|
});
|
|
274
376
|
});
|
|
377
|
+
// A press outside the command list and the field closes the list, as Escape does; the text stays. With a mouse or a
|
|
378
|
+
// trackpad the press then acts as usual. On a touch-only device a tap outside the composer closes only the list: it
|
|
379
|
+
// reaches nothing beneath, and the field keeps focus, so the keyboard stays open.
|
|
380
|
+
createEffect(() => {
|
|
381
|
+
if (!commandsOpen()) return;
|
|
382
|
+
const onPointerDown = event => {
|
|
383
|
+
const target = event.target;
|
|
384
|
+
if (!(target instanceof Node) || commandListRef?.contains(target) || textareaRef?.parentElement?.contains(target)) return;
|
|
385
|
+
setClosedAt(commandQuery()?.start);
|
|
386
|
+
if (isTouchOnly() && !shellRef?.contains(target)) swallowTap(event);
|
|
387
|
+
};
|
|
388
|
+
window.addEventListener("pointerdown", onPointerDown, true);
|
|
389
|
+
onCleanup(() => window.removeEventListener("pointerdown", onPointerDown, true));
|
|
390
|
+
});
|
|
275
391
|
createEffect(() => {
|
|
276
392
|
props.draftKey;
|
|
277
393
|
const token = commandQuery();
|
|
@@ -280,12 +396,17 @@ export function ChatComposer(props) {
|
|
|
280
396
|
setSearching(false);
|
|
281
397
|
return;
|
|
282
398
|
}
|
|
399
|
+
running();
|
|
283
400
|
const parsed = parsedCommandQuery();
|
|
401
|
+
const opening = commandOpening();
|
|
284
402
|
const abort = new AbortController();
|
|
285
403
|
setSearching(true);
|
|
404
|
+
const delay = retrySearch ? 0 : 120;
|
|
405
|
+
retrySearch = false;
|
|
286
406
|
const timer = setTimeout(() => {
|
|
287
407
|
Promise.resolve().then(() => props.searchCommands(parsed.query, abort.signal, {
|
|
288
|
-
scope: parsed.scope?.id
|
|
408
|
+
scope: parsed.scope?.id,
|
|
409
|
+
opening
|
|
289
410
|
})).then(results => {
|
|
290
411
|
if (!abort.signal.aborted) {
|
|
291
412
|
batch(() => {
|
|
@@ -303,7 +424,7 @@ export function ChatComposer(props) {
|
|
|
303
424
|
}).finally(() => {
|
|
304
425
|
if (!abort.signal.aborted) setSearching(false);
|
|
305
426
|
});
|
|
306
|
-
},
|
|
427
|
+
}, delay);
|
|
307
428
|
onCleanup(() => {
|
|
308
429
|
clearTimeout(timer);
|
|
309
430
|
abort.abort();
|
|
@@ -362,6 +483,7 @@ export function ChatComposer(props) {
|
|
|
362
483
|
untrack(() => {
|
|
363
484
|
history.length = 0;
|
|
364
485
|
historyIndex = -1;
|
|
486
|
+
finishModelSelection(null);
|
|
365
487
|
setDismissed(true);
|
|
366
488
|
setClosedAt(undefined);
|
|
367
489
|
setSearchResults([]);
|
|
@@ -387,6 +509,13 @@ export function ChatComposer(props) {
|
|
|
387
509
|
};
|
|
388
510
|
const edit = (value, nextMentions = reconcileChatMentions(props.value, value, mentions())) => {
|
|
389
511
|
if (commandStatus()?.tone === "error") showCommandStatus();
|
|
512
|
+
// Replacing `/` can leave its position and query identical, but starts a new opening.
|
|
513
|
+
if (inputStart !== undefined && inputEnd !== undefined && props.value.slice(inputStart, inputEnd).includes("/")) {
|
|
514
|
+
setCommandOpening(opening => opening + 1);
|
|
515
|
+
setSearchResults([]);
|
|
516
|
+
setSearchResultsQuery(undefined);
|
|
517
|
+
setCommandMoved(false);
|
|
518
|
+
}
|
|
390
519
|
// An edit that starts at or before the closed `/` (select all, then type `/`) replaces it; the new `/` may open again.
|
|
391
520
|
const closed = closedAt();
|
|
392
521
|
if (closed !== undefined) {
|
|
@@ -395,6 +524,7 @@ export function ChatComposer(props) {
|
|
|
395
524
|
if (Math.min(same, inputStart ?? same) <= closed) setClosedAt(undefined);
|
|
396
525
|
}
|
|
397
526
|
inputStart = undefined;
|
|
527
|
+
inputEnd = undefined;
|
|
398
528
|
record();
|
|
399
529
|
props.onValueChange(value);
|
|
400
530
|
props.onMentionsChange?.(nextMentions);
|
|
@@ -438,7 +568,9 @@ export function ChatComposer(props) {
|
|
|
438
568
|
/** The conversation field stays editable while a message is sent, so it keeps the focus and a phone its keyboard. */
|
|
439
569
|
const editBlocked = () => conversation() ? busy() : blocked();
|
|
440
570
|
const hasDraft = () => Boolean(props.value.trim() || !running() && attachments().length > 0);
|
|
441
|
-
|
|
571
|
+
/** The draft may go out now, apart from a submission that is already on its way. */
|
|
572
|
+
const submittable = () => !busy() && hasDraft() && !(running() && runningSubmitIntent() === "steer" && mentions().length);
|
|
573
|
+
const canSubmit = () => !submitting() && submittable();
|
|
442
574
|
const canSelectFiles = () => Boolean(props.fileSelection && !props.fileSelection.disabled && !running() && !blocked());
|
|
443
575
|
const hasAddMenu = () => Boolean(props.fileSelection || props.menuActions?.length);
|
|
444
576
|
const hasContextUsage = () => {
|
|
@@ -558,18 +690,26 @@ export function ChatComposer(props) {
|
|
|
558
690
|
};
|
|
559
691
|
const submit = async () => {
|
|
560
692
|
if (!canSubmit()) return;
|
|
561
|
-
const
|
|
562
|
-
const previousValue = props.value;
|
|
563
|
-
const previousAttachments = attachments();
|
|
564
|
-
const previousMentions = mentions();
|
|
565
|
-
const input = {
|
|
566
|
-
intent,
|
|
567
|
-
text: previousValue,
|
|
568
|
-
mentions: previousMentions,
|
|
569
|
-
attachments: intent !== "steer" ? previousAttachments : []
|
|
570
|
-
};
|
|
693
|
+
const key = props.draftKey;
|
|
571
694
|
setSubmitting(true);
|
|
572
695
|
try {
|
|
696
|
+
if (isTouchOnly()) {
|
|
697
|
+
if (commandSheetHeld()) setClosedAt(commandQuery()?.start);
|
|
698
|
+
// The sheet's Back entry leaves first, so a submit handler that navigates finds the history settled.
|
|
699
|
+
await dialogHistorySettled();
|
|
700
|
+
// A draft that another one replaced, or that may no longer go out, is not sent and keeps its text.
|
|
701
|
+
if (disposed || props.draftKey !== key || !submittable()) return;
|
|
702
|
+
}
|
|
703
|
+
const intent = running() ? runningSubmitIntent() : "send";
|
|
704
|
+
const previousValue = props.value;
|
|
705
|
+
const previousAttachments = attachments();
|
|
706
|
+
const previousMentions = mentions();
|
|
707
|
+
const input = {
|
|
708
|
+
intent,
|
|
709
|
+
text: previousValue,
|
|
710
|
+
mentions: previousMentions,
|
|
711
|
+
attachments: intent !== "steer" ? previousAttachments : []
|
|
712
|
+
};
|
|
573
713
|
await runChatSubmission({
|
|
574
714
|
clear: () => {
|
|
575
715
|
props.onValueChange("");
|
|
@@ -612,6 +752,7 @@ export function ChatComposer(props) {
|
|
|
612
752
|
};
|
|
613
753
|
const executeCommand = async (command, tab = false) => {
|
|
614
754
|
const token = commandQuery();
|
|
755
|
+
const heldHistory = commandSheetHeld();
|
|
615
756
|
if (!token || blocked()) return;
|
|
616
757
|
if (command.disabled || command.reason) {
|
|
617
758
|
// A new object each time, so choosing the same row again inserts and announces its reason again.
|
|
@@ -620,6 +761,11 @@ export function ChatComposer(props) {
|
|
|
620
761
|
} : undefined);
|
|
621
762
|
return;
|
|
622
763
|
}
|
|
764
|
+
if (command.searchAgain) {
|
|
765
|
+
retrySearch = true;
|
|
766
|
+
setCommandOpening(opening => opening + 1);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
623
769
|
if (command.scope && (tab || !command.action && !command.mention) && narrowCommand(command)) return;
|
|
624
770
|
const previous = snapshot();
|
|
625
771
|
const key = props.draftKey;
|
|
@@ -655,12 +801,19 @@ export function ChatComposer(props) {
|
|
|
655
801
|
text: command.busyLabel
|
|
656
802
|
} : undefined);
|
|
657
803
|
try {
|
|
804
|
+
// The sheet's Back entry leaves first, so an action that navigates or opens a dialog finds the history settled.
|
|
805
|
+
if (heldHistory && command.action) {
|
|
806
|
+
await dialogHistorySettled();
|
|
807
|
+
// Another draft or no composer any more: the command does not run against it.
|
|
808
|
+
if (disposed || props.draftKey !== key) return;
|
|
809
|
+
}
|
|
658
810
|
const result = await command.action?.({
|
|
659
811
|
setValue: value => edit(value),
|
|
660
812
|
submit: () => {
|
|
661
813
|
submitRequested = true;
|
|
662
814
|
},
|
|
663
|
-
focus
|
|
815
|
+
focus,
|
|
816
|
+
openModelSelection
|
|
664
817
|
});
|
|
665
818
|
if (result === "cancelled") {
|
|
666
819
|
submitRequested = false;
|
|
@@ -1216,14 +1369,14 @@ export function ChatComposer(props) {
|
|
|
1216
1369
|
const renderCommandRow = command => {
|
|
1217
1370
|
const highlight = () => commandRowMap().get(command)?.highlight;
|
|
1218
1371
|
const title = () => command.label ?? command.name;
|
|
1219
|
-
return _$ssr(_tmpl$
|
|
1372
|
+
return _$ssr(_tmpl$13, _$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
1373
|
get when() {
|
|
1221
1374
|
return highlight();
|
|
1222
1375
|
},
|
|
1223
1376
|
get fallback() {
|
|
1224
1377
|
return title();
|
|
1225
1378
|
},
|
|
1226
|
-
children: range => [title().slice(0, range()[0]), _$ssr(_tmpl$
|
|
1379
|
+
children: range => [title().slice(0, range()[0]), _$ssr(_tmpl$14, _$escape(title().slice(range()[0], range()[1]))), title().slice(range()[1])]
|
|
1227
1380
|
})), _$escape(_$createComponent(Show, {
|
|
1228
1381
|
get when() {
|
|
1229
1382
|
return command.reason ?? command.description;
|
|
@@ -1231,27 +1384,34 @@ export function ChatComposer(props) {
|
|
|
1231
1384
|
get children() {
|
|
1232
1385
|
return _$ssr(_tmpl$11, _$ssrAttribute("id", command.reason ? `${_$escape(commandOptionId(command), true)}-reason` : _$escape(undefined, true), false), _$escape(command.reason ?? command.description));
|
|
1233
1386
|
}
|
|
1387
|
+
})), _$escape(_$createComponent(Show, {
|
|
1388
|
+
get when() {
|
|
1389
|
+
return command.selected;
|
|
1390
|
+
},
|
|
1391
|
+
get children() {
|
|
1392
|
+
return _$ssr(_tmpl$12, _$escape(chatMessages().commandSelected));
|
|
1393
|
+
}
|
|
1234
1394
|
})));
|
|
1235
1395
|
};
|
|
1236
|
-
return _$ssr(_tmpl$
|
|
1396
|
+
return _$ssr(_tmpl$25, _$escape(_$createComponent(Show, {
|
|
1237
1397
|
get when() {
|
|
1238
1398
|
return suggestionsOpen() || hasAccessory();
|
|
1239
1399
|
},
|
|
1240
1400
|
get children() {
|
|
1241
|
-
return _$ssr(_tmpl$
|
|
1401
|
+
return _$ssr(_tmpl$20, _$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, {
|
|
1242
1402
|
get when() {
|
|
1243
1403
|
return emojiOpen();
|
|
1244
1404
|
},
|
|
1245
1405
|
get children() {
|
|
1246
|
-
return _$ssr(_tmpl$
|
|
1406
|
+
return _$ssr(_tmpl$15, _$ssrAttribute("id", _$escape(commandListId, true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().emojiSuggestions, true), false), _$escape(_$createComponent(For, {
|
|
1247
1407
|
get each() {
|
|
1248
1408
|
return emojiMatches();
|
|
1249
1409
|
},
|
|
1250
|
-
children: (entry, index) => _$ssr(_tmpl$
|
|
1410
|
+
children: (entry, index) => _$ssr(_tmpl$26, `${_$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, {
|
|
1251
1411
|
get when() {
|
|
1252
1412
|
return entry.shortcodes[0];
|
|
1253
1413
|
},
|
|
1254
|
-
children: code => _$ssr(_tmpl$
|
|
1414
|
+
children: code => _$ssr(_tmpl$27, _$escape(code()))
|
|
1255
1415
|
})))
|
|
1256
1416
|
})));
|
|
1257
1417
|
}
|
|
@@ -1260,7 +1420,7 @@ export function ChatComposer(props) {
|
|
|
1260
1420
|
return commandsOpen();
|
|
1261
1421
|
},
|
|
1262
1422
|
get children() {
|
|
1263
|
-
return _$ssr(_tmpl$
|
|
1423
|
+
return _$ssr(_tmpl$19, _$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, {
|
|
1264
1424
|
get each() {
|
|
1265
1425
|
return commandModel().groups.map(commandGroupKey);
|
|
1266
1426
|
},
|
|
@@ -1279,12 +1439,12 @@ export function ChatComposer(props) {
|
|
|
1279
1439
|
});
|
|
1280
1440
|
},
|
|
1281
1441
|
get children() {
|
|
1282
|
-
return _$ssr(_tmpl$
|
|
1442
|
+
return _$ssr(_tmpl$30, _$ssrAttribute("aria-labelledby", _$escape(headingId(), true), false), _$ssrAttribute("id", _$escape(headingId(), true), false), _$escape(group()?.scopeTitle ?? group()?.section?.label), _$escape(_$createComponent(Show, {
|
|
1283
1443
|
get when() {
|
|
1284
1444
|
return group()?.loading;
|
|
1285
1445
|
},
|
|
1286
1446
|
get children() {
|
|
1287
|
-
return _$ssr(_tmpl$
|
|
1447
|
+
return _$ssr(_tmpl$28);
|
|
1288
1448
|
}
|
|
1289
1449
|
})), _$escape(_$createComponent(For, {
|
|
1290
1450
|
get each() {
|
|
@@ -1296,7 +1456,7 @@ export function ChatComposer(props) {
|
|
|
1296
1456
|
return group()?.placeholder;
|
|
1297
1457
|
},
|
|
1298
1458
|
get children() {
|
|
1299
|
-
return _$ssr(_tmpl$
|
|
1459
|
+
return _$ssr(_tmpl$29);
|
|
1300
1460
|
}
|
|
1301
1461
|
})));
|
|
1302
1462
|
}
|
|
@@ -1307,21 +1467,21 @@ export function ChatComposer(props) {
|
|
|
1307
1467
|
return _$memo(() => !!(searching() && commandMatches().length === 0))() && !commandModel().groups.some(group => group.section || group.scopeTitle);
|
|
1308
1468
|
},
|
|
1309
1469
|
get children() {
|
|
1310
|
-
return _$ssr(_tmpl$
|
|
1470
|
+
return _$ssr(_tmpl$16, _$escape(messages().loading));
|
|
1311
1471
|
}
|
|
1312
1472
|
})), _$escape(_$createComponent(Show, {
|
|
1313
1473
|
get when() {
|
|
1314
1474
|
return searchError();
|
|
1315
1475
|
},
|
|
1316
1476
|
get children() {
|
|
1317
|
-
return _$ssr(_tmpl$
|
|
1477
|
+
return _$ssr(_tmpl$17, _$escape(messages().error));
|
|
1318
1478
|
}
|
|
1319
1479
|
})), _$escape(_$createComponent(Show, {
|
|
1320
1480
|
get when() {
|
|
1321
1481
|
return _$memo(() => !!(!searching() && !searchError()))() && commandMatches().length === 0;
|
|
1322
1482
|
},
|
|
1323
1483
|
get children() {
|
|
1324
|
-
return _$ssr(_tmpl$
|
|
1484
|
+
return _$ssr(_tmpl$18, !parsedCommandQuery().query.trim() ? _$escape(messages().noResults) : _$escape(chatMessages().commandsNothingFound({
|
|
1325
1485
|
query: parsedCommandQuery().query.trim()
|
|
1326
1486
|
})));
|
|
1327
1487
|
}
|
|
@@ -1334,18 +1494,18 @@ export function ChatComposer(props) {
|
|
|
1334
1494
|
return showHint();
|
|
1335
1495
|
},
|
|
1336
1496
|
get children() {
|
|
1337
|
-
return _$ssr(_tmpl$
|
|
1497
|
+
return _$ssr(_tmpl$21, _$escape(_$createComponent(Show, {
|
|
1338
1498
|
get when() {
|
|
1339
1499
|
return dictationStatus();
|
|
1340
1500
|
},
|
|
1341
1501
|
get fallback() {
|
|
1342
|
-
return _$ssr(_tmpl$
|
|
1502
|
+
return _$ssr(_tmpl$31, _$escape(hint()));
|
|
1343
1503
|
},
|
|
1344
|
-
children: status => [_$ssr(_tmpl$
|
|
1504
|
+
children: status => [_$ssr(_tmpl$32, _$ssrAttribute("data-state", _$escape(dictation() ?? undefined, true), false), _$ssrAttribute("class", _$escape(status().icon, true), false), _$escape(status().text)), _$createComponent(Show, {
|
|
1345
1505
|
get when() {
|
|
1346
1506
|
return _$memo(() => dictation() === "refined")() ? props.microphone?.onRestoreOriginal : undefined;
|
|
1347
1507
|
},
|
|
1348
|
-
children: restore => _$ssr(_tmpl$
|
|
1508
|
+
children: restore => _$ssr(_tmpl$33, _$ssrAttribute("disabled", microphoneDisabled(), true), _$escape(chatMessages().restoreOriginal))
|
|
1349
1509
|
})]
|
|
1350
1510
|
})));
|
|
1351
1511
|
}
|
|
@@ -1354,16 +1514,16 @@ export function ChatComposer(props) {
|
|
|
1354
1514
|
return attachments().length > 0;
|
|
1355
1515
|
},
|
|
1356
1516
|
get children() {
|
|
1357
|
-
return _$ssr(_tmpl$
|
|
1517
|
+
return _$ssr(_tmpl$22, _$ssrAttribute("aria-label", _$escape(chatMessages().attachments, true), false), _$escape(_$createComponent(For, {
|
|
1358
1518
|
get each() {
|
|
1359
1519
|
return attachments();
|
|
1360
1520
|
},
|
|
1361
|
-
children: attachment => _$ssr(_tmpl$
|
|
1521
|
+
children: attachment => _$ssr(_tmpl$35, `k2b-chat-composer__attachment-content ${Boolean(attachment.action) ? "k2b-chat-composer__attachment-content--action" : ""}`, _$escape(_$createComponent(Show, {
|
|
1362
1522
|
get when() {
|
|
1363
1523
|
return attachment.href;
|
|
1364
1524
|
},
|
|
1365
1525
|
get fallback() {
|
|
1366
|
-
return _$ssr(_tmpl$
|
|
1526
|
+
return _$ssr(_tmpl$37, _$escape(_$createComponent(Show, {
|
|
1367
1527
|
get when() {
|
|
1368
1528
|
return _$memo(() => attachment.kind === "image")() && attachment.previewUrl;
|
|
1369
1529
|
},
|
|
@@ -1371,11 +1531,11 @@ export function ChatComposer(props) {
|
|
|
1371
1531
|
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
|
|
1372
1532
|
},
|
|
1373
1533
|
get children() {
|
|
1374
|
-
return _$ssr(_tmpl$
|
|
1534
|
+
return _$ssr(_tmpl$36, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
|
|
1375
1535
|
}
|
|
1376
1536
|
})), _$escape(renderAttachmentCopy(attachment)));
|
|
1377
1537
|
},
|
|
1378
|
-
children: href => _$ssr(_tmpl$
|
|
1538
|
+
children: href => _$ssr(_tmpl$38, _$ssrAttribute("href", _$escape(href(), true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().openInNewTab({
|
|
1379
1539
|
name: attachment.name
|
|
1380
1540
|
}), true), false), _$escape(_$createComponent(Show, {
|
|
1381
1541
|
get when() {
|
|
@@ -1385,14 +1545,14 @@ export function ChatComposer(props) {
|
|
|
1385
1545
|
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
|
|
1386
1546
|
},
|
|
1387
1547
|
get children() {
|
|
1388
|
-
return _$ssr(_tmpl$
|
|
1548
|
+
return _$ssr(_tmpl$36, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
|
|
1389
1549
|
}
|
|
1390
1550
|
})), _$escape(renderAttachmentCopy(attachment)))
|
|
1391
1551
|
})), _$escape(_$createComponent(Show, {
|
|
1392
1552
|
get when() {
|
|
1393
1553
|
return attachment.action;
|
|
1394
1554
|
},
|
|
1395
|
-
children: action => _$ssr(_tmpl$
|
|
1555
|
+
children: action => _$ssr(_tmpl$39, _$ssrAttribute("disabled", blocked() || action().disabled, true), _$escape(_$createComponent(Show, {
|
|
1396
1556
|
get when() {
|
|
1397
1557
|
return action().icon;
|
|
1398
1558
|
},
|
|
@@ -1403,7 +1563,7 @@ export function ChatComposer(props) {
|
|
|
1403
1563
|
return props.onAttachmentsChange;
|
|
1404
1564
|
},
|
|
1405
1565
|
get children() {
|
|
1406
|
-
return _$ssr(_tmpl$
|
|
1566
|
+
return _$ssr(_tmpl$34, _$ssrAttribute("aria-label", _$escape(selectMessages().removeNamed({
|
|
1407
1567
|
name: attachment.name
|
|
1408
1568
|
}), true), false), _$ssrAttribute("disabled", blocked(), true));
|
|
1409
1569
|
}
|
|
@@ -1420,14 +1580,14 @@ export function ChatComposer(props) {
|
|
|
1420
1580
|
return props.error;
|
|
1421
1581
|
},
|
|
1422
1582
|
get children() {
|
|
1423
|
-
return _$ssr(_tmpl$
|
|
1583
|
+
return _$ssr(_tmpl$23, _$escape(props.error));
|
|
1424
1584
|
}
|
|
1425
|
-
}), formatRow(), _$ssr(_tmpl$
|
|
1585
|
+
}), formatRow(), _$ssr(_tmpl$40, _$escape(_$createComponent(Show, {
|
|
1426
1586
|
get when() {
|
|
1427
|
-
return
|
|
1587
|
+
return footer();
|
|
1428
1588
|
},
|
|
1429
1589
|
get fallback() {
|
|
1430
|
-
return [_$ssr(_tmpl$
|
|
1590
|
+
return [_$ssr(_tmpl$41, _$escape(props.footerTools), _$escape(_$createComponent(Show, {
|
|
1431
1591
|
get when() {
|
|
1432
1592
|
return hasAddMenu();
|
|
1433
1593
|
},
|
|
@@ -1459,16 +1619,28 @@ export function ChatComposer(props) {
|
|
|
1459
1619
|
image: model.image
|
|
1460
1620
|
}));
|
|
1461
1621
|
},
|
|
1622
|
+
get open() {
|
|
1623
|
+
return modelOpen();
|
|
1624
|
+
},
|
|
1625
|
+
onOpenChange: open => {
|
|
1626
|
+
if (!choosingModel()) return;
|
|
1627
|
+
setModelOpen(open);
|
|
1628
|
+
// Dropdown closes before committing the choice; let onValueChange settle it first.
|
|
1629
|
+
if (!open) queueMicrotask(() => {
|
|
1630
|
+
if (!modelOpen()) finishModelSelection(null);
|
|
1631
|
+
});
|
|
1632
|
+
},
|
|
1462
1633
|
get disabled() {
|
|
1463
|
-
return blocked() || running() || !props.onModelChange;
|
|
1634
|
+
return (choosingModel() ? blockedBesidesCommand() : blocked()) || running() || !props.onModelChange;
|
|
1464
1635
|
},
|
|
1465
1636
|
onValueChange: modelId => {
|
|
1466
1637
|
props.onModelChange?.(modelId);
|
|
1638
|
+
finishModelSelection(modelId);
|
|
1467
1639
|
queueMicrotask(focus);
|
|
1468
1640
|
}
|
|
1469
1641
|
});
|
|
1470
1642
|
}
|
|
1471
|
-
})), _$escape(props.modelDetails)), _$ssr(_tmpl$
|
|
1643
|
+
})), _$escape(props.modelDetails)), _$ssr(_tmpl$42, _$escape(_$createComponent(For, {
|
|
1472
1644
|
get each() {
|
|
1473
1645
|
return props.contextActions;
|
|
1474
1646
|
},
|
|
@@ -1509,7 +1681,9 @@ export function ChatComposer(props) {
|
|
|
1509
1681
|
}))
|
|
1510
1682
|
})), _$escape(props.submitTools), _$escape(microphoneControl()), _$escape(sendControl()))];
|
|
1511
1683
|
},
|
|
1512
|
-
children
|
|
1684
|
+
get children() {
|
|
1685
|
+
return footer();
|
|
1686
|
+
}
|
|
1513
1687
|
})))];
|
|
1514
1688
|
},
|
|
1515
1689
|
get children() {
|
|
@@ -1518,9 +1692,9 @@ export function ChatComposer(props) {
|
|
|
1518
1692
|
return props.error;
|
|
1519
1693
|
},
|
|
1520
1694
|
get children() {
|
|
1521
|
-
return _$ssr(_tmpl$
|
|
1695
|
+
return _$ssr(_tmpl$23, _$escape(props.error));
|
|
1522
1696
|
}
|
|
1523
|
-
}), formatRow(), _$ssr(_tmpl$
|
|
1697
|
+
}), formatRow(), _$ssr(_tmpl$24, _$escape(attachControl()), _$escape(fileInput()), _$escape(field()), _$escape(formatToggle()), _$escape(emojiButton()), _$escape(microphoneControl()), _$escape(sendControl()))];
|
|
1524
1698
|
}
|
|
1525
1699
|
})), _$escape(_$createComponent(Show, {
|
|
1526
1700
|
get when() {
|
|
@@ -1546,18 +1720,18 @@ export function ChatComposer(props) {
|
|
|
1546
1720
|
return suggestionAnnouncement();
|
|
1547
1721
|
},
|
|
1548
1722
|
keyed: true,
|
|
1549
|
-
children: announced => _$ssr(_tmpl$
|
|
1723
|
+
children: announced => _$ssr(_tmpl$43, _$escape(announced.text))
|
|
1550
1724
|
})), _$escape(_$createComponent(Show, {
|
|
1551
1725
|
get when() {
|
|
1552
1726
|
return _$memo(() => !!!suggestionsOpen())() && commandStatus();
|
|
1553
1727
|
},
|
|
1554
|
-
children: status => _$ssr(_tmpl$
|
|
1728
|
+
children: status => _$ssr(_tmpl$44, _$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
1729
|
})), _$escape(_$createComponent(Show, {
|
|
1556
1730
|
get when() {
|
|
1557
1731
|
return _$memo(() => !!suggestionsOpen())() && announcement();
|
|
1558
1732
|
},
|
|
1559
1733
|
keyed: true,
|
|
1560
|
-
children: announced => _$ssr(_tmpl$
|
|
1734
|
+
children: announced => _$ssr(_tmpl$45, _$escape(announced.text))
|
|
1561
1735
|
})));
|
|
1562
1736
|
}
|
|
1563
1737
|
//# sourceMappingURL=ChatComposer.js.map
|