@k2b/ui 0.17.0 → 0.19.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 +3 -2
- package/dist/browser/actions/ContextMenu.js +3 -1
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/Dropdown.js +91 -46
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +4 -1
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +1311 -565
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/ChatPrimitives.js +9 -6
- package/dist/browser/chat/ChatPrimitives.js.map +1 -1
- package/dist/browser/chat/chat-behavior.js +9 -0
- package/dist/browser/chat/chat-behavior.js.map +1 -1
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/chat/types.js.map +1 -1
- package/dist/browser/content/Calendar.js +579 -533
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/FileView.js +62 -36
- package/dist/browser/content/FileView.js.map +1 -1
- package/dist/browser/content/Lightbox.js +76 -40
- package/dist/browser/content/Lightbox.js.map +1 -1
- package/dist/browser/content/MarkdownView.js +9 -3
- package/dist/browser/content/MarkdownView.js.map +1 -1
- package/dist/browser/content/PdfPreview.js +146 -79
- package/dist/browser/content/PdfPreview.js.map +1 -1
- package/dist/browser/content/Timeline.js +1038 -0
- package/dist/browser/content/Timeline.js.map +1 -0
- package/dist/browser/content/VideoPlayer.js +299 -0
- package/dist/browser/content/VideoPlayer.js.map +1 -0
- package/dist/browser/content/chart-inspection.js +7 -2
- package/dist/browser/content/chart-inspection.js.map +1 -1
- package/dist/browser/content/file-view-preview.js +2 -2
- package/dist/browser/content/file-view-preview.js.map +1 -1
- package/dist/browser/content/index.js +3 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/content/markdown-links.js +178 -0
- package/dist/browser/content/markdown-links.js.map +1 -0
- package/dist/browser/content/timeline-model.js +579 -0
- package/dist/browser/content/timeline-model.js.map +1 -0
- package/dist/browser/feedback/dialog-core.js +26 -14
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/inputs/ChoiceChips.js +66 -0
- package/dist/browser/inputs/ChoiceChips.js.map +1 -0
- package/dist/browser/inputs/ChoiceGroups.js +53 -12
- package/dist/browser/inputs/ChoiceGroups.js.map +1 -1
- package/dist/browser/inputs/FileDropTarget.js +129 -0
- package/dist/browser/inputs/FileDropTarget.js.map +1 -0
- package/dist/browser/inputs/FileInputs.js +84 -43
- package/dist/browser/inputs/FileInputs.js.map +1 -1
- package/dist/browser/inputs/SignatureInput.js +558 -0
- package/dist/browser/inputs/SignatureInput.js.map +1 -0
- package/dist/browser/inputs/emoji/EmojiPicker.js +841 -0
- package/dist/browser/inputs/emoji/EmojiPicker.js.map +1 -0
- package/dist/browser/inputs/emoji/emoji-data.js +1903 -0
- package/dist/browser/inputs/emoji/emoji-data.js.map +1 -0
- package/dist/browser/inputs/emoji/emoji-index.js +209 -0
- package/dist/browser/inputs/emoji/emoji-index.js.map +1 -0
- package/dist/browser/inputs/emoji/emoji-messages.js +64 -0
- package/dist/browser/inputs/emoji/emoji-messages.js.map +1 -0
- package/dist/browser/inputs/file-drop.js +338 -0
- package/dist/browser/inputs/file-drop.js.map +1 -0
- package/dist/browser/inputs/index.js +6 -0
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/inputs/markdown/MarkdownEditor.js +72 -78
- package/dist/browser/inputs/markdown/MarkdownEditor.js.map +1 -1
- package/dist/browser/inputs/markdown/actions.js +48 -2
- package/dist/browser/inputs/markdown/actions.js.map +1 -1
- package/dist/browser/inputs/markdown/code-zone.js +38 -2
- package/dist/browser/inputs/markdown/code-zone.js.map +1 -1
- package/dist/browser/inputs/signature-messages.js +39 -0
- package/dist/browser/inputs/signature-messages.js.map +1 -0
- package/dist/browser/inputs/signature.js +208 -0
- package/dist/browser/inputs/signature.js.map +1 -0
- package/dist/browser/internal/render-error.js +49 -0
- package/dist/browser/internal/render-error.js.map +1 -0
- package/dist/browser/intl/messages.js +205 -4
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +483 -218
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/FloatingWindow.js +4 -1
- package/dist/browser/layout/FloatingWindow.js.map +1 -1
- package/dist/browser/layout/Navigation.js +274 -197
- package/dist/browser/layout/Navigation.js.map +1 -1
- package/dist/browser/layout/SidebarItemPreview.js +5 -1
- package/dist/browser/layout/SidebarItemPreview.js.map +1 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/layout/navigation-model.js +2 -0
- package/dist/browser/layout/navigation-model.js.map +1 -1
- package/dist/browser/surfaces/NoticeCard.js +47 -44
- package/dist/browser/surfaces/NoticeCard.js.map +1 -1
- package/dist/browser/surfaces/ResourceCard.js +212 -0
- package/dist/browser/surfaces/ResourceCard.js.map +1 -0
- package/dist/browser/surfaces/index.js +1 -0
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/licenses/emojibase-data.txt +21 -0
- package/dist/ssr/actions/ContextMenu.js +3 -1
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +49 -12
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +4 -1
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +823 -221
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/ChatPrimitives.js +9 -6
- package/dist/ssr/chat/ChatPrimitives.js.map +1 -1
- package/dist/ssr/chat/chat-behavior.js +9 -0
- package/dist/ssr/chat/chat-behavior.js.map +1 -1
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/chat/types.js.map +1 -1
- package/dist/ssr/content/Calendar.js +183 -142
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/FileView.js +30 -6
- package/dist/ssr/content/FileView.js.map +1 -1
- package/dist/ssr/content/Lightbox.js +19 -5
- package/dist/ssr/content/Lightbox.js.map +1 -1
- package/dist/ssr/content/MarkdownView.js +9 -3
- package/dist/ssr/content/MarkdownView.js.map +1 -1
- package/dist/ssr/content/PdfPreview.js +77 -36
- package/dist/ssr/content/PdfPreview.js.map +1 -1
- package/dist/ssr/content/Timeline.js +804 -0
- package/dist/ssr/content/Timeline.js.map +1 -0
- package/dist/ssr/content/VideoPlayer.js +228 -0
- package/dist/ssr/content/VideoPlayer.js.map +1 -0
- package/dist/ssr/content/chart-inspection.js +7 -2
- package/dist/ssr/content/chart-inspection.js.map +1 -1
- package/dist/ssr/content/file-view-preview.js +2 -2
- package/dist/ssr/content/file-view-preview.js.map +1 -1
- package/dist/ssr/content/index.js +3 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/content/markdown-links.js +178 -0
- package/dist/ssr/content/markdown-links.js.map +1 -0
- package/dist/ssr/content/timeline-model.js +579 -0
- package/dist/ssr/content/timeline-model.js.map +1 -0
- package/dist/ssr/feedback/dialog-core.js +26 -14
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/inputs/ChoiceChips.js +66 -0
- package/dist/ssr/inputs/ChoiceChips.js.map +1 -0
- package/dist/ssr/inputs/ChoiceGroups.js +12 -4
- package/dist/ssr/inputs/ChoiceGroups.js.map +1 -1
- package/dist/ssr/inputs/FileDropTarget.js +103 -0
- package/dist/ssr/inputs/FileDropTarget.js.map +1 -0
- package/dist/ssr/inputs/FileInputs.js +49 -12
- package/dist/ssr/inputs/FileInputs.js.map +1 -1
- package/dist/ssr/inputs/SignatureInput.js +404 -0
- package/dist/ssr/inputs/SignatureInput.js.map +1 -0
- package/dist/ssr/inputs/emoji/EmojiPicker.js +551 -0
- package/dist/ssr/inputs/emoji/EmojiPicker.js.map +1 -0
- package/dist/ssr/inputs/emoji/emoji-data.js +1903 -0
- package/dist/ssr/inputs/emoji/emoji-data.js.map +1 -0
- package/dist/ssr/inputs/emoji/emoji-index.js +209 -0
- package/dist/ssr/inputs/emoji/emoji-index.js.map +1 -0
- package/dist/ssr/inputs/emoji/emoji-messages.js +64 -0
- package/dist/ssr/inputs/emoji/emoji-messages.js.map +1 -0
- package/dist/ssr/inputs/file-drop.js +338 -0
- package/dist/ssr/inputs/file-drop.js.map +1 -0
- package/dist/ssr/inputs/index.js +6 -0
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/inputs/markdown/MarkdownEditor.js +14 -2
- package/dist/ssr/inputs/markdown/MarkdownEditor.js.map +1 -1
- package/dist/ssr/inputs/markdown/actions.js +48 -2
- package/dist/ssr/inputs/markdown/actions.js.map +1 -1
- package/dist/ssr/inputs/markdown/code-zone.js +38 -2
- package/dist/ssr/inputs/markdown/code-zone.js.map +1 -1
- package/dist/ssr/inputs/signature-messages.js +39 -0
- package/dist/ssr/inputs/signature-messages.js.map +1 -0
- package/dist/ssr/inputs/signature.js +208 -0
- package/dist/ssr/inputs/signature.js.map +1 -0
- package/dist/ssr/internal/render-error.js +49 -0
- package/dist/ssr/internal/render-error.js.map +1 -0
- package/dist/ssr/intl/messages.js +205 -4
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +264 -47
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/FloatingWindow.js +4 -1
- package/dist/ssr/layout/FloatingWindow.js.map +1 -1
- package/dist/ssr/layout/Navigation.js +169 -122
- package/dist/ssr/layout/Navigation.js.map +1 -1
- package/dist/ssr/layout/SidebarItemPreview.js +5 -1
- package/dist/ssr/layout/SidebarItemPreview.js.map +1 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/layout/navigation-model.js +2 -0
- package/dist/ssr/layout/navigation-model.js.map +1 -1
- package/dist/ssr/surfaces/NoticeCard.js +17 -12
- package/dist/ssr/surfaces/NoticeCard.js.map +1 -1
- package/dist/ssr/surfaces/ResourceCard.js +115 -0
- package/dist/ssr/surfaces/ResourceCard.js.map +1 -0
- 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/Dropdown.d.ts +13 -1
- package/dist/types/actions/FilterChip.d.ts +5 -0
- package/dist/types/chat/ChatComposer.d.ts +24 -1
- package/dist/types/chat/ChatPrimitives.d.ts +1 -1
- package/dist/types/chat/chat-behavior.d.ts +15 -0
- package/dist/types/chat/index.d.ts +1 -1
- package/dist/types/chat/types.d.ts +34 -0
- package/dist/types/content/Calendar.d.ts +28 -8
- package/dist/types/content/Lightbox.d.ts +8 -0
- package/dist/types/content/Timeline.d.ts +49 -0
- package/dist/types/content/VideoPlayer.d.ts +41 -0
- package/dist/types/content/index.d.ts +6 -2
- package/dist/types/content/markdown-links.d.ts +66 -0
- package/dist/types/content/timeline-model.d.ts +148 -0
- package/dist/types/feedback/dialog-core.d.ts +1 -1
- package/dist/types/inputs/ChoiceChips.d.ts +20 -0
- package/dist/types/inputs/ChoiceGroups.d.ts +11 -2
- package/dist/types/inputs/FileDropTarget.d.ts +23 -0
- package/dist/types/inputs/FileInputs.d.ts +8 -0
- package/dist/types/inputs/SignatureInput.d.ts +22 -0
- package/dist/types/inputs/emoji/EmojiPicker.d.ts +42 -0
- package/dist/types/inputs/emoji/emoji-data.d.ts +2 -0
- package/dist/types/inputs/emoji/emoji-index.d.ts +109 -0
- package/dist/types/inputs/emoji/emoji-messages.d.ts +30 -0
- package/dist/types/inputs/file-drop.d.ts +80 -0
- package/dist/types/inputs/index.d.ts +12 -0
- package/dist/types/inputs/markdown/actions.d.ts +4 -0
- package/dist/types/inputs/markdown/code-zone.d.ts +7 -0
- package/dist/types/inputs/signature-messages.d.ts +11 -0
- package/dist/types/inputs/signature.d.ts +72 -0
- package/dist/types/internal/render-error.d.ts +13 -0
- package/dist/types/intl/messages.d.ts +101 -0
- package/dist/types/layout/AppWorkspace.d.ts +38 -0
- package/dist/types/layout/SidebarItemPreview.d.ts +2 -0
- package/dist/types/layout/index.d.ts +2 -2
- package/dist/types/layout/navigation-model.d.ts +18 -0
- package/dist/types/surfaces/ResourceCard.d.ts +31 -0
- package/dist/types/surfaces/index.d.ts +2 -0
- package/package.json +5 -4
|
@@ -1,59 +1,158 @@
|
|
|
1
1
|
import { mergeProps as _$mergeProps } from "solid-js/web";
|
|
2
|
-
import { createComponent as _$createComponent } from "solid-js/web";
|
|
3
2
|
import { ssrStyleProperty as _$ssrStyleProperty } from "solid-js/web";
|
|
4
3
|
import { memo as _$memo } from "solid-js/web";
|
|
4
|
+
import { createComponent as _$createComponent } from "solid-js/web";
|
|
5
5
|
import { ssr as _$ssr } from "solid-js/web";
|
|
6
6
|
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
7
7
|
import { escape as _$escape } from "solid-js/web";
|
|
8
8
|
var _tmpl$ = ["<span><strong", ">", "</strong></span>"],
|
|
9
|
-
_tmpl$2 = ["<
|
|
10
|
-
_tmpl$3 = ["<
|
|
11
|
-
_tmpl$4 =
|
|
12
|
-
_tmpl$5 = ["<div
|
|
13
|
-
_tmpl$6 =
|
|
14
|
-
_tmpl$7 =
|
|
15
|
-
_tmpl$8 = ["<div class=\"k2b-chat-
|
|
9
|
+
_tmpl$2 = ["<input class=\"k2b-sr-only\" type=\"file\" tabindex=\"-1\" aria-hidden=\"true\"", "", ">"],
|
|
10
|
+
_tmpl$3 = ["<i", " aria-hidden=\"true\"></i>"],
|
|
11
|
+
_tmpl$4 = "<i class=\"ti ti-letter-case\" aria-hidden=\"true\"></i>",
|
|
12
|
+
_tmpl$5 = ["<div", " class=\"k2b-chat-composer__format\" role=\"group\"", ">", "</div>"],
|
|
13
|
+
_tmpl$6 = "<i class=\"ti ti-mood-smile\" aria-hidden=\"true\"></i>",
|
|
14
|
+
_tmpl$7 = "<i class=\"ti ti-chevron-up\" aria-hidden=\"true\"></i>",
|
|
15
|
+
_tmpl$8 = ["<div class=\"k2b-chat-composer__microphone\">", "", "</div>"],
|
|
16
16
|
_tmpl$9 = ["<div class=\"k2b-chat-composer__highlight\" aria-hidden=\"true\">", "\n</div>"],
|
|
17
|
-
_tmpl$0 =
|
|
18
|
-
_tmpl$1 = ["<div class=\"k2b-chat-
|
|
19
|
-
_tmpl$10 = ["<
|
|
20
|
-
_tmpl$11 = ["<
|
|
21
|
-
_tmpl$12 = ["<div class=\"k2b-chat-
|
|
22
|
-
_tmpl$13 = ["<
|
|
23
|
-
_tmpl$14 = ["<div
|
|
24
|
-
_tmpl$15 = ["<
|
|
25
|
-
_tmpl$16 = ["<
|
|
26
|
-
_tmpl$17 = ["<
|
|
27
|
-
_tmpl$18 = ["<
|
|
28
|
-
_tmpl$19 = "<i class=\"ti ti-
|
|
29
|
-
_tmpl$20 = ["<
|
|
30
|
-
_tmpl$21 = ["<div class=\"k2b-chat-
|
|
31
|
-
_tmpl$22 = ["<
|
|
17
|
+
_tmpl$0 = "<textarea class=\"k2b-chat-composer__measure\" rows=\"1\" tabindex=\"-1\" aria-hidden=\"true\" readonly></textarea>",
|
|
18
|
+
_tmpl$1 = ["<div class=\"k2b-chat-composer__input\" role=\"group\"", ">", "<textarea class=\"", "\" rows=\"1\"", "", "></textarea>", "</div>"],
|
|
19
|
+
_tmpl$10 = ["<span class=\"", "\">", "</span>"],
|
|
20
|
+
_tmpl$11 = ["<div class=\"k2b-chat-composer-accessory\"><div", " class=\"k2b-chat-composer__commands\" role=\"listbox\"", ">", "</div></div>"],
|
|
21
|
+
_tmpl$12 = ["<div role=\"status\" class=\"k2b-chat-composer__loading\"><i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i><strong>", "</strong></div>"],
|
|
22
|
+
_tmpl$13 = ["<div role=\"status\"><i class=\"ti ti-alert-circle\"></i> ", "</div>"],
|
|
23
|
+
_tmpl$14 = ["<div role=\"status\">", "</div>"],
|
|
24
|
+
_tmpl$15 = ["<div class=\"k2b-chat-composer-accessory\"><div", " class=\"k2b-chat-composer__commands\" role=\"listbox\"", ">", "", "", "", "</div></div>"],
|
|
25
|
+
_tmpl$16 = ["<div class=\"k2b-chat-composer-slot\"", "><div style=\"", "\"", ">", "</div>", "", "</div>"],
|
|
26
|
+
_tmpl$17 = ["<div class=\"k2b-chat-composer__hint\" aria-live=\"polite\">", "</div>"],
|
|
27
|
+
_tmpl$18 = ["<div class=\"k2b-chat-composer__attachments\" role=\"list\"", " tabindex=\"0\">", "</div>"],
|
|
28
|
+
_tmpl$19 = ["<div class=\"k2b-chat-composer__error\" role=\"alert\"><i class=\"ti ti-alert-circle\" aria-hidden=\"true\"></i>", "</div>"],
|
|
29
|
+
_tmpl$20 = ["<div class=\"k2b-chat-composer__row\">", "", "<div class=\"k2b-chat-composer__field\">", "<div class=\"k2b-chat-composer__field-tools\">", "", "", "</div></div>", "</div>"],
|
|
30
|
+
_tmpl$21 = ["<div class=\"k2b-chat-composer-shell\">", "<section class=\"", "\"", " role=\"group\"", ">", "", "", "", "</section></div>"],
|
|
31
|
+
_tmpl$22 = ["<button id=\"", "\" type=\"button\" role=\"option\" tabindex=\"-1\"", "><span class=\"k2b-chat-composer__emoji-glyph\" aria-hidden=\"true\">", "</span><strong>", "</strong>", "</button>"],
|
|
32
|
+
_tmpl$23 = ["<small>:", ":</small>"],
|
|
33
|
+
_tmpl$24 = ["<button id=\"", "\" type=\"button\" role=\"option\" tabindex=\"-1\"", "><i", " aria-hidden=\"true\"></i><strong>", "</strong><small>", "</small></button>"],
|
|
34
|
+
_tmpl$25 = ["<span class=\"k2b-chat-composer__hint-text\">", "</span>"],
|
|
35
|
+
_tmpl$26 = ["<span class=\"k2b-chat-composer__dictation\"", "><i", " aria-hidden=\"true\"></i><span>", "</span></span>"],
|
|
36
|
+
_tmpl$27 = ["<button type=\"button\" class=\"k2b-chat-composer__hint-action\"", ">", "</button>"],
|
|
37
|
+
_tmpl$28 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-remove\"", "", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
|
|
38
|
+
_tmpl$29 = ["<div class=\"k2b-chat-composer__attachment\" role=\"listitem\"><div class=\"", "\">", "", "</div>", "</div>"],
|
|
39
|
+
_tmpl$30 = ["<img", ">"],
|
|
40
|
+
_tmpl$31 = ["<div class=\"k2b-chat-composer__attachment-identity\">", "", "</div>"],
|
|
41
|
+
_tmpl$32 = ["<a class=\"k2b-chat-composer__attachment-link\"", " target=\"_blank\" rel=\"noopener noreferrer\"", ">", "", "</a>"],
|
|
42
|
+
_tmpl$33 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-action\"", ">", "", "</button>"],
|
|
43
|
+
_tmpl$34 = ["<footer class=\"k2b-chat-composer__footer\">", "</footer>"],
|
|
44
|
+
_tmpl$35 = ["<div class=\"k2b-chat-composer__tools\">", "", "", "", "", "", "", "</div>"],
|
|
45
|
+
_tmpl$36 = ["<div class=\"k2b-chat-composer__submit\">", "", "", "", "", "</div>"];
|
|
32
46
|
import { children, createEffect, createMemo, createSignal, createUniqueId, For, onCleanup, onMount, Show, untrack } from "solid-js";
|
|
33
47
|
import { Dropdown } from "../actions/Dropdown";
|
|
34
48
|
import { Tooltip } from "../feedback/Tooltip";
|
|
49
|
+
import { replaceTextareaRange } from "../inputs/editor-dom";
|
|
50
|
+
import { completedEmojiShortcode, emojiInTone, emojiName, emojiShortcodeQuery, loadEmojiIndex, suggestEmoji } from "../inputs/emoji/emoji-index";
|
|
51
|
+
import { FileDropTarget } from "../inputs/FileDropTarget";
|
|
52
|
+
import { toggleBulletList, toggleCodeBlock, toggleInlineMarker, toggleQuote } from "../inputs/markdown/actions";
|
|
53
|
+
import { openCodeFence } from "../inputs/markdown/code-zone";
|
|
35
54
|
import { SelectChip } from "../inputs/SelectChip";
|
|
55
|
+
import { useLocale } from "../intl/locale";
|
|
36
56
|
import { useUiMessages } from "../intl/messages";
|
|
37
57
|
import { ChatContextUsage as ContextUsage } from "./ChatPrimitives";
|
|
38
|
-
import { executeChatAction, nextChatCommandIndex, reportChatFailure, runChatSubmission } from "./chat-behavior";
|
|
58
|
+
import { conversationEnterAction, executeChatAction, nextChatCommandIndex, reportChatFailure, runChatSubmission } from "./chat-behavior";
|
|
39
59
|
import { chatCommandQuery, chatMentionSegments, reconcileChatMentions } from "./composer-document";
|
|
40
60
|
const composerMaxInputHeight = 309;
|
|
61
|
+
/** Emoji suggestions for a `:shortcode`, as many as fit the list without scrolling on a phone. */
|
|
62
|
+
const emojiSuggestionLimit = 8;
|
|
41
63
|
// Keep editor undo text within approximately 2 MiB, plus the current edit.
|
|
42
64
|
const composerUndoBudgetChars = 1_000_000;
|
|
65
|
+
const insertComposerLink = textarea => {
|
|
66
|
+
const {
|
|
67
|
+
value,
|
|
68
|
+
selectionStart,
|
|
69
|
+
selectionEnd
|
|
70
|
+
} = textarea;
|
|
71
|
+
const label = value.slice(selectionStart, selectionEnd);
|
|
72
|
+
replaceTextareaRange(textarea, selectionStart, selectionEnd, `[${label}]()`);
|
|
73
|
+
// Without a selection the label comes first, otherwise the address.
|
|
74
|
+
const caret = label ? selectionStart + label.length + 3 : selectionStart + 1;
|
|
75
|
+
textarea.setSelectionRange(caret, caret);
|
|
76
|
+
};
|
|
77
|
+
const formatTools = [{
|
|
78
|
+
id: "bold",
|
|
79
|
+
icon: "ti ti-bold",
|
|
80
|
+
label: m => m.boldShortcut,
|
|
81
|
+
run: textarea => toggleInlineMarker(textarea, "**"),
|
|
82
|
+
key: "b"
|
|
83
|
+
}, {
|
|
84
|
+
id: "italic",
|
|
85
|
+
icon: "ti ti-italic",
|
|
86
|
+
label: m => m.italicShortcut,
|
|
87
|
+
run: textarea => toggleInlineMarker(textarea, "*"),
|
|
88
|
+
key: "i"
|
|
89
|
+
}, {
|
|
90
|
+
id: "strikethrough",
|
|
91
|
+
icon: "ti ti-strikethrough",
|
|
92
|
+
label: m => m.strikethroughShortcut,
|
|
93
|
+
run: textarea => toggleInlineMarker(textarea, "~~"),
|
|
94
|
+
shiftCode: "KeyX"
|
|
95
|
+
}, {
|
|
96
|
+
id: "code",
|
|
97
|
+
icon: "ti ti-code",
|
|
98
|
+
label: m => m.inlineCodeShortcut,
|
|
99
|
+
run: textarea => toggleInlineMarker(textarea, "`"),
|
|
100
|
+
key: "e"
|
|
101
|
+
}, {
|
|
102
|
+
id: "code-block",
|
|
103
|
+
icon: "ti ti-source-code",
|
|
104
|
+
label: m => m.codeBlock,
|
|
105
|
+
run: toggleCodeBlock
|
|
106
|
+
}, {
|
|
107
|
+
id: "bullet-list",
|
|
108
|
+
icon: "ti ti-list",
|
|
109
|
+
label: m => m.bulletListShortcut,
|
|
110
|
+
run: toggleBulletList,
|
|
111
|
+
shiftCode: "Digit8"
|
|
112
|
+
}, {
|
|
113
|
+
id: "quote",
|
|
114
|
+
icon: "ti ti-quote",
|
|
115
|
+
label: m => m.quote,
|
|
116
|
+
run: toggleQuote
|
|
117
|
+
}, {
|
|
118
|
+
id: "link",
|
|
119
|
+
icon: "ti ti-link",
|
|
120
|
+
label: m => m.insertLink,
|
|
121
|
+
run: insertComposerLink
|
|
122
|
+
}];
|
|
123
|
+
const formatShortcut = event => {
|
|
124
|
+
if (event.altKey || !(event.ctrlKey || event.metaKey)) return undefined;
|
|
125
|
+
return formatTools.find(tool => event.shiftKey ? tool.shiftCode === event.code : tool.key === event.key.toLowerCase());
|
|
126
|
+
};
|
|
127
|
+
const touchOnlyQuery = "(any-pointer: coarse) and (not (any-pointer: fine))";
|
|
128
|
+
const isTouchOnly = () => typeof matchMedia === "function" && matchMedia(touchOnlyQuery).matches;
|
|
129
|
+
/** How long a press on the microphone lasts before it asks for a voice message instead of dictation. */
|
|
130
|
+
const microphoneHoldMs = 500;
|
|
131
|
+
/** Keeps the field focused (and a phone's keyboard open) when a composer button is pressed with a mouse or finger. */
|
|
132
|
+
const keepFieldFocus = event => event.preventDefault();
|
|
43
133
|
const attachmentIcon = attachment => attachment.icon ?? (attachment.kind === "image" ? "ti ti-photo" : attachment.kind === "resource" ? "ti ti-link" : "ti ti-file");
|
|
134
|
+
const hasContent = items => items.some(item => item != null && typeof item !== "boolean" && item !== "");
|
|
44
135
|
export function ChatComposer(props) {
|
|
45
136
|
const accessory = children(() => props.accessory);
|
|
46
|
-
const hasAccessory = () => accessory.toArray()
|
|
137
|
+
const hasAccessory = () => hasContent(accessory.toArray());
|
|
138
|
+
const hint = children(() => props.hint);
|
|
47
139
|
const messages = useUiMessages();
|
|
48
140
|
const commandListId = `k2b-chat-commands-${createUniqueId().replace(/[^A-Za-z0-9_-]/g, "-")}`;
|
|
141
|
+
const formatGroupId = `${commandListId}-format`;
|
|
49
142
|
const [selectedCommandIndex, setSelectedCommandIndex] = createSignal(0);
|
|
50
|
-
const [dragActive, setDragActive] = createSignal(false);
|
|
51
143
|
const [addingFiles, setAddingFiles] = createSignal(false);
|
|
52
144
|
const [submitting, setSubmitting] = createSignal(false);
|
|
53
145
|
let composerRef;
|
|
54
146
|
let textareaRef;
|
|
55
147
|
let fileInputRef;
|
|
148
|
+
let measureRef;
|
|
149
|
+
let microphoneRef;
|
|
56
150
|
let sawRunning = props.state === "running";
|
|
151
|
+
const conversation = () => props.variant === "conversation";
|
|
152
|
+
const [formattingOpen, setFormattingOpen] = createSignal(false);
|
|
153
|
+
const [microphoneMenuOpen, setMicrophoneMenuOpen] = createSignal(false);
|
|
154
|
+
const dictation = () => props.microphone?.dictation ?? null;
|
|
155
|
+
const showHint = () => conversation() || dictation() !== null || hasContent(hint.toArray());
|
|
57
156
|
const state = () => props.state ?? "idle";
|
|
58
157
|
const running = () => state() === "running";
|
|
59
158
|
const stopping = () => state() === "stopping";
|
|
@@ -70,15 +169,29 @@ export function ChatComposer(props) {
|
|
|
70
169
|
let highlightRef;
|
|
71
170
|
let commandListRef;
|
|
72
171
|
const mentions = () => props.mentions ?? [];
|
|
172
|
+
const locale = useLocale();
|
|
173
|
+
const [emojiIndex, setEmojiIndex] = createSignal();
|
|
174
|
+
const emojiQuery = createMemo(() => !props.emoji || dismissed() || composing() ? null : emojiShortcodeQuery(props.value, caret(), selectionEnd()));
|
|
175
|
+
// The emoji data loads with the first `:shortcode`; a failed load only means no suggestions.
|
|
176
|
+
createEffect(() => {
|
|
177
|
+
if (emojiQuery() && !emojiIndex()) loadEmojiIndex().then(setEmojiIndex, () => undefined);
|
|
178
|
+
});
|
|
179
|
+
const emojiMatches = createMemo(() => {
|
|
180
|
+
const token = emojiQuery();
|
|
181
|
+
const index = emojiIndex();
|
|
182
|
+
return token && index ? suggestEmoji(index, token.query, emojiSuggestionLimit) : [];
|
|
183
|
+
});
|
|
184
|
+
const emojiOpen = () => emojiMatches().length > 0;
|
|
73
185
|
const commandQuery = createMemo(() => dismissed() || composing() ? null : chatCommandQuery(props.value, caret(), selectionEnd()));
|
|
74
186
|
const commandMatches = createMemo(() => {
|
|
75
187
|
const token = commandQuery();
|
|
76
188
|
if (!token) return [];
|
|
77
189
|
return [...(props.commands ?? []).filter(command => command.name.toLowerCase().includes(token.query.toLowerCase())), ...searchResults()];
|
|
78
190
|
});
|
|
79
|
-
const commandsOpen = () => Boolean(commandQuery() && (props.commands?.length || props.searchCommands));
|
|
191
|
+
const commandsOpen = () => Boolean(!emojiOpen() && commandQuery() && (props.commands?.length || props.searchCommands));
|
|
192
|
+
const suggestionsOpen = () => commandsOpen() || emojiOpen();
|
|
80
193
|
createEffect(() => {
|
|
81
|
-
if (!
|
|
194
|
+
if (!suggestionsOpen()) return;
|
|
82
195
|
let disposed = false;
|
|
83
196
|
const measure = () => {
|
|
84
197
|
if (disposed || !commandListRef) return;
|
|
@@ -175,7 +288,10 @@ export function ChatComposer(props) {
|
|
|
175
288
|
setSelectionEnd(textareaRef?.selectionEnd ?? props.value.length);
|
|
176
289
|
};
|
|
177
290
|
const selectedCommand = () => commandMatches()[selectedCommandIndex()];
|
|
178
|
-
const
|
|
291
|
+
const busy = () => Boolean(props.disabled || stopping() || state() === "submitting" || executing() || addingFiles());
|
|
292
|
+
const blocked = () => busy() || submitting();
|
|
293
|
+
/** The conversation field stays editable while a message is sent, so it keeps the focus and a phone its keyboard. */
|
|
294
|
+
const editBlocked = () => conversation() ? busy() : blocked();
|
|
179
295
|
const hasDraft = () => Boolean(props.value.trim() || !running() && attachments().length > 0);
|
|
180
296
|
const canSubmit = () => !blocked() && hasDraft() && !(running() && runningSubmitIntent() === "steer" && mentions().length);
|
|
181
297
|
const canSelectFiles = () => Boolean(props.fileSelection && !props.fileSelection.disabled && !running() && !blocked());
|
|
@@ -195,7 +311,7 @@ export function ChatComposer(props) {
|
|
|
195
311
|
icon: addingFiles() ? "ti ti-loader-2 k2b-spin" : "ti ti-paperclip",
|
|
196
312
|
label: props.fileSelection.label ?? messages().attachFiles,
|
|
197
313
|
disabled: !canSelectFiles(),
|
|
198
|
-
action: () =>
|
|
314
|
+
action: () => chooseFiles()
|
|
199
315
|
});
|
|
200
316
|
}
|
|
201
317
|
for (const action of props.menuActions ?? []) {
|
|
@@ -211,6 +327,14 @@ export function ChatComposer(props) {
|
|
|
211
327
|
};
|
|
212
328
|
const autoResize = () => {
|
|
213
329
|
if (!textareaRef) return;
|
|
330
|
+
if (conversation()) {
|
|
331
|
+
// A hidden copy measures the text. Collapsing the field itself would shrink the composer for a frame, and
|
|
332
|
+
// WebKit then clamps the scroll position of the conversation above it. CSS caps the height.
|
|
333
|
+
if (!measureRef) return;
|
|
334
|
+
measureRef.value = textareaRef.value;
|
|
335
|
+
textareaRef.style.height = `${measureRef.scrollHeight}px`;
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
214
338
|
textareaRef.style.height = "auto";
|
|
215
339
|
textareaRef.style.height = `${Math.min(textareaRef.scrollHeight, composerMaxInputHeight)}px`;
|
|
216
340
|
};
|
|
@@ -218,14 +342,22 @@ export function ChatComposer(props) {
|
|
|
218
342
|
onMount(() => {
|
|
219
343
|
autoResize();
|
|
220
344
|
if (props.focusToken !== undefined) focus();
|
|
345
|
+
// The copy follows the field's width, so a narrower composer measures more lines.
|
|
346
|
+
if (measureRef && typeof ResizeObserver === "function") {
|
|
347
|
+
const observer = new ResizeObserver(() => autoResize());
|
|
348
|
+
observer.observe(measureRef);
|
|
349
|
+
onCleanup(() => observer.disconnect());
|
|
350
|
+
}
|
|
221
351
|
});
|
|
222
352
|
createEffect(() => {
|
|
223
353
|
commandMatches();
|
|
354
|
+
emojiMatches();
|
|
224
355
|
setSelectedCommandIndex(0);
|
|
225
356
|
});
|
|
226
357
|
createEffect(() => {
|
|
227
358
|
const index = selectedCommandIndex();
|
|
228
359
|
commandMatches();
|
|
360
|
+
emojiMatches();
|
|
229
361
|
queueMicrotask(() => {
|
|
230
362
|
const list = commandListRef;
|
|
231
363
|
const item = list?.querySelector(`[id="${commandListId}-${index}"]`);
|
|
@@ -255,6 +387,13 @@ export function ChatComposer(props) {
|
|
|
255
387
|
});
|
|
256
388
|
const setAttachments = next => props.onAttachmentsChange?.(next);
|
|
257
389
|
const renderAttachmentCopy = attachment => _$ssr(_tmpl$, _$ssrAttribute("title", _$escape(attachment.name, true), false), _$escape(attachment.name));
|
|
390
|
+
const chooseFiles = () => {
|
|
391
|
+
const selection = props.fileSelection;
|
|
392
|
+
if (!selection?.choose) return fileInputRef?.click();
|
|
393
|
+
selection.choose().then(
|
|
394
|
+
// A single-file composer keeps the first chosen file, as its file dialog and drops do.
|
|
395
|
+
files => void runFiles(selection.multiple === false ? files.slice(0, 1) : files), error => (props.fileSelection?.onError ?? props.onError)?.(error));
|
|
396
|
+
};
|
|
258
397
|
const runFiles = async files => {
|
|
259
398
|
if (!canSelectFiles()) return;
|
|
260
399
|
const selected = Array.from(files);
|
|
@@ -292,8 +431,17 @@ export function ChatComposer(props) {
|
|
|
292
431
|
},
|
|
293
432
|
perform: () => props.onSubmit(input),
|
|
294
433
|
restore: () => {
|
|
295
|
-
|
|
296
|
-
|
|
434
|
+
// Text typed while the submission ran stays, after the returned draft. Its mentions are read first, because
|
|
435
|
+
// an application may already move them when the text changes.
|
|
436
|
+
const typed = props.value;
|
|
437
|
+
const typedMentions = mentions();
|
|
438
|
+
const shift = previousValue.length + 1;
|
|
439
|
+
props.onValueChange(typed ? `${previousValue}\n${typed}` : previousValue);
|
|
440
|
+
props.onMentionsChange?.(typed ? [...previousMentions, ...typedMentions.map(mention => ({
|
|
441
|
+
...mention,
|
|
442
|
+
start: mention.start + shift,
|
|
443
|
+
end: mention.end + shift
|
|
444
|
+
}))] : previousMentions);
|
|
297
445
|
if (intent !== "steer") setAttachments(previousAttachments);
|
|
298
446
|
},
|
|
299
447
|
onError: props.onError
|
|
@@ -350,13 +498,74 @@ export function ChatComposer(props) {
|
|
|
350
498
|
focus();
|
|
351
499
|
});
|
|
352
500
|
};
|
|
501
|
+
|
|
502
|
+
/** Replaces `start`–`end` with the emoji through the editing path, so the browser's undo restores the shortcode. */
|
|
503
|
+
const insertEmoji = (start, end, emoji) => {
|
|
504
|
+
if (!textareaRef || editBlocked()) return;
|
|
505
|
+
replaceTextareaRange(textareaRef, start, end, emoji);
|
|
506
|
+
syncCaret();
|
|
507
|
+
reportChatFailure(() => props.emoji?.onPick?.(emoji), props.onError);
|
|
508
|
+
};
|
|
509
|
+
const pickEmojiSuggestion = position => {
|
|
510
|
+
const token = emojiQuery();
|
|
511
|
+
const entry = emojiMatches()[position];
|
|
512
|
+
if (!token || !entry) return;
|
|
513
|
+
insertEmoji(token.start, token.end, emojiInTone(entry, props.emoji?.skinTone ?? 0));
|
|
514
|
+
};
|
|
515
|
+
/**
|
|
516
|
+
* A typed colon loads the emoji data, and the closing colon of a known `:shortcode:` turns it into its emoji. A
|
|
517
|
+
* shortcode closed before the data arrived turns when it arrives, as long as nothing changed in the meantime.
|
|
518
|
+
*/
|
|
519
|
+
const completeShortcode = () => {
|
|
520
|
+
const textarea = textareaRef;
|
|
521
|
+
if (!props.emoji || !textarea) return;
|
|
522
|
+
const {
|
|
523
|
+
value,
|
|
524
|
+
selectionStart: caret
|
|
525
|
+
} = textarea;
|
|
526
|
+
const completed = completedEmojiShortcode(value, caret);
|
|
527
|
+
const convert = index => {
|
|
528
|
+
const entry = completed && index.byShortcode.get(completed.shortcode.toLowerCase());
|
|
529
|
+
if (completed && entry) insertEmoji(completed.start, completed.end, emojiInTone(entry, props.emoji?.skinTone ?? 0));
|
|
530
|
+
};
|
|
531
|
+
const index = emojiIndex();
|
|
532
|
+
if (index) {
|
|
533
|
+
convert(index);
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
loadEmojiIndex().then(loaded => {
|
|
537
|
+
setEmojiIndex(loaded);
|
|
538
|
+
const untouched = textarea.value === value && textarea.selectionStart === caret && textarea.selectionEnd === caret;
|
|
539
|
+
if (untouched && textarea.matches(":focus")) convert(loaded);
|
|
540
|
+
}, () => undefined);
|
|
541
|
+
};
|
|
353
542
|
const onKeyDown = event => {
|
|
354
|
-
|
|
543
|
+
// WebKit ends the composition before the keydown of the Enter that confirms it; that keydown keeps keyCode 229.
|
|
544
|
+
if (event.isComposing || event.keyCode === 229 || composing()) return;
|
|
355
545
|
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "z") {
|
|
356
546
|
event.preventDefault();
|
|
357
547
|
restoreHistory(event.shiftKey ? 1 : -1);
|
|
358
548
|
return;
|
|
359
549
|
}
|
|
550
|
+
if (emojiOpen()) {
|
|
551
|
+
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
552
|
+
event.preventDefault();
|
|
553
|
+
setSelectedCommandIndex(index => nextChatCommandIndex(index, emojiMatches().length, event.key === "ArrowUp" ? -1 : 1));
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
// Only a plain Enter or Tab picks: Shift+Enter still breaks the line, Shift+Tab still moves the focus back.
|
|
557
|
+
const plain = !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
558
|
+
if (plain && (event.key === "Enter" || event.key === "Tab")) {
|
|
559
|
+
event.preventDefault();
|
|
560
|
+
pickEmojiSuggestion(selectedCommandIndex());
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (event.key === "Escape") {
|
|
564
|
+
event.preventDefault();
|
|
565
|
+
setDismissed(true);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
360
569
|
const matches = commandMatches();
|
|
361
570
|
if (commandsOpen()) {
|
|
362
571
|
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
@@ -364,7 +573,8 @@ export function ChatComposer(props) {
|
|
|
364
573
|
setSelectedCommandIndex(index => nextChatCommandIndex(index, matches.length, event.key === "ArrowUp" ? -1 : 1));
|
|
365
574
|
return;
|
|
366
575
|
}
|
|
367
|
-
|
|
576
|
+
// Ctrl/⌘+Enter sends, also while suggestions are open.
|
|
577
|
+
if ((event.key === "Tab" || event.key === "Enter" && !event.ctrlKey && !event.metaKey) && matches.length > 0) {
|
|
368
578
|
event.preventDefault();
|
|
369
579
|
const command = selectedCommand();
|
|
370
580
|
if (command) void executeCommand(command);
|
|
@@ -376,301 +586,693 @@ export function ChatComposer(props) {
|
|
|
376
586
|
return;
|
|
377
587
|
}
|
|
378
588
|
}
|
|
379
|
-
|
|
589
|
+
const format = props.formatting && textareaRef ? formatShortcut(event) : undefined;
|
|
590
|
+
if (format && textareaRef) {
|
|
591
|
+
event.preventDefault();
|
|
592
|
+
format.run(textareaRef);
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (event.key !== "Enter") return;
|
|
596
|
+
if (conversation()) {
|
|
597
|
+
const action = conversationEnterAction(event, {
|
|
598
|
+
sendKey: props.sendKey ?? "enter",
|
|
599
|
+
touchOnly: isTouchOnly(),
|
|
600
|
+
inCodeBlock: openCodeFence(props.value, textareaRef?.selectionStart ?? props.value.length) !== null
|
|
601
|
+
});
|
|
602
|
+
if (action === "send") {
|
|
603
|
+
event.preventDefault();
|
|
604
|
+
void submit();
|
|
605
|
+
}
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
const send = props.sendKey === "mod-enter" ? event.ctrlKey || event.metaKey : !event.shiftKey;
|
|
609
|
+
if (send && !event.isComposing) {
|
|
380
610
|
event.preventDefault();
|
|
381
611
|
void submit();
|
|
382
612
|
}
|
|
383
613
|
};
|
|
384
|
-
|
|
614
|
+
const insertText = text => {
|
|
615
|
+
if (!textareaRef || editBlocked()) return;
|
|
616
|
+
replaceTextareaRange(textareaRef, textareaRef.selectionStart, textareaRef.selectionEnd, text);
|
|
617
|
+
};
|
|
618
|
+
let holdTimer;
|
|
619
|
+
let held = false;
|
|
620
|
+
const releaseHold = () => {
|
|
621
|
+
clearTimeout(holdTimer);
|
|
622
|
+
holdTimer = undefined;
|
|
623
|
+
};
|
|
624
|
+
onCleanup(releaseHold);
|
|
625
|
+
const microphoneDisabled = () => Boolean(props.microphone?.disabled || blocked() || dictation() === "refining");
|
|
626
|
+
const microphoneItems = () => {
|
|
627
|
+
const microphone = props.microphone;
|
|
628
|
+
const items = [];
|
|
629
|
+
if (microphone?.onDictate) {
|
|
630
|
+
const dictate = microphone.onDictate;
|
|
631
|
+
items.push({
|
|
632
|
+
icon: "ti ti-microphone",
|
|
633
|
+
label: messages().dictate,
|
|
634
|
+
action: () => reportChatFailure(dictate, props.onError)
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
if (microphone?.onVoiceMessage) {
|
|
638
|
+
const record = microphone.onVoiceMessage;
|
|
639
|
+
items.push({
|
|
640
|
+
icon: "ti ti-player-record",
|
|
641
|
+
label: messages().recordVoiceMessage,
|
|
642
|
+
action: () => reportChatFailure(record, props.onError)
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
return items;
|
|
646
|
+
};
|
|
647
|
+
const dictationStatus = () => {
|
|
648
|
+
switch (dictation()) {
|
|
649
|
+
case "listening":
|
|
650
|
+
return {
|
|
651
|
+
icon: "ti ti-microphone",
|
|
652
|
+
text: messages().dictationListening
|
|
653
|
+
};
|
|
654
|
+
case "refining":
|
|
655
|
+
return {
|
|
656
|
+
icon: "ti ti-loader-2 k2b-spin",
|
|
657
|
+
text: messages().dictationRefining
|
|
658
|
+
};
|
|
659
|
+
case "refined":
|
|
660
|
+
return {
|
|
661
|
+
icon: "ti ti-sparkles",
|
|
662
|
+
text: messages().dictationRefined
|
|
663
|
+
};
|
|
664
|
+
case "unrefined":
|
|
665
|
+
return {
|
|
666
|
+
icon: "ti ti-microphone",
|
|
667
|
+
text: messages().dictationUnrefined
|
|
668
|
+
};
|
|
669
|
+
case "interrupted":
|
|
670
|
+
return {
|
|
671
|
+
icon: "ti ti-alert-triangle",
|
|
672
|
+
text: messages().dictationInterrupted
|
|
673
|
+
};
|
|
674
|
+
default:
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
const fileInput = () => _$createComponent(Show, {
|
|
385
679
|
get when() {
|
|
386
|
-
return
|
|
680
|
+
return props.fileSelection;
|
|
681
|
+
},
|
|
682
|
+
get children() {
|
|
683
|
+
return _$ssr(_tmpl$2, _$ssrAttribute("accept", _$escape(props.fileSelection?.accept, true), false), _$ssrAttribute("multiple", props.fileSelection?.multiple ?? true, true));
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
const addMenu = (icon, extraClass = "") => _$createComponent(Dropdown.Root, {
|
|
687
|
+
position: "top-right",
|
|
688
|
+
get label() {
|
|
689
|
+
return messages().addToChat;
|
|
690
|
+
},
|
|
691
|
+
get items() {
|
|
692
|
+
return menuItems();
|
|
693
|
+
},
|
|
694
|
+
get disabled() {
|
|
695
|
+
return blocked();
|
|
387
696
|
},
|
|
388
697
|
get children() {
|
|
389
|
-
return _$
|
|
698
|
+
return _$createComponent(Dropdown.Trigger, {
|
|
699
|
+
appearance: "plain",
|
|
700
|
+
"class": `k2b-chat-composer__icon-action${extraClass}`,
|
|
701
|
+
get label() {
|
|
702
|
+
return messages().addToChat;
|
|
703
|
+
},
|
|
704
|
+
get tooltip() {
|
|
705
|
+
return messages().addToChat;
|
|
706
|
+
},
|
|
707
|
+
get children() {
|
|
708
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(icon, true), false));
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
/** The conversation's attach button opens the file choice directly; other actions turn it into the add menu. */
|
|
715
|
+
const attachControl = () => _$createComponent(Show, {
|
|
716
|
+
get when() {
|
|
717
|
+
return props.menuActions?.length;
|
|
718
|
+
},
|
|
719
|
+
get fallback() {
|
|
720
|
+
return _$createComponent(Show, {
|
|
721
|
+
get when() {
|
|
722
|
+
return props.fileSelection;
|
|
723
|
+
},
|
|
724
|
+
children: selection => _$createComponent(Tooltip.Trigger, {
|
|
725
|
+
type: "button",
|
|
726
|
+
"class": "k2b-chat-composer__icon-action k2b-chat-composer__attach",
|
|
727
|
+
get ["aria-label"]() {
|
|
728
|
+
return selection().label ?? messages().attachFiles;
|
|
729
|
+
},
|
|
730
|
+
get content() {
|
|
731
|
+
return selection().label ?? messages().attachFiles;
|
|
732
|
+
},
|
|
733
|
+
get disabled() {
|
|
734
|
+
return !canSelectFiles();
|
|
735
|
+
},
|
|
736
|
+
onClick: chooseFiles,
|
|
737
|
+
get children() {
|
|
738
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", addingFiles() ? "ti ti-loader-2 k2b-spin" : "ti ti-paperclip", false));
|
|
739
|
+
}
|
|
740
|
+
})
|
|
741
|
+
});
|
|
742
|
+
},
|
|
743
|
+
get children() {
|
|
744
|
+
return addMenu("ti ti-plus", " k2b-chat-composer__attach");
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
const formatToggle = () => _$createComponent(Show, {
|
|
748
|
+
get when() {
|
|
749
|
+
return props.formatting;
|
|
750
|
+
},
|
|
751
|
+
get children() {
|
|
752
|
+
return _$createComponent(Tooltip.Trigger, {
|
|
753
|
+
type: "button",
|
|
754
|
+
"class": "k2b-chat-composer__icon-action k2b-chat-composer__format-toggle",
|
|
755
|
+
get ["aria-label"]() {
|
|
756
|
+
return messages().composerFormatting;
|
|
757
|
+
},
|
|
758
|
+
get ["aria-pressed"]() {
|
|
759
|
+
return formattingOpen();
|
|
760
|
+
},
|
|
761
|
+
get ["aria-controls"]() {
|
|
762
|
+
return formattingOpen() ? formatGroupId : undefined;
|
|
763
|
+
},
|
|
764
|
+
get content() {
|
|
765
|
+
return messages().composerFormatting;
|
|
766
|
+
},
|
|
767
|
+
onMouseDown: keepFieldFocus,
|
|
768
|
+
onClick: () => setFormattingOpen(open => !open),
|
|
769
|
+
get children() {
|
|
770
|
+
return _$ssr(_tmpl$4);
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
/** One row of fixed height. It shows every button at once, also on a phone, so nothing hides behind a scroll. */
|
|
777
|
+
const formatRow = () => _$createComponent(Show, {
|
|
778
|
+
get when() {
|
|
779
|
+
return _$memo(() => !!props.formatting)() && formattingOpen();
|
|
780
|
+
},
|
|
781
|
+
get children() {
|
|
782
|
+
return _$ssr(_tmpl$5, _$ssrAttribute("id", _$escape(formatGroupId, true), false), _$ssrAttribute("aria-label", _$escape(messages().composerFormatting, true), false), _$escape(_$createComponent(For, {
|
|
783
|
+
each: formatTools,
|
|
784
|
+
children: tool => _$createComponent(Tooltip.Trigger, {
|
|
785
|
+
type: "button",
|
|
786
|
+
"class": "k2b-chat-composer__icon-action",
|
|
787
|
+
get ["aria-label"]() {
|
|
788
|
+
return tool.label(messages());
|
|
789
|
+
},
|
|
790
|
+
get content() {
|
|
791
|
+
return tool.label(messages());
|
|
792
|
+
},
|
|
793
|
+
get disabled() {
|
|
794
|
+
return editBlocked();
|
|
795
|
+
},
|
|
796
|
+
onMouseDown: keepFieldFocus,
|
|
797
|
+
onClick: () => {
|
|
798
|
+
if (textareaRef) tool.run(textareaRef);
|
|
799
|
+
},
|
|
800
|
+
get children() {
|
|
801
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(tool.icon, true), false));
|
|
802
|
+
}
|
|
803
|
+
})
|
|
804
|
+
})));
|
|
805
|
+
}
|
|
806
|
+
});
|
|
807
|
+
const emojiButton = () => _$createComponent(Show, {
|
|
808
|
+
get when() {
|
|
809
|
+
return props.emoji;
|
|
810
|
+
},
|
|
811
|
+
children: emoji => _$createComponent(Tooltip.Trigger, {
|
|
812
|
+
type: "button",
|
|
813
|
+
"class": "k2b-chat-composer__icon-action k2b-chat-composer__emoji",
|
|
814
|
+
get ["aria-label"]() {
|
|
815
|
+
return messages().insertEmoji;
|
|
816
|
+
},
|
|
817
|
+
get content() {
|
|
818
|
+
return messages().insertEmoji;
|
|
819
|
+
},
|
|
820
|
+
get disabled() {
|
|
821
|
+
return editBlocked();
|
|
822
|
+
},
|
|
823
|
+
onMouseDown: keepFieldFocus,
|
|
824
|
+
onClick: event => {
|
|
825
|
+
const anchor = event.currentTarget;
|
|
826
|
+
reportChatFailure(() => emoji().onOpen({
|
|
827
|
+
anchor,
|
|
828
|
+
insert: insertText
|
|
829
|
+
}), props.onError);
|
|
830
|
+
},
|
|
831
|
+
get children() {
|
|
832
|
+
return _$ssr(_tmpl$6);
|
|
833
|
+
}
|
|
834
|
+
})
|
|
835
|
+
});
|
|
836
|
+
const microphoneControl = () => _$createComponent(Show, {
|
|
837
|
+
get when() {
|
|
838
|
+
return _$memo(() => !!(props.microphone?.onDictate || props.microphone?.onVoiceMessage))() ? props.microphone : undefined;
|
|
839
|
+
},
|
|
840
|
+
children: microphone => _$ssr(_tmpl$8, _$escape(_$createComponent(Tooltip.Trigger, {
|
|
841
|
+
type: "button",
|
|
842
|
+
"class": "k2b-chat-composer__icon-action k2b-chat-composer__microphone-button",
|
|
843
|
+
get ["data-state"]() {
|
|
844
|
+
return dictation() ?? undefined;
|
|
845
|
+
},
|
|
846
|
+
get disabled() {
|
|
847
|
+
return microphoneDisabled();
|
|
848
|
+
},
|
|
849
|
+
get ["aria-pressed"]() {
|
|
850
|
+
return _$memo(() => !!microphone().onDictate)() ? dictation() === "listening" : undefined;
|
|
851
|
+
},
|
|
852
|
+
get ["aria-haspopup"]() {
|
|
853
|
+
return microphone().onDictate ? undefined : "menu";
|
|
854
|
+
},
|
|
855
|
+
get ["aria-expanded"]() {
|
|
856
|
+
return _$memo(() => !!microphone().onDictate)() ? undefined : microphoneMenuOpen();
|
|
857
|
+
},
|
|
858
|
+
get ["aria-label"]() {
|
|
859
|
+
return _$memo(() => !!microphone().onDictate)() ? messages().dictate : messages().recordVoiceMessage;
|
|
860
|
+
},
|
|
861
|
+
get content() {
|
|
862
|
+
return _$memo(() => dictation() === "listening")() ? messages().stopDictation : _$memo(() => !!microphone().onDictate)() ? _$memo(() => !!microphone().onVoiceMessage)() ? messages().dictateOrHold : messages().dictate : messages().recordVoiceMessage;
|
|
863
|
+
},
|
|
864
|
+
onMouseDown: keepFieldFocus,
|
|
865
|
+
onContextMenu: event => event.preventDefault(),
|
|
866
|
+
onPointerDown: event => {
|
|
867
|
+
held = false;
|
|
868
|
+
releaseHold();
|
|
869
|
+
const record = microphone().onVoiceMessage;
|
|
870
|
+
if (event.button !== 0 || !record || dictation() === "listening") return;
|
|
871
|
+
holdTimer = setTimeout(() => {
|
|
872
|
+
// The composer may have become blocked, or recording withdrawn, during the press.
|
|
873
|
+
const current = props.microphone?.onVoiceMessage;
|
|
874
|
+
if (!current || microphoneDisabled()) return;
|
|
875
|
+
held = true;
|
|
876
|
+
reportChatFailure(current, props.onError);
|
|
877
|
+
}, microphoneHoldMs);
|
|
878
|
+
},
|
|
879
|
+
onPointerUp: releaseHold,
|
|
880
|
+
onPointerCancel: releaseHold,
|
|
881
|
+
onPointerLeave: releaseHold,
|
|
882
|
+
onClick: event => {
|
|
883
|
+
// A press that already asked for a voice message ends here; a key press never holds.
|
|
884
|
+
if (held) {
|
|
885
|
+
held = false;
|
|
886
|
+
if (event.detail > 0) return;
|
|
887
|
+
}
|
|
888
|
+
const dictate = microphone().onDictate;
|
|
889
|
+
if (dictate) {
|
|
890
|
+
reportChatFailure(dictate, props.onError);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
setMicrophoneMenuOpen(true);
|
|
894
|
+
// From the keyboard it opens the menu like a menu button: the focus moves to the first item.
|
|
895
|
+
if (event.detail === 0) {
|
|
896
|
+
queueMicrotask(() => microphoneRef?.querySelector('[role="menuitem"]:not(:disabled)')?.focus());
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
get children() {
|
|
900
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", dictation() === "listening" ? "ti ti-player-stop" : dictation() === "refining" ? "ti ti-loader-2 k2b-spin" : "ti ti-microphone", false));
|
|
901
|
+
}
|
|
902
|
+
})), _$escape(_$createComponent(Show, {
|
|
903
|
+
get when() {
|
|
904
|
+
return microphone().onVoiceMessage;
|
|
905
|
+
},
|
|
906
|
+
get children() {
|
|
907
|
+
return _$createComponent(Dropdown.Root, {
|
|
908
|
+
position: "top-left",
|
|
909
|
+
get label() {
|
|
910
|
+
return messages().microphoneOptions;
|
|
911
|
+
},
|
|
912
|
+
get items() {
|
|
913
|
+
return microphoneItems();
|
|
914
|
+
},
|
|
915
|
+
get disabled() {
|
|
916
|
+
return microphoneDisabled();
|
|
917
|
+
},
|
|
918
|
+
get open() {
|
|
919
|
+
return microphoneMenuOpen();
|
|
920
|
+
},
|
|
921
|
+
onOpenChange: setMicrophoneMenuOpen,
|
|
922
|
+
get children() {
|
|
923
|
+
return _$createComponent(Dropdown.Trigger, {
|
|
924
|
+
appearance: "plain",
|
|
925
|
+
"class": "k2b-chat-composer__icon-action k2b-chat-composer__microphone-menu",
|
|
926
|
+
get label() {
|
|
927
|
+
return messages().microphoneOptions;
|
|
928
|
+
},
|
|
929
|
+
get tooltip() {
|
|
930
|
+
return messages().microphoneOptions;
|
|
931
|
+
},
|
|
932
|
+
get children() {
|
|
933
|
+
return _$ssr(_tmpl$7);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
})))
|
|
940
|
+
});
|
|
941
|
+
const sendControl = () => _$createComponent(Show, {
|
|
942
|
+
get when() {
|
|
943
|
+
return _$memo(() => !!(running() && !hasDraft()))() && props.onStop;
|
|
944
|
+
},
|
|
945
|
+
get fallback() {
|
|
946
|
+
return _$createComponent(Tooltip.Trigger, {
|
|
947
|
+
type: "button",
|
|
948
|
+
"class": "k2b-chat-composer__send",
|
|
949
|
+
get disabled() {
|
|
950
|
+
return !canSubmit();
|
|
951
|
+
},
|
|
952
|
+
onMouseDown: event => {
|
|
953
|
+
if (conversation()) keepFieldFocus(event);
|
|
954
|
+
},
|
|
955
|
+
get ["aria-label"]() {
|
|
956
|
+
return _$memo(() => !!submitting())() ? _$memo(() => !!running())() ? _$memo(() => runningSubmitIntent() === "queue")() ? messages().queueing : messages().steering : messages().sending : _$memo(() => !!running())() ? _$memo(() => runningSubmitIntent() === "queue")() ? messages().queueMessage : messages().steerResponse : messages().sendMessage;
|
|
957
|
+
},
|
|
958
|
+
get content() {
|
|
959
|
+
return _$memo(() => !!running())() ? _$memo(() => runningSubmitIntent() === "queue")() ? messages().queueMessage : messages().steerResponse : messages().sendMessage;
|
|
960
|
+
},
|
|
961
|
+
onClick: () => void submit(),
|
|
962
|
+
get children() {
|
|
963
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", submitting() ? "ti ti-loader-2 k2b-spin" : conversation() ? "ti ti-send" : "ti ti-arrow-up", false));
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
},
|
|
967
|
+
get children() {
|
|
968
|
+
return _$createComponent(Tooltip.Trigger, {
|
|
969
|
+
type: "button",
|
|
970
|
+
"class": "k2b-chat-composer__stop",
|
|
971
|
+
get disabled() {
|
|
972
|
+
return stopping();
|
|
973
|
+
},
|
|
974
|
+
get ["aria-label"]() {
|
|
975
|
+
return _$memo(() => !!stopping())() ? messages().stopping : messages().stopResponse;
|
|
976
|
+
},
|
|
977
|
+
get content() {
|
|
978
|
+
return messages().stopResponse;
|
|
979
|
+
},
|
|
980
|
+
onClick: () => reportChatFailure(() => props.onStop?.(), props.onError),
|
|
981
|
+
get children() {
|
|
982
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", stopping() ? "ti ti-loader-2 k2b-spin" : "ti ti-player-stop", false));
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
const field = () => _$ssr(_tmpl$1, _$ssrAttribute("aria-label", _$escape(messages().messageInput, true), false), _$escape(_$createComponent(Show, {
|
|
988
|
+
get when() {
|
|
989
|
+
return mentions().length > 0;
|
|
990
|
+
},
|
|
991
|
+
get children() {
|
|
992
|
+
return _$ssr(_tmpl$9, _$escape(_$createComponent(For, {
|
|
993
|
+
get each() {
|
|
994
|
+
return chatMentionSegments(props.value, mentions());
|
|
995
|
+
},
|
|
996
|
+
children: part => _$ssr(_tmpl$10, Boolean(part.mention) ? "k2b-chat-composer__mention" : "", _$escape(part.text))
|
|
997
|
+
})));
|
|
998
|
+
}
|
|
999
|
+
})), 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() ? messages().addGuidance : conversation() ? messages().writeConversationMessage : messages().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() ? emojiMatches()[selectedCommandIndex()] : selectedCommand()) ? `${_$escape(commandListId, true)}-${_$escape(selectedCommandIndex(), true)}` : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
|
|
1000
|
+
get when() {
|
|
1001
|
+
return conversation();
|
|
1002
|
+
},
|
|
1003
|
+
get children() {
|
|
1004
|
+
return _$ssr(_tmpl$0);
|
|
1005
|
+
}
|
|
1006
|
+
})));
|
|
1007
|
+
return _$ssr(_tmpl$21, _$escape(_$createComponent(Show, {
|
|
1008
|
+
get when() {
|
|
1009
|
+
return suggestionsOpen() || hasAccessory();
|
|
1010
|
+
},
|
|
1011
|
+
get children() {
|
|
1012
|
+
return _$ssr(_tmpl$16, _$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, {
|
|
1013
|
+
get when() {
|
|
1014
|
+
return emojiOpen();
|
|
1015
|
+
},
|
|
1016
|
+
get children() {
|
|
1017
|
+
return _$ssr(_tmpl$11, _$ssrAttribute("id", _$escape(commandListId, true), false), _$ssrAttribute("aria-label", _$escape(messages().emojiSuggestions, true), false), _$escape(_$createComponent(For, {
|
|
1018
|
+
get each() {
|
|
1019
|
+
return emojiMatches();
|
|
1020
|
+
},
|
|
1021
|
+
children: (entry, index) => _$ssr(_tmpl$22, `${_$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, {
|
|
1022
|
+
get when() {
|
|
1023
|
+
return entry.shortcodes[0];
|
|
1024
|
+
},
|
|
1025
|
+
children: code => _$ssr(_tmpl$23, _$escape(code()))
|
|
1026
|
+
})))
|
|
1027
|
+
})));
|
|
1028
|
+
}
|
|
1029
|
+
})), _$escape(_$createComponent(Show, {
|
|
390
1030
|
get when() {
|
|
391
1031
|
return commandsOpen();
|
|
392
1032
|
},
|
|
393
1033
|
get children() {
|
|
394
|
-
return _$ssr(_tmpl$
|
|
1034
|
+
return _$ssr(_tmpl$15, _$ssrAttribute("id", _$escape(commandListId, true), false), _$ssrAttribute("aria-label", _$escape(messages().commands, true), false), _$escape(_$createComponent(For, {
|
|
395
1035
|
get each() {
|
|
396
1036
|
return commandMatches();
|
|
397
1037
|
},
|
|
398
|
-
children: (command, index) => _$ssr(_tmpl$
|
|
1038
|
+
children: (command, index) => _$ssr(_tmpl$24, `${_$escape(commandListId, true)}-${_$escape(index(), true)}`, _$ssrAttribute("aria-selected", _$escape(index(), true) === _$escape(selectedCommandIndex(), true), false) + _$ssrAttribute("aria-disabled", _$escape(command.disabled, true), false) + _$ssrAttribute("data-active", index() === selectedCommandIndex() ? "true" : _$escape(undefined, true), false), _$ssrAttribute("class", _$escape(command.icon ?? "ti ti-slash", true), false), _$escape(command.label ?? `/${command.name}`), _$escape(command.description))
|
|
399
1039
|
})), _$escape(_$createComponent(Show, {
|
|
400
1040
|
get when() {
|
|
401
1041
|
return searching();
|
|
402
1042
|
},
|
|
403
1043
|
get children() {
|
|
404
|
-
return _$ssr(_tmpl$
|
|
1044
|
+
return _$ssr(_tmpl$12, _$escape(messages().loading));
|
|
405
1045
|
}
|
|
406
1046
|
})), _$escape(_$createComponent(Show, {
|
|
407
1047
|
get when() {
|
|
408
1048
|
return searchError();
|
|
409
1049
|
},
|
|
410
1050
|
get children() {
|
|
411
|
-
return _$ssr(_tmpl$
|
|
1051
|
+
return _$ssr(_tmpl$13, _$escape(messages().error));
|
|
412
1052
|
}
|
|
413
1053
|
})), _$escape(_$createComponent(Show, {
|
|
414
1054
|
get when() {
|
|
415
1055
|
return _$memo(() => !!(!searching() && !searchError()))() && commandMatches().length === 0;
|
|
416
1056
|
},
|
|
417
1057
|
get children() {
|
|
418
|
-
return _$ssr(_tmpl$
|
|
1058
|
+
return _$ssr(_tmpl$14, _$escape(messages().noResults));
|
|
419
1059
|
}
|
|
420
1060
|
})));
|
|
421
1061
|
}
|
|
422
1062
|
})));
|
|
423
1063
|
}
|
|
424
|
-
})), `k2b-chat-composer ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-running", running() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-
|
|
1064
|
+
})), `k2b-chat-composer ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-running", running() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-variant", conversation() ? "conversation" : _$escape(undefined, true), false), _$ssrAttribute("aria-label", _$escape(props.label ?? messages().messageComposer, true), false), _$escape(_$createComponent(Show, {
|
|
1065
|
+
get when() {
|
|
1066
|
+
return showHint();
|
|
1067
|
+
},
|
|
1068
|
+
get children() {
|
|
1069
|
+
return _$ssr(_tmpl$17, _$escape(_$createComponent(Show, {
|
|
1070
|
+
get when() {
|
|
1071
|
+
return dictationStatus();
|
|
1072
|
+
},
|
|
1073
|
+
get fallback() {
|
|
1074
|
+
return _$ssr(_tmpl$25, _$escape(hint()));
|
|
1075
|
+
},
|
|
1076
|
+
children: status => [_$ssr(_tmpl$26, _$ssrAttribute("data-state", _$escape(dictation() ?? undefined, true), false), _$ssrAttribute("class", _$escape(status().icon, true), false), _$escape(status().text)), _$createComponent(Show, {
|
|
1077
|
+
get when() {
|
|
1078
|
+
return _$memo(() => dictation() === "refined")() ? props.microphone?.onRestoreOriginal : undefined;
|
|
1079
|
+
},
|
|
1080
|
+
children: restore => _$ssr(_tmpl$27, _$ssrAttribute("disabled", microphoneDisabled(), true), _$escape(messages().restoreOriginal))
|
|
1081
|
+
})]
|
|
1082
|
+
})));
|
|
1083
|
+
}
|
|
1084
|
+
})), _$escape(_$createComponent(Show, {
|
|
425
1085
|
get when() {
|
|
426
1086
|
return attachments().length > 0;
|
|
427
1087
|
},
|
|
428
1088
|
get children() {
|
|
429
|
-
return _$ssr(_tmpl$
|
|
1089
|
+
return _$ssr(_tmpl$18, _$ssrAttribute("aria-label", _$escape(messages().attachments, true), false), _$escape(_$createComponent(For, {
|
|
430
1090
|
get each() {
|
|
431
1091
|
return attachments();
|
|
432
1092
|
},
|
|
433
|
-
children: attachment => _$ssr(_tmpl$
|
|
1093
|
+
children: attachment => _$ssr(_tmpl$29, `k2b-chat-composer__attachment-content ${Boolean(attachment.action) ? "k2b-chat-composer__attachment-content--action" : ""}`, _$escape(_$createComponent(Show, {
|
|
434
1094
|
get when() {
|
|
435
1095
|
return attachment.href;
|
|
436
1096
|
},
|
|
437
1097
|
get fallback() {
|
|
438
|
-
return _$ssr(_tmpl$
|
|
1098
|
+
return _$ssr(_tmpl$31, _$escape(_$createComponent(Show, {
|
|
439
1099
|
get when() {
|
|
440
1100
|
return _$memo(() => attachment.kind === "image")() && attachment.previewUrl;
|
|
441
1101
|
},
|
|
442
1102
|
get fallback() {
|
|
443
|
-
return _$ssr(_tmpl$
|
|
1103
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
|
|
444
1104
|
},
|
|
445
1105
|
get children() {
|
|
446
|
-
return _$ssr(_tmpl$
|
|
1106
|
+
return _$ssr(_tmpl$30, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
|
|
447
1107
|
}
|
|
448
1108
|
})), _$escape(renderAttachmentCopy(attachment)));
|
|
449
1109
|
},
|
|
450
|
-
children: href => _$ssr(_tmpl$
|
|
1110
|
+
children: href => _$ssr(_tmpl$32, _$ssrAttribute("href", _$escape(href(), true), false), _$ssrAttribute("aria-label", _$escape(messages().openInNewTab({
|
|
451
1111
|
name: attachment.name
|
|
452
1112
|
}), true), false), _$escape(_$createComponent(Show, {
|
|
453
1113
|
get when() {
|
|
454
1114
|
return _$memo(() => attachment.kind === "image")() && attachment.previewUrl;
|
|
455
1115
|
},
|
|
456
1116
|
get fallback() {
|
|
457
|
-
return _$ssr(_tmpl$
|
|
1117
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
|
|
458
1118
|
},
|
|
459
1119
|
get children() {
|
|
460
|
-
return _$ssr(_tmpl$
|
|
1120
|
+
return _$ssr(_tmpl$30, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
|
|
461
1121
|
}
|
|
462
1122
|
})), _$escape(renderAttachmentCopy(attachment)))
|
|
463
1123
|
})), _$escape(_$createComponent(Show, {
|
|
464
1124
|
get when() {
|
|
465
1125
|
return attachment.action;
|
|
466
1126
|
},
|
|
467
|
-
children: action => _$ssr(_tmpl$
|
|
1127
|
+
children: action => _$ssr(_tmpl$33, _$ssrAttribute("disabled", blocked() || action().disabled, true), _$escape(_$createComponent(Show, {
|
|
468
1128
|
get when() {
|
|
469
1129
|
return action().icon;
|
|
470
1130
|
},
|
|
471
|
-
children: icon => _$ssr(_tmpl$
|
|
1131
|
+
children: icon => _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(icon(), true), false))
|
|
472
1132
|
})), _$escape(action().label))
|
|
473
1133
|
})), _$escape(_$createComponent(Show, {
|
|
474
1134
|
get when() {
|
|
475
1135
|
return props.onAttachmentsChange;
|
|
476
1136
|
},
|
|
477
1137
|
get children() {
|
|
478
|
-
return _$ssr(_tmpl$
|
|
1138
|
+
return _$ssr(_tmpl$28, _$ssrAttribute("aria-label", _$escape(messages().removeNamed({
|
|
479
1139
|
name: attachment.name
|
|
480
1140
|
}), true), false), _$ssrAttribute("disabled", blocked(), true));
|
|
481
1141
|
}
|
|
482
1142
|
})))
|
|
483
1143
|
})));
|
|
484
1144
|
}
|
|
485
|
-
})), _$ssrAttribute("aria-label", _$escape(messages().messageInput, true), false), _$escape(_$createComponent(Show, {
|
|
486
|
-
get when() {
|
|
487
|
-
return dragActive();
|
|
488
|
-
},
|
|
489
|
-
get children() {
|
|
490
|
-
return _$ssr(_tmpl$8, _$escape(messages().dropFilesToAttach));
|
|
491
|
-
}
|
|
492
|
-
})), _$escape(_$createComponent(Show, {
|
|
493
|
-
get when() {
|
|
494
|
-
return mentions().length > 0;
|
|
495
|
-
},
|
|
496
|
-
get children() {
|
|
497
|
-
return _$ssr(_tmpl$9, _$escape(_$createComponent(For, {
|
|
498
|
-
get each() {
|
|
499
|
-
return chatMentionSegments(props.value, mentions());
|
|
500
|
-
},
|
|
501
|
-
children: part => _$ssr(_tmpl$18, Boolean(part.mention) ? "k2b-chat-composer__mention" : "", _$escape(part.text))
|
|
502
|
-
})));
|
|
503
|
-
}
|
|
504
|
-
})), mentions().length > 0 ? "k2b-chat-composer__textarea--highlighted" : "", _$ssrAttribute("value", _$escape(props.value, true), false), _$ssrAttribute("disabled", blocked(), true) + _$ssrAttribute("placeholder", _$escape(props.placeholder ?? (running() ? messages().addGuidance : messages().writeMessage), true), false) + _$ssrAttribute("aria-label", _$escape(props.inputLabel ?? messages().message, true), false) + _$ssrAttribute("role", commandsOpen() ? "combobox" : _$escape(undefined, true), false) + _$ssrAttribute("aria-autocomplete", commandsOpen() ? "list" : _$escape(undefined, true), false) + _$ssrAttribute("aria-controls", commandsOpen() ? _$escape(commandListId, true) : _$escape(undefined, true), false) + _$ssrAttribute("aria-expanded", commandsOpen() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("aria-activedescendant", selectedCommand() ? `${_$escape(commandListId, true)}-${_$escape(selectedCommandIndex(), true)}` : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
|
|
505
|
-
get when() {
|
|
506
|
-
return props.error;
|
|
507
|
-
},
|
|
508
|
-
get children() {
|
|
509
|
-
return _$ssr(_tmpl$0, _$escape(props.error));
|
|
510
|
-
}
|
|
511
1145
|
})), _$escape(_$createComponent(Show, {
|
|
512
1146
|
get when() {
|
|
513
|
-
return
|
|
1147
|
+
return conversation();
|
|
514
1148
|
},
|
|
515
1149
|
get fallback() {
|
|
516
|
-
return [
|
|
1150
|
+
return [field(), _$createComponent(Show, {
|
|
517
1151
|
get when() {
|
|
518
|
-
return
|
|
1152
|
+
return props.error;
|
|
519
1153
|
},
|
|
520
1154
|
get children() {
|
|
521
|
-
return _$
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
1155
|
+
return _$ssr(_tmpl$19, _$escape(props.error));
|
|
1156
|
+
}
|
|
1157
|
+
}), formatRow(), _$ssr(_tmpl$34, _$escape(_$createComponent(Show, {
|
|
1158
|
+
get when() {
|
|
1159
|
+
return props.footerContent;
|
|
1160
|
+
},
|
|
1161
|
+
get fallback() {
|
|
1162
|
+
return [_$ssr(_tmpl$35, _$escape(props.footerTools), _$escape(_$createComponent(Show, {
|
|
1163
|
+
get when() {
|
|
1164
|
+
return hasAddMenu();
|
|
528
1165
|
},
|
|
529
|
-
get
|
|
530
|
-
return
|
|
1166
|
+
get children() {
|
|
1167
|
+
return addMenu("ti ti-plus");
|
|
1168
|
+
}
|
|
1169
|
+
})), _$escape(fileInput()), _$escape(formatToggle()), _$escape(emojiButton()), _$escape(_$createComponent(Show, {
|
|
1170
|
+
get when() {
|
|
1171
|
+
return (props.models?.length ?? 0) > 0;
|
|
531
1172
|
},
|
|
532
1173
|
get children() {
|
|
533
|
-
return _$createComponent(
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
get label() {
|
|
537
|
-
return messages().addToChat;
|
|
1174
|
+
return _$createComponent(SelectChip, {
|
|
1175
|
+
get ["aria-label"]() {
|
|
1176
|
+
return messages().chooseModel;
|
|
538
1177
|
},
|
|
539
|
-
|
|
540
|
-
|
|
1178
|
+
position: "top-right",
|
|
1179
|
+
"class": "k2b-chat-composer__model",
|
|
1180
|
+
menuWidth: "15rem",
|
|
1181
|
+
get placeholder() {
|
|
1182
|
+
return messages().model;
|
|
541
1183
|
},
|
|
542
|
-
|
|
543
|
-
|
|
1184
|
+
value: () => props.selectedModelId ?? "",
|
|
1185
|
+
get options() {
|
|
1186
|
+
return (props.models ?? []).map(model => ({
|
|
1187
|
+
value: model.id,
|
|
1188
|
+
label: model.label,
|
|
1189
|
+
description: model.description,
|
|
1190
|
+
icon: model.icon,
|
|
1191
|
+
image: model.image
|
|
1192
|
+
}));
|
|
1193
|
+
},
|
|
1194
|
+
get disabled() {
|
|
1195
|
+
return blocked() || running() || !props.onModelChange;
|
|
1196
|
+
},
|
|
1197
|
+
onValueChange: modelId => {
|
|
1198
|
+
props.onModelChange?.(modelId);
|
|
1199
|
+
queueMicrotask(focus);
|
|
544
1200
|
}
|
|
545
1201
|
});
|
|
546
1202
|
}
|
|
547
|
-
})
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
get when() {
|
|
551
|
-
return props.fileSelection;
|
|
552
|
-
},
|
|
553
|
-
get children() {
|
|
554
|
-
return _$ssr(_tmpl$20, _$ssrAttribute("accept", _$escape(props.fileSelection?.accept, true), false), _$ssrAttribute("multiple", props.fileSelection?.multiple ?? true, true));
|
|
555
|
-
}
|
|
556
|
-
})), _$escape(_$createComponent(Show, {
|
|
557
|
-
get when() {
|
|
558
|
-
return (props.models?.length ?? 0) > 0;
|
|
559
|
-
},
|
|
560
|
-
get children() {
|
|
561
|
-
return _$createComponent(SelectChip, {
|
|
562
|
-
get ["aria-label"]() {
|
|
563
|
-
return messages().chooseModel;
|
|
564
|
-
},
|
|
565
|
-
position: "top-right",
|
|
566
|
-
"class": "k2b-chat-composer__model",
|
|
567
|
-
menuWidth: "15rem",
|
|
568
|
-
get placeholder() {
|
|
569
|
-
return messages().model;
|
|
570
|
-
},
|
|
571
|
-
value: () => props.selectedModelId ?? "",
|
|
572
|
-
get options() {
|
|
573
|
-
return (props.models ?? []).map(model => ({
|
|
574
|
-
value: model.id,
|
|
575
|
-
label: model.label,
|
|
576
|
-
description: model.description,
|
|
577
|
-
icon: model.icon,
|
|
578
|
-
image: model.image
|
|
579
|
-
}));
|
|
1203
|
+
})), _$escape(props.modelDetails)), _$ssr(_tmpl$36, _$escape(_$createComponent(For, {
|
|
1204
|
+
get each() {
|
|
1205
|
+
return props.contextActions;
|
|
580
1206
|
},
|
|
581
|
-
|
|
582
|
-
|
|
1207
|
+
children: action => _$createComponent(Tooltip.Trigger, {
|
|
1208
|
+
type: "button",
|
|
1209
|
+
"class": "k2b-chat-composer__icon-action",
|
|
1210
|
+
get ["data-tone"]() {
|
|
1211
|
+
return action.variant === "danger" ? "danger" : undefined;
|
|
1212
|
+
},
|
|
1213
|
+
get disabled() {
|
|
1214
|
+
return action.disabled;
|
|
1215
|
+
},
|
|
1216
|
+
get ["aria-pressed"]() {
|
|
1217
|
+
return action.pressed;
|
|
1218
|
+
},
|
|
1219
|
+
get ["aria-label"]() {
|
|
1220
|
+
return action.label;
|
|
1221
|
+
},
|
|
1222
|
+
get content() {
|
|
1223
|
+
return action.label;
|
|
1224
|
+
},
|
|
1225
|
+
onClick: () => reportChatFailure(() => executeChatAction(action), props.onError),
|
|
1226
|
+
get children() {
|
|
1227
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(action.icon ?? "ti ti-dots", true), false));
|
|
1228
|
+
}
|
|
1229
|
+
})
|
|
1230
|
+
})), _$escape(_$createComponent(Show, {
|
|
1231
|
+
get when() {
|
|
1232
|
+
return _$memo(() => !!hasContextUsage())() ? props.contextUsage ?? {} : undefined;
|
|
583
1233
|
},
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
},
|
|
594
|
-
children: action => _$createComponent(Tooltip.Trigger, {
|
|
595
|
-
type: "button",
|
|
596
|
-
"class": "k2b-chat-composer__icon-action",
|
|
597
|
-
get ["data-tone"]() {
|
|
598
|
-
return action.variant === "danger" ? "danger" : undefined;
|
|
599
|
-
},
|
|
600
|
-
get disabled() {
|
|
601
|
-
return action.disabled;
|
|
602
|
-
},
|
|
603
|
-
get ["aria-pressed"]() {
|
|
604
|
-
return action.pressed;
|
|
605
|
-
},
|
|
606
|
-
get ["aria-label"]() {
|
|
607
|
-
return action.label;
|
|
608
|
-
},
|
|
609
|
-
get content() {
|
|
610
|
-
return action.label;
|
|
611
|
-
},
|
|
612
|
-
onClick: () => reportChatFailure(() => executeChatAction(action), props.onError),
|
|
613
|
-
get children() {
|
|
614
|
-
return _$ssr(_tmpl$15, _$ssrAttribute("class", _$escape(action.icon ?? "ti ti-dots", true), false));
|
|
615
|
-
}
|
|
616
|
-
})
|
|
617
|
-
})), _$escape(_$createComponent(Show, {
|
|
618
|
-
get when() {
|
|
619
|
-
return _$memo(() => !!hasContextUsage())() ? props.contextUsage ?? {} : undefined;
|
|
1234
|
+
children: usage => _$createComponent(ContextUsage, _$mergeProps(usage, {
|
|
1235
|
+
get action() {
|
|
1236
|
+
return props.contextPopupAction;
|
|
1237
|
+
},
|
|
1238
|
+
get onActionError() {
|
|
1239
|
+
return props.onError;
|
|
1240
|
+
}
|
|
1241
|
+
}))
|
|
1242
|
+
})), _$escape(props.submitTools), _$escape(microphoneControl()), _$escape(sendControl()))];
|
|
620
1243
|
},
|
|
621
|
-
children:
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
return props.onError;
|
|
627
|
-
}
|
|
628
|
-
}))
|
|
629
|
-
})), _$escape(props.submitTools), _$escape(_$createComponent(Show, {
|
|
1244
|
+
children: content => content()
|
|
1245
|
+
})))];
|
|
1246
|
+
},
|
|
1247
|
+
get children() {
|
|
1248
|
+
return [_$createComponent(Show, {
|
|
630
1249
|
get when() {
|
|
631
|
-
return
|
|
632
|
-
},
|
|
633
|
-
get fallback() {
|
|
634
|
-
return _$createComponent(Tooltip.Trigger, {
|
|
635
|
-
type: "button",
|
|
636
|
-
"class": "k2b-chat-composer__send",
|
|
637
|
-
get disabled() {
|
|
638
|
-
return !canSubmit();
|
|
639
|
-
},
|
|
640
|
-
get ["aria-label"]() {
|
|
641
|
-
return _$memo(() => !!submitting())() ? _$memo(() => !!running())() ? _$memo(() => runningSubmitIntent() === "queue")() ? messages().queueing : messages().steering : messages().sending : _$memo(() => !!running())() ? _$memo(() => runningSubmitIntent() === "queue")() ? messages().queueMessage : messages().steerResponse : messages().sendMessage;
|
|
642
|
-
},
|
|
643
|
-
get content() {
|
|
644
|
-
return _$memo(() => !!running())() ? _$memo(() => runningSubmitIntent() === "queue")() ? messages().queueMessage : messages().steerResponse : messages().sendMessage;
|
|
645
|
-
},
|
|
646
|
-
onClick: () => void submit(),
|
|
647
|
-
get children() {
|
|
648
|
-
return _$ssr(_tmpl$15, _$ssrAttribute("class", submitting() ? "ti ti-loader-2 k2b-spin" : "ti ti-arrow-up", false));
|
|
649
|
-
}
|
|
650
|
-
});
|
|
1250
|
+
return props.error;
|
|
651
1251
|
},
|
|
652
1252
|
get children() {
|
|
653
|
-
return _$
|
|
654
|
-
type: "button",
|
|
655
|
-
"class": "k2b-chat-composer__stop",
|
|
656
|
-
get disabled() {
|
|
657
|
-
return stopping();
|
|
658
|
-
},
|
|
659
|
-
get ["aria-label"]() {
|
|
660
|
-
return _$memo(() => !!stopping())() ? messages().stopping : messages().stopResponse;
|
|
661
|
-
},
|
|
662
|
-
get content() {
|
|
663
|
-
return messages().stopResponse;
|
|
664
|
-
},
|
|
665
|
-
onClick: () => reportChatFailure(() => props.onStop?.(), props.onError),
|
|
666
|
-
get children() {
|
|
667
|
-
return _$ssr(_tmpl$15, _$ssrAttribute("class", stopping() ? "ti ti-loader-2 k2b-spin" : "ti ti-player-stop", false));
|
|
668
|
-
}
|
|
669
|
-
});
|
|
1253
|
+
return _$ssr(_tmpl$19, _$escape(props.error));
|
|
670
1254
|
}
|
|
671
|
-
})))];
|
|
1255
|
+
}), formatRow(), _$ssr(_tmpl$20, _$escape(attachControl()), _$escape(fileInput()), _$escape(field()), _$escape(formatToggle()), _$escape(emojiButton()), _$escape(microphoneControl()), _$escape(sendControl()))];
|
|
1256
|
+
}
|
|
1257
|
+
})), _$escape(_$createComponent(Show, {
|
|
1258
|
+
get when() {
|
|
1259
|
+
return props.fileSelection;
|
|
672
1260
|
},
|
|
673
|
-
children:
|
|
1261
|
+
children: selection => _$createComponent(FileDropTarget, {
|
|
1262
|
+
get label() {
|
|
1263
|
+
return messages().dropFilesToAttach;
|
|
1264
|
+
},
|
|
1265
|
+
get accept() {
|
|
1266
|
+
return selection().accept;
|
|
1267
|
+
},
|
|
1268
|
+
get multiple() {
|
|
1269
|
+
return selection().multiple;
|
|
1270
|
+
},
|
|
1271
|
+
get disabled() {
|
|
1272
|
+
return !canSelectFiles();
|
|
1273
|
+
},
|
|
1274
|
+
onDrop: files => void runFiles(files)
|
|
1275
|
+
})
|
|
674
1276
|
})));
|
|
675
1277
|
}
|
|
676
1278
|
//# sourceMappingURL=ChatComposer.js.map
|