@k2b/ui 0.28.0 → 0.30.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 +2 -2
- package/dist/browser/actions/ContextMenu.js +5 -0
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/DragAndDrop.js +89 -0
- package/dist/browser/actions/DragAndDrop.js.map +1 -0
- package/dist/browser/actions/Dropdown.js +6 -3
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +137 -7
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/actions/GestureMenu.js +26 -3
- package/dist/browser/actions/GestureMenu.js.map +1 -1
- package/dist/browser/actions/SegmentedControl.js +5 -9
- package/dist/browser/actions/SegmentedControl.js.map +1 -1
- package/dist/browser/actions/SpotlightSearch.js +6 -3
- package/dist/browser/actions/SpotlightSearch.js.map +1 -1
- package/dist/browser/actions/Tabs.js +5 -2
- package/dist/browser/actions/Tabs.js.map +1 -1
- package/dist/browser/actions/ViewTabs.js +294 -0
- package/dist/browser/actions/ViewTabs.js.map +1 -0
- package/dist/browser/actions/drag-and-drop-messages.js +75 -0
- package/dist/browser/actions/drag-and-drop-messages.js.map +1 -0
- package/dist/browser/actions/drag-and-drop.js +692 -0
- package/dist/browser/actions/drag-and-drop.js.map +1 -0
- package/dist/browser/actions/filter-messages.js +6 -2
- package/dist/browser/actions/filter-messages.js.map +1 -1
- package/dist/browser/actions/index.js +3 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +1229 -605
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/ChatDecision.js +814 -0
- package/dist/browser/chat/ChatDecision.js.map +1 -0
- package/dist/browser/chat/ChatPrimitives.js +292 -153
- package/dist/browser/chat/ChatPrimitives.js.map +1 -1
- package/dist/browser/chat/ChatTimeline.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +14 -0
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/command-search.js +35 -17
- package/dist/browser/chat/command-search.js.map +1 -1
- package/dist/browser/chat/index.js +10 -3
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/chat/types.js.map +1 -1
- package/dist/browser/content/Calendar.js +146 -119
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/CalendarWeekView.js +291 -266
- package/dist/browser/content/CalendarWeekView.js.map +1 -1
- package/dist/browser/content/Chart.js +54 -71
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/DataTable.js +224 -155
- package/dist/browser/content/DataTable.js.map +1 -1
- package/dist/browser/content/FileBrowser.js +2 -2
- package/dist/browser/content/FileBrowser.js.map +1 -1
- package/dist/browser/content/FileTree.js +42 -36
- package/dist/browser/content/FileTree.js.map +1 -1
- package/dist/browser/content/FileTypeIcon.js +72 -0
- package/dist/browser/content/FileTypeIcon.js.map +1 -0
- package/dist/browser/content/FileView.js +2 -2
- package/dist/browser/content/FileView.js.map +1 -1
- package/dist/browser/content/ReferenceChip.js +162 -0
- package/dist/browser/content/ReferenceChip.js.map +1 -0
- package/dist/browser/content/calendar-pointer.js +9 -0
- package/dist/browser/content/calendar-pointer.js.map +1 -1
- package/dist/browser/content/calendar-time-view.js +6 -3
- package/dist/browser/content/calendar-time-view.js.map +1 -1
- package/dist/browser/content/data-table-messages.js +4 -2
- package/dist/browser/content/data-table-messages.js.map +1 -1
- package/dist/browser/content/index.js +2 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/feedback/MovedHint.js +197 -0
- package/dist/browser/feedback/MovedHint.js.map +1 -0
- package/dist/browser/feedback/dialog-core.js +66 -9
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/feedback/index.js +1 -0
- package/dist/browser/feedback/index.js.map +1 -1
- package/dist/browser/feedback/prompts.js +6 -1
- package/dist/browser/feedback/prompts.js.map +1 -1
- package/dist/browser/inputs/DatePicker.js +337 -212
- package/dist/browser/inputs/DatePicker.js.map +1 -1
- package/dist/browser/inputs/date-picker.js +59 -5
- package/dist/browser/inputs/date-picker.js.map +1 -1
- package/dist/browser/intl/messages.js +12 -0
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/intl/weekend.js +39 -0
- package/dist/browser/intl/weekend.js.map +1 -0
- package/dist/browser/layout/AppOverview.js +1 -2
- package/dist/browser/layout/AppOverview.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +947 -531
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/PageTitle.js +3 -2
- package/dist/browser/layout/PageTitle.js.map +1 -1
- package/dist/browser/layout/PanelDialog.js +88 -86
- package/dist/browser/layout/PanelDialog.js.map +1 -1
- package/dist/browser/layout/ResizeSeparator.js +81 -0
- package/dist/browser/layout/ResizeSeparator.js.map +1 -0
- package/dist/browser/layout/SettingsModal.js +2 -2
- package/dist/browser/layout/SettingsModal.js.map +1 -1
- package/dist/browser/layout/SidebarSwitcher.js +19 -11
- package/dist/browser/layout/SidebarSwitcher.js.map +1 -1
- package/dist/browser/layout/TabBar.js +16 -13
- package/dist/browser/layout/TabBar.js.map +1 -1
- package/dist/browser/layout/app-host-width.js +44 -0
- package/dist/browser/layout/app-host-width.js.map +1 -0
- package/dist/browser/layout/app-workspace-controller.js +337 -44
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/index.js +4 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/layout/resize-separator.js +90 -0
- package/dist/browser/layout/resize-separator.js.map +1 -0
- package/dist/browser/layout/workspace-messages.js +12 -2
- package/dist/browser/layout/workspace-messages.js.map +1 -1
- package/dist/browser/surfaces/LinkCard.js +1 -1
- package/dist/browser/surfaces/LinkCard.js.map +1 -1
- package/dist/browser/surfaces/Placeholder.js +45 -11
- package/dist/browser/surfaces/Placeholder.js.map +1 -1
- package/dist/browser/surfaces/StatCell.js +23 -0
- package/dist/browser/surfaces/StatCell.js.map +1 -1
- package/dist/browser/widgets/Widget.js +1 -1
- package/dist/browser/widgets/Widget.js.map +1 -1
- package/dist/ssr/actions/ContextMenu.js +5 -0
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/DragAndDrop.js +63 -0
- package/dist/ssr/actions/DragAndDrop.js.map +1 -0
- package/dist/ssr/actions/Dropdown.js +5 -2
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +59 -7
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/actions/GestureMenu.js +26 -3
- package/dist/ssr/actions/GestureMenu.js.map +1 -1
- package/dist/ssr/actions/SegmentedControl.js +1 -2
- package/dist/ssr/actions/SegmentedControl.js.map +1 -1
- package/dist/ssr/actions/SpotlightSearch.js +2 -2
- package/dist/ssr/actions/SpotlightSearch.js.map +1 -1
- package/dist/ssr/actions/Tabs.js +2 -2
- package/dist/ssr/actions/Tabs.js.map +1 -1
- package/dist/ssr/actions/ViewTabs.js +211 -0
- package/dist/ssr/actions/ViewTabs.js.map +1 -0
- package/dist/ssr/actions/drag-and-drop-messages.js +75 -0
- package/dist/ssr/actions/drag-and-drop-messages.js.map +1 -0
- package/dist/ssr/actions/drag-and-drop.js +692 -0
- package/dist/ssr/actions/drag-and-drop.js.map +1 -0
- package/dist/ssr/actions/filter-messages.js +6 -2
- package/dist/ssr/actions/filter-messages.js.map +1 -1
- package/dist/ssr/actions/index.js +3 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +668 -136
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/ChatDecision.js +479 -0
- package/dist/ssr/chat/ChatDecision.js.map +1 -0
- package/dist/ssr/chat/ChatPrimitives.js +95 -24
- package/dist/ssr/chat/ChatPrimitives.js.map +1 -1
- package/dist/ssr/chat/ChatTimeline.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +14 -0
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/command-search.js +35 -17
- package/dist/ssr/chat/command-search.js.map +1 -1
- package/dist/ssr/chat/index.js +10 -3
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/chat/types.js.map +1 -1
- package/dist/ssr/content/Calendar.js +112 -103
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/CalendarWeekView.js +42 -28
- package/dist/ssr/content/CalendarWeekView.js.map +1 -1
- package/dist/ssr/content/Chart.js +19 -23
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/DataTable.js +78 -31
- package/dist/ssr/content/DataTable.js.map +1 -1
- package/dist/ssr/content/FileBrowser.js +2 -2
- package/dist/ssr/content/FileBrowser.js.map +1 -1
- package/dist/ssr/content/FileTree.js +21 -14
- package/dist/ssr/content/FileTree.js.map +1 -1
- package/dist/ssr/content/FileTypeIcon.js +50 -0
- package/dist/ssr/content/FileTypeIcon.js.map +1 -0
- package/dist/ssr/content/FileView.js +2 -2
- package/dist/ssr/content/FileView.js.map +1 -1
- package/dist/ssr/content/ReferenceChip.js +121 -0
- package/dist/ssr/content/ReferenceChip.js.map +1 -0
- package/dist/ssr/content/calendar-pointer.js +9 -0
- package/dist/ssr/content/calendar-pointer.js.map +1 -1
- package/dist/ssr/content/calendar-time-view.js +6 -3
- package/dist/ssr/content/calendar-time-view.js.map +1 -1
- package/dist/ssr/content/data-table-messages.js +4 -2
- package/dist/ssr/content/data-table-messages.js.map +1 -1
- package/dist/ssr/content/index.js +2 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/feedback/MovedHint.js +166 -0
- package/dist/ssr/feedback/MovedHint.js.map +1 -0
- package/dist/ssr/feedback/dialog-core.js +66 -9
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/feedback/index.js +1 -0
- package/dist/ssr/feedback/index.js.map +1 -1
- package/dist/ssr/feedback/prompts.js +6 -1
- package/dist/ssr/feedback/prompts.js.map +1 -1
- package/dist/ssr/inputs/DatePicker.js +138 -69
- package/dist/ssr/inputs/DatePicker.js.map +1 -1
- package/dist/ssr/inputs/date-picker.js +59 -5
- package/dist/ssr/inputs/date-picker.js.map +1 -1
- package/dist/ssr/intl/messages.js +12 -0
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/intl/weekend.js +39 -0
- package/dist/ssr/intl/weekend.js.map +1 -0
- package/dist/ssr/layout/AppOverview.js +1 -2
- package/dist/ssr/layout/AppOverview.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +457 -116
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/PageTitle.js +3 -2
- package/dist/ssr/layout/PageTitle.js.map +1 -1
- package/dist/ssr/layout/PanelDialog.js +7 -6
- package/dist/ssr/layout/PanelDialog.js.map +1 -1
- package/dist/ssr/layout/ResizeSeparator.js +45 -0
- package/dist/ssr/layout/ResizeSeparator.js.map +1 -0
- package/dist/ssr/layout/SettingsModal.js +2 -2
- package/dist/ssr/layout/SettingsModal.js.map +1 -1
- package/dist/ssr/layout/SidebarSwitcher.js +19 -11
- package/dist/ssr/layout/SidebarSwitcher.js.map +1 -1
- package/dist/ssr/layout/TabBar.js +2 -2
- package/dist/ssr/layout/TabBar.js.map +1 -1
- package/dist/ssr/layout/app-host-width.js +44 -0
- package/dist/ssr/layout/app-host-width.js.map +1 -0
- package/dist/ssr/layout/app-workspace-controller.js +337 -44
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/index.js +4 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/layout/resize-separator.js +90 -0
- package/dist/ssr/layout/resize-separator.js.map +1 -0
- package/dist/ssr/layout/workspace-messages.js +12 -2
- package/dist/ssr/layout/workspace-messages.js.map +1 -1
- package/dist/ssr/surfaces/LinkCard.js +1 -1
- package/dist/ssr/surfaces/LinkCard.js.map +1 -1
- package/dist/ssr/surfaces/Placeholder.js +25 -6
- package/dist/ssr/surfaces/Placeholder.js.map +1 -1
- package/dist/ssr/surfaces/StatCell.js +23 -0
- package/dist/ssr/surfaces/StatCell.js.map +1 -1
- package/dist/ssr/widgets/Widget.js +1 -1
- package/dist/ssr/widgets/Widget.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/ContextMenu.d.ts +1 -0
- package/dist/types/actions/DragAndDrop.d.ts +29 -0
- package/dist/types/actions/Dropdown.d.ts +4 -0
- package/dist/types/actions/FilterChip.d.ts +22 -0
- package/dist/types/actions/ViewTabs.d.ts +30 -0
- package/dist/types/actions/drag-and-drop-messages.d.ts +35 -0
- package/dist/types/actions/drag-and-drop.d.ts +36 -0
- package/dist/types/actions/filter-messages.d.ts +2 -0
- package/dist/types/actions/index.d.ts +6 -2
- package/dist/types/chat/ChatComposer.d.ts +71 -1
- package/dist/types/chat/ChatDecision.d.ts +149 -0
- package/dist/types/chat/ChatPrimitives.d.ts +14 -1
- package/dist/types/chat/ChatTimeline.d.ts +2 -1
- package/dist/types/chat/chat-messages.d.ts +7 -0
- package/dist/types/chat/command-search.d.ts +5 -0
- package/dist/types/chat/index.d.ts +28 -5
- package/dist/types/chat/types.d.ts +54 -1
- package/dist/types/content/Chart.d.ts +9 -3
- package/dist/types/content/DataTable.d.ts +3 -0
- package/dist/types/content/FileTypeIcon.d.ts +27 -0
- package/dist/types/content/ReferenceChip.d.ts +49 -0
- package/dist/types/content/calendar-pointer.d.ts +6 -0
- package/dist/types/content/data-table-messages.d.ts +1 -0
- package/dist/types/content/index.d.ts +3 -0
- package/dist/types/feedback/MovedHint.d.ts +25 -0
- package/dist/types/feedback/dialog-core.d.ts +5 -2
- package/dist/types/feedback/index.d.ts +2 -0
- package/dist/types/feedback/prompts.d.ts +2 -0
- package/dist/types/inputs/DatePicker.d.ts +7 -0
- package/dist/types/inputs/date-picker.d.ts +25 -1
- package/dist/types/intl/messages.d.ts +6 -0
- package/dist/types/intl/weekend.d.ts +12 -0
- package/dist/types/layout/AppWorkspace.d.ts +48 -10
- package/dist/types/layout/ResizeSeparator.d.ts +9 -0
- package/dist/types/layout/TabBar.d.ts +7 -0
- package/dist/types/layout/app-host-width.d.ts +6 -0
- package/dist/types/layout/app-workspace-controller.d.ts +2 -0
- package/dist/types/layout/index.d.ts +5 -2
- package/dist/types/layout/resize-separator.d.ts +18 -0
- package/dist/types/layout/workspace-messages.d.ts +5 -0
- package/dist/types/surfaces/Placeholder.d.ts +2 -1
- package/dist/types/surfaces/StatCell.d.ts +6 -0
- package/package.json +5 -5
|
@@ -17,42 +17,44 @@ var _tmpl$ = ["<span><strong", ">", "</strong></span>"],
|
|
|
17
17
|
_tmpl$0 = "<textarea class=\"k2b-chat-composer__measure\" rows=\"1\" tabindex=\"-1\" aria-hidden=\"true\" readonly></textarea>",
|
|
18
18
|
_tmpl$1 = ["<div class=\"k2b-chat-composer__input\" role=\"group\"", ">", "<textarea class=\"", "\" rows=\"1\"", "", "></textarea>", "</div>"],
|
|
19
19
|
_tmpl$10 = ["<span class=\"", "\">", "</span>"],
|
|
20
|
-
_tmpl$11 = ["<small", ">", "</small>"],
|
|
20
|
+
_tmpl$11 = ["<span class=\"k2b-chat-composer__command-detail\"", "><small", ">", "</small><small", "><i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i>", "</small></span>"],
|
|
21
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
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
23
|
_tmpl$14 = ["<b>", "</b>"],
|
|
24
|
-
_tmpl$15 = ["<
|
|
25
|
-
_tmpl$16 = ["<div
|
|
26
|
-
_tmpl$17 = ["<
|
|
27
|
-
_tmpl$18 = ["<div role=\"status\">", "</div>"],
|
|
28
|
-
_tmpl$19 = ["<div
|
|
29
|
-
_tmpl$20 = ["<div
|
|
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 = ["<div class=\"k2b-chat-
|
|
35
|
-
_tmpl$26 = ["<
|
|
36
|
-
_tmpl$27 = ["<
|
|
37
|
-
_tmpl$28 = "<
|
|
38
|
-
_tmpl$29 = "<
|
|
39
|
-
_tmpl$30 =
|
|
40
|
-
_tmpl$31 = ["<
|
|
41
|
-
_tmpl$32 =
|
|
42
|
-
_tmpl$33 = ["<
|
|
43
|
-
_tmpl$34 = ["<
|
|
44
|
-
_tmpl$35 = ["<
|
|
45
|
-
_tmpl$36 = ["<
|
|
46
|
-
_tmpl$37 = ["<div class=\"k2b-chat-composer__attachment
|
|
47
|
-
_tmpl$38 = ["<
|
|
48
|
-
_tmpl$39 = ["<
|
|
49
|
-
_tmpl$40 = ["<
|
|
50
|
-
_tmpl$41 = ["<
|
|
51
|
-
_tmpl$42 = ["<
|
|
52
|
-
_tmpl$43 = ["<
|
|
53
|
-
_tmpl$44 = ["<div class=\"k2b-chat-
|
|
54
|
-
_tmpl$45 = ["<span
|
|
55
|
-
|
|
24
|
+
_tmpl$15 = ["<small", ">", "</small>"],
|
|
25
|
+
_tmpl$16 = ["<div class=\"k2b-chat-composer-accessory\"><div", " class=\"k2b-chat-composer__commands\" role=\"listbox\"", ">", "</div></div>"],
|
|
26
|
+
_tmpl$17 = ["<label class=\"k2b-chat-composer__command-search\"><i class=\"ti ti-search\" aria-hidden=\"true\"></i><input type=\"text\" role=\"combobox\"", " aria-autocomplete=\"list\"", " aria-expanded=\"true\"", " autocomplete=\"off\" autocapitalize=\"off\" spellcheck=\"false\"", "></label>"],
|
|
27
|
+
_tmpl$18 = ["<div role=\"status\" class=\"k2b-chat-composer__loading\"><i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i><strong>", "</strong></div>"],
|
|
28
|
+
_tmpl$19 = ["<div role=\"status\"><i class=\"ti ti-alert-circle\"></i> ", "</div>"],
|
|
29
|
+
_tmpl$20 = ["<div role=\"status\">", "</div>"],
|
|
30
|
+
_tmpl$21 = ["<div class=\"k2b-chat-composer-accessory\" data-commands", ">", "<div", " class=\"k2b-chat-composer__commands\" role=\"listbox\"", ">", "", "", "", "", "</div></div>"],
|
|
31
|
+
_tmpl$22 = ["<div class=\"k2b-chat-composer-slot\"", "><div style=\"", "\"", ">", "</div>", "", "</div>"],
|
|
32
|
+
_tmpl$23 = ["<div class=\"k2b-chat-composer__hint\" aria-live=\"polite\">", "</div>"],
|
|
33
|
+
_tmpl$24 = ["<div class=\"k2b-chat-composer__attachments\" role=\"list\"", " tabindex=\"0\">", "</div>"],
|
|
34
|
+
_tmpl$25 = ["<div class=\"k2b-chat-composer__error\" role=\"alert\"><i class=\"ti ti-alert-circle\" aria-hidden=\"true\"></i>", "</div>"],
|
|
35
|
+
_tmpl$26 = ["<div class=\"k2b-chat-composer__row\">", "", "<div class=\"k2b-chat-composer__field\">", "<div class=\"k2b-chat-composer__field-tools\">", "", "", "</div></div>", "</div>"],
|
|
36
|
+
_tmpl$27 = ["<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>"],
|
|
37
|
+
_tmpl$28 = ["<button id=\"", "\" type=\"button\" role=\"option\" tabindex=\"-1\"", "><span class=\"k2b-chat-composer__emoji-glyph\" aria-hidden=\"true\">", "</span><strong>", "</strong>", "</button>"],
|
|
38
|
+
_tmpl$29 = ["<small>:", ":</small>"],
|
|
39
|
+
_tmpl$30 = "<i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i>",
|
|
40
|
+
_tmpl$31 = ["<div class=\"k2b-chat-composer__command-group\" role=\"group\"", "><div class=\"k2b-chat-composer__command-heading\"", " role=\"presentation\"><span>", "</span>", "</div>", "", "</div>"],
|
|
41
|
+
_tmpl$32 = "<div class=\"k2b-chat-composer__command-placeholder\" aria-hidden=\"true\"><span></span><span><span></span><span></span></span></div>",
|
|
42
|
+
_tmpl$33 = ["<span class=\"k2b-chat-composer__hint-text\">", "</span>"],
|
|
43
|
+
_tmpl$34 = ["<span class=\"k2b-chat-composer__dictation\"", "><i", " aria-hidden=\"true\"></i><span>", "</span></span>"],
|
|
44
|
+
_tmpl$35 = ["<button type=\"button\" class=\"k2b-chat-composer__hint-action\"", ">", "</button>"],
|
|
45
|
+
_tmpl$36 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-remove\"", "", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
|
|
46
|
+
_tmpl$37 = ["<div class=\"k2b-chat-composer__attachment\" role=\"listitem\"><div class=\"", "\">", "", "</div>", "</div>"],
|
|
47
|
+
_tmpl$38 = ["<img", ">"],
|
|
48
|
+
_tmpl$39 = ["<div class=\"k2b-chat-composer__attachment-identity\">", "", "</div>"],
|
|
49
|
+
_tmpl$40 = ["<a class=\"k2b-chat-composer__attachment-link\"", " target=\"_blank\" rel=\"noopener noreferrer\"", ">", "", "</a>"],
|
|
50
|
+
_tmpl$41 = ["<button type=\"button\" class=\"k2b-chat-composer__attachment-action\"", ">", "", "</button>"],
|
|
51
|
+
_tmpl$42 = ["<footer class=\"k2b-chat-composer__footer\">", "</footer>"],
|
|
52
|
+
_tmpl$43 = ["<div class=\"k2b-chat-composer__tools\">", "", "", "", "", "", "", "</div>"],
|
|
53
|
+
_tmpl$44 = ["<div class=\"k2b-chat-composer__submit\">", "", "", "", "", "</div>"],
|
|
54
|
+
_tmpl$45 = ["<span>", "</span>"],
|
|
55
|
+
_tmpl$46 = ["<div class=\"k2b-chat-composer__status-line\"", "><i aria-hidden=\"true\"", "></i><span>", "</span></div>"],
|
|
56
|
+
_tmpl$47 = ["<span class=\"k2b-sr-only\">", "</span>"];
|
|
57
|
+
import { batch, children, createEffect, createMemo, createSignal, createUniqueId, For, Index, on, onCleanup, onMount, Show, untrack } from "solid-js";
|
|
56
58
|
import { Dropdown } from "../actions/Dropdown";
|
|
57
59
|
import { dialogHistorySettled, holdDialogHistory } from "../feedback/dialog-core";
|
|
58
60
|
import { Tooltip } from "../feedback/Tooltip";
|
|
@@ -78,7 +80,17 @@ const emojiSuggestionLimit = 8;
|
|
|
78
80
|
// Keep editor undo text within approximately 2 MiB, plus the current edit.
|
|
79
81
|
const composerUndoBudgetChars = 1_000_000;
|
|
80
82
|
|
|
81
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* An action can cancel and restore its token, report a short completion message, or hand back a reference chosen in a
|
|
85
|
+
* dialog: `mention` takes the token's place exactly as a `mention` row does, and Ctrl/⌘+Z brings the token back.
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
/** The draft as a successful `open` leaves it: without the `/…` token, with its references moved along. Save this one. */
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* How an `open` row ends: on success (`void`) the token leaves as for an action; `"cancelled"` changes nothing; `failed`
|
|
92
|
+
* keeps the list open and the draft unchanged, and its text replaces the row's description until the row runs again.
|
|
93
|
+
*/
|
|
82
94
|
|
|
83
95
|
/** A fixed place in the slash list. Sections keep the given order, also while searching. */
|
|
84
96
|
|
|
@@ -168,6 +180,17 @@ export function ChatComposer(props) {
|
|
|
168
180
|
return `${commandListId}-c${commandIds.get(key)}`;
|
|
169
181
|
};
|
|
170
182
|
const [closedAt, setClosedAt] = createSignal();
|
|
183
|
+
/** The list opened from "+": the field's selection when "+" was pressed, and the search field's text. */
|
|
184
|
+
const [addSearch, setAddSearch] = createSignal();
|
|
185
|
+
const [addQuery, setAddQuery] = createSignal("");
|
|
186
|
+
let addSearchRef;
|
|
187
|
+
let addButtonRef;
|
|
188
|
+
let addComposing = false;
|
|
189
|
+
/** The `open` row running now, and why `open` rows failed in this opening, by row key. */
|
|
190
|
+
const [openingRow, setOpeningRow] = createSignal();
|
|
191
|
+
const [openFailures, setOpenFailures] = createSignal({});
|
|
192
|
+
/** Cancels the `open` row running now; `key` follows announced draft moves, `label` is its busy line. */
|
|
193
|
+
let openingRun;
|
|
171
194
|
// Where the pending native edit starts; a selection replaced as a whole starts at its beginning.
|
|
172
195
|
let inputStart;
|
|
173
196
|
let inputEnd;
|
|
@@ -272,7 +295,17 @@ export function ChatComposer(props) {
|
|
|
272
295
|
return token && index ? suggestEmoji(index, token.query, emojiSuggestionLimit) : [];
|
|
273
296
|
});
|
|
274
297
|
const emojiOpen = () => emojiMatches().length > 0;
|
|
275
|
-
|
|
298
|
+
// From "+", the search field's text is the query of an empty token at the field's stored caret.
|
|
299
|
+
const caretCommandToken = createMemo(() => {
|
|
300
|
+
const search = addSearch();
|
|
301
|
+
if (!search) return chatCommandQuery(props.value, caret(), selectionEnd());
|
|
302
|
+
const at = Math.min(search.end, props.value.length);
|
|
303
|
+
return {
|
|
304
|
+
start: at,
|
|
305
|
+
end: at,
|
|
306
|
+
query: addQuery()
|
|
307
|
+
};
|
|
308
|
+
});
|
|
276
309
|
const caretCommandStart = createMemo(() => caretCommandToken()?.start);
|
|
277
310
|
// Retained server rows belong to one `/`: they go when it does or when another `/` starts.
|
|
278
311
|
createEffect(() => {
|
|
@@ -287,6 +320,7 @@ export function ChatComposer(props) {
|
|
|
287
320
|
});
|
|
288
321
|
const commandQuery = createMemo(() => {
|
|
289
322
|
const token = caretCommandToken();
|
|
323
|
+
if (addSearch()) return token;
|
|
290
324
|
return dismissed() || composing() || token?.start === closedAt() ? null : token;
|
|
291
325
|
});
|
|
292
326
|
const openingStart = createMemo(() => commandQuery()?.start);
|
|
@@ -295,14 +329,44 @@ export function ChatComposer(props) {
|
|
|
295
329
|
const start = openingStart();
|
|
296
330
|
if (start !== undefined) setCommandOpening(opening => opening + 1);
|
|
297
331
|
});
|
|
332
|
+
// A failed `open` row says so for the rest of its list opening.
|
|
333
|
+
createEffect(() => {
|
|
334
|
+
props.draftKey;
|
|
335
|
+
commandOpening();
|
|
336
|
+
setOpenFailures({});
|
|
337
|
+
});
|
|
298
338
|
const parsedCommandQuery = createMemo(() => parseChatCommandQuery(commandQuery()?.query ?? "", props.commandScopes ?? []));
|
|
339
|
+
const commandFallbackRow = createMemo(() => {
|
|
340
|
+
const parsed = parsedCommandQuery();
|
|
341
|
+
const query = parsed.query.trim();
|
|
342
|
+
return commandQuery() && (query || parsed.scope) ? props.commandFallback?.({
|
|
343
|
+
query,
|
|
344
|
+
scope: parsed.scope?.id
|
|
345
|
+
}) : undefined;
|
|
346
|
+
});
|
|
299
347
|
const currentCommandScope = createMemo(() => parsedCommandQuery().scope?.id);
|
|
300
348
|
createEffect(() => {
|
|
301
349
|
currentCommandScope();
|
|
302
350
|
setSearchResults([]);
|
|
303
351
|
setSearchResultsQuery(undefined);
|
|
304
352
|
});
|
|
305
|
-
|
|
353
|
+
// Rows of a `fixedWhileOpen` section are the ones it had when this `/` opened the list; later ones wait for the next
|
|
354
|
+
// `/`. A retry row starts another opening in the same open list, so it does not count.
|
|
355
|
+
const fixedCommandKeys = createMemo(() => {
|
|
356
|
+
props.draftKey;
|
|
357
|
+
if (openingStart() === undefined) return undefined;
|
|
358
|
+
return untrack(() => {
|
|
359
|
+
const fixed = new Set((props.commandSections ?? []).filter(section => section.fixedWhileOpen).map(section => section.id));
|
|
360
|
+
return fixed.size ? new Set((props.commands ?? []).filter(command => fixed.has(command.section ?? "")).map(chatCommandKey)) : undefined;
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
const localCommands = createMemo(() => {
|
|
364
|
+
const commands = props.commands ?? [];
|
|
365
|
+
const keys = fixedCommandKeys();
|
|
366
|
+
if (!keys) return commands;
|
|
367
|
+
const fixed = new Set((props.commandSections ?? []).filter(section => section.fixedWhileOpen).map(section => section.id));
|
|
368
|
+
return commands.filter(command => !fixed.has(command.section ?? "") || keys.has(chatCommandKey(command)));
|
|
369
|
+
});
|
|
306
370
|
const commandModel = createMemo(() => chatCommandListModel({
|
|
307
371
|
query: commandQuery()?.query ?? "",
|
|
308
372
|
scopes: props.commandScopes,
|
|
@@ -311,9 +375,12 @@ export function ChatComposer(props) {
|
|
|
311
375
|
searchResults: searchResultsScope() === parsedCommandQuery().scope?.id ? searchResults() : [],
|
|
312
376
|
searchResultsFresh: searchResultsQuery() === commandQuery()?.query && searchResultsScope() === parsedCommandQuery().scope?.id,
|
|
313
377
|
searchSettled: searchResultsQuery() !== undefined && searchResultsScope() === parsedCommandQuery().scope?.id,
|
|
314
|
-
searching: searching()
|
|
378
|
+
searching: searching(),
|
|
379
|
+
fallback: commandFallbackRow()
|
|
315
380
|
}));
|
|
316
381
|
const commandMatches = createMemo(() => commandQuery() ? commandModel().rows.map(row => row.command) : []);
|
|
382
|
+
/** Rows that matched; an unscoped fallback row only follows them. */
|
|
383
|
+
const foundCommandCount = () => commandMatches().length - (commandModel().fallback ? 1 : 0);
|
|
317
384
|
const currentCommandQuery = createMemo(() => caretCommandToken()?.query);
|
|
318
385
|
// Arrow marking belongs to one token in one draft; another draft or `/` starts at the top row again.
|
|
319
386
|
createEffect(() => {
|
|
@@ -322,13 +389,87 @@ export function ChatComposer(props) {
|
|
|
322
389
|
currentCommandQuery();
|
|
323
390
|
setCommandMoved(false);
|
|
324
391
|
});
|
|
325
|
-
const commandsOpen = () => Boolean(!emojiOpen() && commandQuery() && (localCommands().length || props.searchCommands));
|
|
326
|
-
|
|
392
|
+
const commandsOpen = () => Boolean(!emojiOpen() && commandQuery() && (localCommands().length || props.searchCommands || commandFallbackRow()));
|
|
393
|
+
// Rows that arrive for a pending section never move a visible row of the overview: until the person types, the list
|
|
394
|
+
// keeps the height it had with its placeholders and scrolls what does not fit. A list below its maximum height grows
|
|
395
|
+
// upward from the field, so a change of height alone would move its first row. While searching, the rows arrive
|
|
396
|
+
// with the search's own answer, which changes the list anyway.
|
|
397
|
+
// From "+", the whole panel keeps the height it opened with instead.
|
|
398
|
+
const commandsPending = createMemo(() => commandsOpen() && !addSearch() && !parsedCommandQuery().scope && !parsedCommandQuery().query.trim() && commandModel().groups.some(group => group.pendingRows > 0));
|
|
399
|
+
// Typing, another opening or closing the list lets it size itself again.
|
|
400
|
+
const commandListSizeKey = createMemo(() => commandsOpen() ? `${commandOpening()}\u0000${caretCommandToken()?.query}` : undefined);
|
|
401
|
+
// The list's height with its placeholders, for the size key it was measured under.
|
|
402
|
+
let pendingList;
|
|
403
|
+
createEffect(() => {
|
|
404
|
+
const list = commandListRef;
|
|
405
|
+
if (!commandsPending() || !list || typeof ResizeObserver === "undefined") return;
|
|
406
|
+
const measure = () => {
|
|
407
|
+
pendingList = {
|
|
408
|
+
height: list.getBoundingClientRect().height,
|
|
409
|
+
key: untrack(commandListSizeKey)
|
|
410
|
+
};
|
|
411
|
+
};
|
|
412
|
+
measure();
|
|
413
|
+
const observer = new ResizeObserver(measure);
|
|
414
|
+
observer.observe(list);
|
|
415
|
+
onCleanup(() => observer.disconnect());
|
|
416
|
+
});
|
|
417
|
+
createEffect(on(commandsPending, (pending, wasPending) => {
|
|
418
|
+
const held = pendingList;
|
|
419
|
+
pendingList = undefined;
|
|
420
|
+
// Only rows arriving hold the list; the person's typing or closing it does not.
|
|
421
|
+
if (pending || !wasPending || !held || held.key !== commandListSizeKey() || !commandListRef?.isConnected) return;
|
|
422
|
+
commandListRef.style.height = `${held.height}px`;
|
|
423
|
+
commandListRef.setAttribute("data-held", "");
|
|
424
|
+
}));
|
|
425
|
+
createEffect(on(commandListSizeKey, () => {
|
|
426
|
+
commandListRef?.style.removeProperty("height");
|
|
427
|
+
commandListRef?.removeAttribute("data-held");
|
|
428
|
+
}, {
|
|
429
|
+
defer: true
|
|
430
|
+
}));
|
|
431
|
+
// Escape, a press outside, or moving the caret away closes the list; while an `open` row runs, that cancels it, so
|
|
432
|
+
// nothing opens after the person backed out. Success ends the opening and closes the list in one step. A new draft
|
|
433
|
+
// cancels too, unless the opener announced that next move with `follow()`: its busy line moves to the status line,
|
|
434
|
+
// and Escape still cancels there. Any later unannounced draft change cancels.
|
|
435
|
+
createEffect(() => {
|
|
436
|
+
const draftKey = props.draftKey;
|
|
437
|
+
const open = commandsOpen();
|
|
438
|
+
const row = openingRow();
|
|
439
|
+
const run = openingRun;
|
|
440
|
+
if (!run || row === undefined) return;
|
|
441
|
+
if (draftKey !== run.key) {
|
|
442
|
+
if (run.follow) {
|
|
443
|
+
run.follow = false;
|
|
444
|
+
run.key = draftKey;
|
|
445
|
+
run.moved = true;
|
|
446
|
+
showCommandStatus({
|
|
447
|
+
tone: "busy",
|
|
448
|
+
text: run.label
|
|
449
|
+
});
|
|
450
|
+
} else run.controller.abort();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (!open && !run.moved) run.controller.abort();
|
|
454
|
+
});
|
|
455
|
+
onCleanup(() => openingRun?.controller.abort());
|
|
456
|
+
// An `open` row gives the sheet's Back entry up first, so it never races the navigation it starts.
|
|
457
|
+
const commandSheetHeld = createMemo(() => commandsOpen() && isTouchOnly() && openingRow() === undefined);
|
|
327
458
|
createEffect(() => {
|
|
328
459
|
if (!commandSheetHeld()) return;
|
|
329
|
-
onCleanup(holdDialogHistory(() =>
|
|
460
|
+
onCleanup(holdDialogHistory(() => closeCommandList()));
|
|
330
461
|
});
|
|
331
462
|
const suggestionsOpen = () => commandsOpen() || emojiOpen();
|
|
463
|
+
const fieldOwnsList = () => suggestionsOpen() && !addSearch();
|
|
464
|
+
// From "+", the panel keeps the height it opened with while the person types or rows arrive, so neither the search
|
|
465
|
+
// field nor the first row moves; what does not fit scrolls. The space above the field still bounds it.
|
|
466
|
+
const addPanelOpen = createMemo(() => addSearch() !== undefined && commandsOpen());
|
|
467
|
+
createEffect(() => {
|
|
468
|
+
const accessory = addPanelOpen() ? commandListRef?.parentElement : undefined;
|
|
469
|
+
if (!accessory) return;
|
|
470
|
+
const frame = requestAnimationFrame(() => accessory.style.setProperty("--k2b-chat-command-held", `${accessory.getBoundingClientRect().height}px`));
|
|
471
|
+
onCleanup(() => cancelAnimationFrame(frame));
|
|
472
|
+
});
|
|
332
473
|
createEffect(() => {
|
|
333
474
|
if (!suggestionsOpen()) return;
|
|
334
475
|
let disposed = false;
|
|
@@ -356,10 +497,13 @@ export function ChatComposer(props) {
|
|
|
356
497
|
const left = Math.max(0, column?.left ?? 0);
|
|
357
498
|
const right = Math.min(page, column?.right ?? page);
|
|
358
499
|
const slot = accessory.parentElement.getBoundingClientRect();
|
|
359
|
-
|
|
360
|
-
|
|
500
|
+
// From its place in the slot, not its box: the sheet opened from "+" rises into place, and a box measured during
|
|
501
|
+
// that animation would include its offset.
|
|
502
|
+
const bottom = slot.bottom - (Number.parseFloat(window.getComputedStyle(accessory).bottom) || 0);
|
|
503
|
+
// On the accessory, so a panel opened from "+" is bounded as a whole, with its search field.
|
|
504
|
+
accessory.style.setProperty("--k2b-chat-command-space", `${Math.max(40, bottom - top - 8)}px`);
|
|
361
505
|
// Only a list that reaches the screen's top edge keeps clear of a notch or the status bar.
|
|
362
|
-
|
|
506
|
+
accessory.style.setProperty("--k2b-chat-command-safe-top", top === viewportTop ? "env(safe-area-inset-top, 0px)" : "0px");
|
|
363
507
|
accessory.style.setProperty("--k2b-chat-command-reach-left", `${Math.max(0, slot.left - left)}px`);
|
|
364
508
|
accessory.style.setProperty("--k2b-chat-command-reach-right", `${Math.max(0, right - slot.right)}px`);
|
|
365
509
|
};
|
|
@@ -377,11 +521,29 @@ export function ChatComposer(props) {
|
|
|
377
521
|
// A press outside the command list and the field closes the list, as Escape does; the text stays. With a mouse or a
|
|
378
522
|
// trackpad the press then acts as usual. On a touch-only device a tap outside the composer closes only the list: it
|
|
379
523
|
// reaches nothing beneath, and the field keeps focus, so the keyboard stays open.
|
|
524
|
+
// A list opened from "+" is a menu: any press outside it closes only the list, with every pointer, and the field gets
|
|
525
|
+
// its focus back. "+" itself toggles with its click; a press in the field closes the list and lands there as usual.
|
|
380
526
|
createEffect(() => {
|
|
381
527
|
if (!commandsOpen()) return;
|
|
382
528
|
const onPointerDown = event => {
|
|
383
529
|
const target = event.target;
|
|
384
|
-
if (!(target instanceof Node) || commandListRef?.
|
|
530
|
+
if (!(target instanceof Node) || commandListRef?.parentElement?.contains(target)) return;
|
|
531
|
+
if (addSearch()) {
|
|
532
|
+
if (addButtonRef?.contains(target) && !addButtonRef.disabled) return;
|
|
533
|
+
if (textareaRef?.parentElement?.contains(target)) {
|
|
534
|
+
// The field takes the focus before the search field goes, so a phone keeps its keyboard; the press itself
|
|
535
|
+
// then places the caret.
|
|
536
|
+
textareaRef.focus({
|
|
537
|
+
preventScroll: true
|
|
538
|
+
});
|
|
539
|
+
endAddSearch(false);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
swallowTap(event);
|
|
543
|
+
endAddSearch(true);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
if (textareaRef?.parentElement?.contains(target)) return;
|
|
385
547
|
setClosedAt(commandQuery()?.start);
|
|
386
548
|
if (isTouchOnly() && !shellRef?.contains(target)) swallowTap(event);
|
|
387
549
|
};
|
|
@@ -431,9 +593,10 @@ export function ChatComposer(props) {
|
|
|
431
593
|
});
|
|
432
594
|
});
|
|
433
595
|
let settledEmpty;
|
|
596
|
+
// A space after "Nothing found" ends the `/…` as plain text; a search field opened from "+" just keeps its text.
|
|
434
597
|
createEffect(() => {
|
|
435
598
|
const token = commandQuery();
|
|
436
|
-
if (!token || parsedCommandQuery().scope || searchError()) {
|
|
599
|
+
if (!token || addSearch() || parsedCommandQuery().scope || searchError()) {
|
|
437
600
|
settledEmpty = undefined;
|
|
438
601
|
return;
|
|
439
602
|
}
|
|
@@ -484,6 +647,7 @@ export function ChatComposer(props) {
|
|
|
484
647
|
history.length = 0;
|
|
485
648
|
historyIndex = -1;
|
|
486
649
|
finishModelSelection(null);
|
|
650
|
+
endAddSearch(false);
|
|
487
651
|
setDismissed(true);
|
|
488
652
|
setClosedAt(undefined);
|
|
489
653
|
setSearchResults([]);
|
|
@@ -532,6 +696,8 @@ export function ChatComposer(props) {
|
|
|
532
696
|
setDismissed(false);
|
|
533
697
|
};
|
|
534
698
|
const restoreHistory = direction => {
|
|
699
|
+
// A field that only stays enabled to keep focus, while an `open` row runs, is not edited by undo either.
|
|
700
|
+
if (editBlocked()) return;
|
|
535
701
|
record();
|
|
536
702
|
const next = history[historyIndex + direction];
|
|
537
703
|
if (!next) return;
|
|
@@ -550,6 +716,45 @@ export function ChatComposer(props) {
|
|
|
550
716
|
setSelectionEnd(textareaRef?.selectionEnd ?? props.value.length);
|
|
551
717
|
});
|
|
552
718
|
};
|
|
719
|
+
/** Closes the list opened from "+"; `refocus` gives the field its focus and the selection it had when "+" was pressed. */
|
|
720
|
+
const endAddSearch = refocus => {
|
|
721
|
+
const search = addSearch();
|
|
722
|
+
if (!search) return;
|
|
723
|
+
addComposing = false;
|
|
724
|
+
batch(() => {
|
|
725
|
+
setAddSearch(undefined);
|
|
726
|
+
setAddQuery("");
|
|
727
|
+
});
|
|
728
|
+
if (!refocus || !textareaRef) return;
|
|
729
|
+
const length = textareaRef.value.length;
|
|
730
|
+
textareaRef.focus();
|
|
731
|
+
textareaRef.setSelectionRange(Math.min(search.start, length), Math.min(search.end, length));
|
|
732
|
+
syncCaret();
|
|
733
|
+
};
|
|
734
|
+
/** Escape, Back, a press outside: the list closes and the text stays. */
|
|
735
|
+
const closeCommandList = (refocus = true) => {
|
|
736
|
+
if (addSearch()) endAddSearch(refocus);else setClosedAt(commandQuery()?.start);
|
|
737
|
+
};
|
|
738
|
+
const toggleAddSearch = () => {
|
|
739
|
+
if (addSearch()) {
|
|
740
|
+
endAddSearch(true);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
if (blocked() || !textareaRef) return;
|
|
744
|
+
const start = textareaRef.selectionStart;
|
|
745
|
+
const end = textareaRef.selectionEnd;
|
|
746
|
+
batch(() => {
|
|
747
|
+
// Emoji suggestions for a `:shortcode` at the caret give way; they would hold the list closed.
|
|
748
|
+
setDismissed(true);
|
|
749
|
+
setAddQuery("");
|
|
750
|
+
setAddSearch({
|
|
751
|
+
start,
|
|
752
|
+
end
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
// Within the press, so a phone opens its keyboard for the search field.
|
|
756
|
+
addSearchRef?.focus();
|
|
757
|
+
};
|
|
553
758
|
const selectedCommand = createMemo(() => {
|
|
554
759
|
const rows = commandMatches();
|
|
555
760
|
return commandMoved() && rows.find(command => chatCommandKey(command) === activeCommandKey()) || rows[0];
|
|
@@ -573,6 +778,8 @@ export function ChatComposer(props) {
|
|
|
573
778
|
const canSubmit = () => !submitting() && submittable();
|
|
574
779
|
const canSelectFiles = () => Boolean(props.fileSelection && !props.fileSelection.disabled && !running() && !blocked());
|
|
575
780
|
const hasAddMenu = () => Boolean(props.fileSelection || props.menuActions?.length);
|
|
781
|
+
/** "+" opens the slash list, as long as there is one; otherwise it stays the add menu. */
|
|
782
|
+
const addOpensCommands = () => Boolean(props.addOpensCommands && (props.commands?.length || props.searchCommands));
|
|
576
783
|
const hasContextUsage = () => {
|
|
577
784
|
if (props.contextPopupAction) return true;
|
|
578
785
|
const context = props.contextUsage;
|
|
@@ -666,12 +873,78 @@ export function ChatComposer(props) {
|
|
|
666
873
|
});
|
|
667
874
|
const setAttachments = next => props.onAttachmentsChange?.(next);
|
|
668
875
|
const renderAttachmentCopy = attachment => _$ssr(_tmpl$, _$ssrAttribute("title", _$escape(attachment.name, true), false), _$escape(attachment.name));
|
|
669
|
-
|
|
876
|
+
|
|
877
|
+
/** `onNothing` runs when the person closes the selection without a file. */
|
|
878
|
+
const chooseFiles = onNothing => {
|
|
670
879
|
const selection = props.fileSelection;
|
|
671
|
-
if (!selection?.choose)
|
|
672
|
-
|
|
880
|
+
if (!selection?.choose) {
|
|
881
|
+
const input = fileInputRef;
|
|
882
|
+
if (input && onNothing) {
|
|
883
|
+
const done = new AbortController();
|
|
884
|
+
input.addEventListener("cancel", () => {
|
|
885
|
+
done.abort();
|
|
886
|
+
onNothing();
|
|
887
|
+
}, {
|
|
888
|
+
signal: done.signal
|
|
889
|
+
});
|
|
890
|
+
input.addEventListener("change", () => done.abort(), {
|
|
891
|
+
signal: done.signal
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
return input?.click();
|
|
895
|
+
}
|
|
896
|
+
const failed = error => {
|
|
897
|
+
onNothing?.();
|
|
898
|
+
(props.fileSelection?.onError ?? props.onError)?.(error);
|
|
899
|
+
};
|
|
900
|
+
let chosen;
|
|
901
|
+
try {
|
|
902
|
+
chosen = selection.choose();
|
|
903
|
+
} catch (error) {
|
|
904
|
+
failed(error);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
chosen.then(
|
|
673
908
|
// A single-file composer keeps the first chosen file, as its file dialog and drops do.
|
|
674
|
-
files =>
|
|
909
|
+
files => {
|
|
910
|
+
if (files.length === 0) onNothing?.();else void runFiles(selection.multiple === false ? files.slice(0, 1) : files);
|
|
911
|
+
}, failed);
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* "Attach files" from the slash list: the token leaves as one edit, and the selection opens synchronously, inside the
|
|
916
|
+
* key or click that chose the row, because the device's file dialog needs that activation. Closing the selection
|
|
917
|
+
* without a file brings the token back, unless the draft changed meanwhile.
|
|
918
|
+
*/
|
|
919
|
+
const attachFilesFromCommand = (token, selection) => {
|
|
920
|
+
if (!canSelectFiles()) return;
|
|
921
|
+
const key = props.draftKey;
|
|
922
|
+
const previous = snapshot();
|
|
923
|
+
const previousHistory = {
|
|
924
|
+
entries: [...history],
|
|
925
|
+
index: historyIndex
|
|
926
|
+
};
|
|
927
|
+
const nextValue = props.value.slice(0, token.start) + props.value.slice(token.end);
|
|
928
|
+
edit(nextValue, reconcileChatMentions(props.value, nextValue, mentions()));
|
|
929
|
+
setDismissed(true);
|
|
930
|
+
chooseFiles(() => {
|
|
931
|
+
if (props.draftKey !== key || props.value !== nextValue) return;
|
|
932
|
+
setDismissed(true);
|
|
933
|
+
props.onValueChange(previous.value);
|
|
934
|
+
props.onMentionsChange?.(previous.mentions);
|
|
935
|
+
history.splice(0, history.length, ...previousHistory.entries);
|
|
936
|
+
historyIndex = previousHistory.index;
|
|
937
|
+
queueMicrotask(() => {
|
|
938
|
+
textareaRef?.setSelectionRange(selection?.start ?? token.end, selection?.end ?? token.end);
|
|
939
|
+
syncCaret();
|
|
940
|
+
focus();
|
|
941
|
+
});
|
|
942
|
+
});
|
|
943
|
+
queueMicrotask(() => {
|
|
944
|
+
if (props.draftKey !== key || props.value !== nextValue) return;
|
|
945
|
+
textareaRef?.setSelectionRange(token.start, token.start);
|
|
946
|
+
syncCaret();
|
|
947
|
+
});
|
|
675
948
|
};
|
|
676
949
|
const runFiles = async files => {
|
|
677
950
|
if (!canSelectFiles()) return;
|
|
@@ -694,7 +967,7 @@ export function ChatComposer(props) {
|
|
|
694
967
|
setSubmitting(true);
|
|
695
968
|
try {
|
|
696
969
|
if (isTouchOnly()) {
|
|
697
|
-
if (commandSheetHeld())
|
|
970
|
+
if (commandSheetHeld()) closeCommandList(false);
|
|
698
971
|
// The sheet's Back entry leaves first, so a submit handler that navigates finds the history settled.
|
|
699
972
|
await dialogHistorySettled();
|
|
700
973
|
// A draft that another one replaced, or that may no longer go out, is not sent and keeps its text.
|
|
@@ -746,6 +1019,10 @@ export function ChatComposer(props) {
|
|
|
746
1019
|
const word = scope?.words[0];
|
|
747
1020
|
const token = commandQuery();
|
|
748
1021
|
if (!word || !token || !textareaRef) return false;
|
|
1022
|
+
if (addSearch()) {
|
|
1023
|
+
setAddQuery(`${word} `);
|
|
1024
|
+
return true;
|
|
1025
|
+
}
|
|
749
1026
|
replaceTextareaRange(textareaRef, token.start + 1, token.end, `${word} `);
|
|
750
1027
|
syncCaret();
|
|
751
1028
|
return true;
|
|
@@ -753,6 +1030,8 @@ export function ChatComposer(props) {
|
|
|
753
1030
|
const executeCommand = async (command, tab = false) => {
|
|
754
1031
|
const token = commandQuery();
|
|
755
1032
|
const heldHistory = commandSheetHeld();
|
|
1033
|
+
const addSelection = addSearch();
|
|
1034
|
+
const fromAdd = addSelection !== undefined;
|
|
756
1035
|
if (!token || blocked()) return;
|
|
757
1036
|
if (command.disabled || command.reason) {
|
|
758
1037
|
// A new object each time, so choosing the same row again inserts and announces its reason again.
|
|
@@ -766,17 +1045,35 @@ export function ChatComposer(props) {
|
|
|
766
1045
|
setCommandOpening(opening => opening + 1);
|
|
767
1046
|
return;
|
|
768
1047
|
}
|
|
769
|
-
if (command.scope && (tab || !command.action && !command.mention) && narrowCommand(command)) return;
|
|
1048
|
+
if (command.scope && (tab || !command.action && !command.mention && !command.attachFiles) && narrowCommand(command)) return;
|
|
1049
|
+
if (command.attachFiles) {
|
|
1050
|
+
if (!canSelectFiles()) return;
|
|
1051
|
+
// The field has the focus before the selection opens, so closing it without a file comes back there.
|
|
1052
|
+
endAddSearch(true);
|
|
1053
|
+
attachFilesFromCommand(token, addSelection);
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
if (command.open) {
|
|
1057
|
+
await openFromCommand(command, command.open, token);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
// The field has the focus again before an action opens a dialog, so the dialog gives it back there.
|
|
1061
|
+
endAddSearch(true);
|
|
1062
|
+
// From "+" a reference joins the text at the caret, apart from a word right before it.
|
|
1063
|
+
const lead = value => fromAdd && token.start > 0 && !/\s/.test(value[token.start - 1] ?? "") ? " " : "";
|
|
770
1064
|
const previous = snapshot();
|
|
771
1065
|
const key = props.draftKey;
|
|
772
|
-
const replacement = command.mention ? command.mention.name + " " : "";
|
|
1066
|
+
const replacement = command.mention ? lead(props.value) + command.mention.name + " " : "";
|
|
773
1067
|
const nextValue = props.value.slice(0, token.start) + replacement + props.value.slice(token.end);
|
|
774
1068
|
const nextMentions = reconcileChatMentions(props.value, nextValue, mentions());
|
|
775
|
-
if (command.mention)
|
|
776
|
-
start
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1069
|
+
if (command.mention) {
|
|
1070
|
+
const start = token.start + lead(props.value).length;
|
|
1071
|
+
nextMentions.push({
|
|
1072
|
+
start,
|
|
1073
|
+
end: start + command.mention.name.length,
|
|
1074
|
+
attachment: command.mention
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
780
1077
|
// A cancelled or failed command leaves no undo step behind: restoring puts the history back as well.
|
|
781
1078
|
const previousHistory = {
|
|
782
1079
|
entries: [...history],
|
|
@@ -787,6 +1084,7 @@ export function ChatComposer(props) {
|
|
|
787
1084
|
setExecuting(true);
|
|
788
1085
|
let submitRequested = false;
|
|
789
1086
|
let restored = false;
|
|
1087
|
+
let mentioned;
|
|
790
1088
|
const restore = () => {
|
|
791
1089
|
if (props.draftKey !== key || props.value !== nextValue) return;
|
|
792
1090
|
setDismissed(true);
|
|
@@ -819,6 +1117,33 @@ export function ChatComposer(props) {
|
|
|
819
1117
|
submitRequested = false;
|
|
820
1118
|
restore();
|
|
821
1119
|
showCommandStatus();
|
|
1120
|
+
} else if (result && "mention" in result) {
|
|
1121
|
+
// One undo step from the token to the reference, as if the row had been a reference itself.
|
|
1122
|
+
if (props.draftKey === key && props.value === nextValue) {
|
|
1123
|
+
restore();
|
|
1124
|
+
restored = false;
|
|
1125
|
+
const name = result.mention.name;
|
|
1126
|
+
const start = token.start + lead(previous.value).length;
|
|
1127
|
+
const withMention = previous.value.slice(0, token.start) + lead(previous.value) + name + " " + previous.value.slice(token.end);
|
|
1128
|
+
edit(withMention, [...reconcileChatMentions(previous.value, withMention, previous.mentions), {
|
|
1129
|
+
start,
|
|
1130
|
+
end: start + name.length,
|
|
1131
|
+
attachment: result.mention
|
|
1132
|
+
}]);
|
|
1133
|
+
setDismissed(true);
|
|
1134
|
+
mentioned = {
|
|
1135
|
+
value: withMention,
|
|
1136
|
+
caret: start + name.length + 1
|
|
1137
|
+
};
|
|
1138
|
+
showCommandStatus();
|
|
1139
|
+
} else {
|
|
1140
|
+
// The pick is lost; say so, also when the draft moved to another key meanwhile (such as a new chat saved
|
|
1141
|
+
// while the dialog was open), so it never ends in silence.
|
|
1142
|
+
showCommandStatus({
|
|
1143
|
+
tone: "error",
|
|
1144
|
+
text: chatMessages().commandDraftChanged
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
822
1147
|
} else if (result) {
|
|
823
1148
|
showCommandStatus({
|
|
824
1149
|
tone: "done",
|
|
@@ -840,9 +1165,9 @@ export function ChatComposer(props) {
|
|
|
840
1165
|
if (submitRequested && props.draftKey === key) await submit();
|
|
841
1166
|
queueMicrotask(() => {
|
|
842
1167
|
if (props.draftKey !== key) return;
|
|
843
|
-
if (restored || props.value === nextValue) {
|
|
844
|
-
const position = restored ? token.end : token.start + replacement.length;
|
|
845
|
-
textareaRef?.setSelectionRange(position, position);
|
|
1168
|
+
if (restored || props.value === nextValue || mentioned && props.value === mentioned.value) {
|
|
1169
|
+
const position = restored ? token.end : mentioned?.caret ?? token.start + replacement.length;
|
|
1170
|
+
textareaRef?.setSelectionRange(restored && addSelection ? addSelection.start : position, restored && addSelection ? addSelection.end : position);
|
|
846
1171
|
}
|
|
847
1172
|
syncCaret();
|
|
848
1173
|
autoResize();
|
|
@@ -850,6 +1175,110 @@ export function ChatComposer(props) {
|
|
|
850
1175
|
});
|
|
851
1176
|
};
|
|
852
1177
|
|
|
1178
|
+
/**
|
|
1179
|
+
* Runs an `open` row with the token and the list in place. Success removes the token in one undo step; `failed`
|
|
1180
|
+
* stays in the row while the list is still there, otherwise the status line says it, so it never ends in silence.
|
|
1181
|
+
*/
|
|
1182
|
+
const openFromCommand = async (command, open, token) => {
|
|
1183
|
+
const key = props.draftKey;
|
|
1184
|
+
const row = chatCommandKey(command);
|
|
1185
|
+
const value = props.value;
|
|
1186
|
+
const nextValue = value.slice(0, token.start) + value.slice(token.end);
|
|
1187
|
+
const nextMentions = reconcileChatMentions(value, nextValue, mentions());
|
|
1188
|
+
// Still the same draft and `/…`, so the row is where the person chose it.
|
|
1189
|
+
const inPlace = () => !disposed && props.draftKey === key && props.value === value && commandQuery()?.start === token.start;
|
|
1190
|
+
const heldHistory = commandSheetHeld();
|
|
1191
|
+
// Closing the list or leaving the composer cancels the opening; the row ends at once, without waiting for it.
|
|
1192
|
+
const controller = new AbortController();
|
|
1193
|
+
const run = {
|
|
1194
|
+
controller,
|
|
1195
|
+
key,
|
|
1196
|
+
label: command.busyLabel ?? chatMessages().commandOpening,
|
|
1197
|
+
follow: false,
|
|
1198
|
+
moved: false
|
|
1199
|
+
};
|
|
1200
|
+
openingRun = run;
|
|
1201
|
+
const cancelled = new Promise(resolve => controller.signal.addEventListener("abort", () => resolve("cancelled"), {
|
|
1202
|
+
once: true
|
|
1203
|
+
}));
|
|
1204
|
+
setOpenFailures(({
|
|
1205
|
+
[row]: _,
|
|
1206
|
+
...rest
|
|
1207
|
+
}) => rest);
|
|
1208
|
+
setOpeningRow(row);
|
|
1209
|
+
setExecuting(true);
|
|
1210
|
+
// An opening that ends without leaving, by failure, rejection or cancelling, also aborts `signal`, so the opener
|
|
1211
|
+
// can put back what it saved without the token.
|
|
1212
|
+
const finish = (left = false) => {
|
|
1213
|
+
if (!left) controller.abort();
|
|
1214
|
+
if (openingRun === run) openingRun = undefined;
|
|
1215
|
+
if (commandStatus()?.tone === "busy") showCommandStatus();
|
|
1216
|
+
setOpeningRow(undefined);
|
|
1217
|
+
setExecuting(false);
|
|
1218
|
+
};
|
|
1219
|
+
let result;
|
|
1220
|
+
try {
|
|
1221
|
+
if (heldHistory) {
|
|
1222
|
+
await dialogHistorySettled();
|
|
1223
|
+
if (!inPlace()) {
|
|
1224
|
+
finish();
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
result = await Promise.race([open({
|
|
1229
|
+
value: nextValue,
|
|
1230
|
+
mentions: nextMentions
|
|
1231
|
+
}, controller.signal, () => {
|
|
1232
|
+
run.follow = true;
|
|
1233
|
+
}), cancelled]);
|
|
1234
|
+
} catch (error) {
|
|
1235
|
+
finish();
|
|
1236
|
+
if (disposed) {
|
|
1237
|
+
props.onError?.(error);
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
if (inPlace()) closeCommandList();
|
|
1241
|
+
showCommandStatus({
|
|
1242
|
+
tone: "error",
|
|
1243
|
+
text: error instanceof Error && error.message ? error.message : chatMessages().commandFailed
|
|
1244
|
+
});
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
if (!result) {
|
|
1248
|
+
// Success: the token leaves and the list closes in the same step that ends the opening, so a phone sheet never
|
|
1249
|
+
// takes its Back entry again while the page navigates.
|
|
1250
|
+
batch(() => {
|
|
1251
|
+
if (!disposed && props.draftKey === key && props.value === value) {
|
|
1252
|
+
edit(nextValue, nextMentions);
|
|
1253
|
+
setDismissed(true);
|
|
1254
|
+
}
|
|
1255
|
+
endAddSearch(!disposed && props.draftKey === key);
|
|
1256
|
+
finish(true);
|
|
1257
|
+
});
|
|
1258
|
+
queueMicrotask(() => {
|
|
1259
|
+
if (disposed || props.draftKey !== key || props.value !== nextValue) return;
|
|
1260
|
+
textareaRef?.setSelectionRange(token.start, token.start);
|
|
1261
|
+
syncCaret();
|
|
1262
|
+
autoResize();
|
|
1263
|
+
});
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
finish();
|
|
1267
|
+
if (result === "cancelled") return;
|
|
1268
|
+
if (inPlace()) {
|
|
1269
|
+
setOpenFailures(failures => ({
|
|
1270
|
+
...failures,
|
|
1271
|
+
[row]: result.failed
|
|
1272
|
+
}));
|
|
1273
|
+
setAnnouncement({
|
|
1274
|
+
text: result.failed
|
|
1275
|
+
});
|
|
1276
|
+
} else if (disposed) props.onError?.(new Error(result.failed));else showCommandStatus({
|
|
1277
|
+
tone: "error",
|
|
1278
|
+
text: result.failed
|
|
1279
|
+
});
|
|
1280
|
+
};
|
|
1281
|
+
|
|
853
1282
|
/** Replaces `start`–`end` with the emoji through the editing path, so the browser's undo restores the shortcode. */
|
|
854
1283
|
const insertEmoji = (start, end, emoji) => {
|
|
855
1284
|
if (!textareaRef || editBlocked()) return;
|
|
@@ -890,9 +1319,66 @@ export function ChatComposer(props) {
|
|
|
890
1319
|
if (untouched && textarea.matches(":focus")) convert(loaded);
|
|
891
1320
|
}, () => undefined);
|
|
892
1321
|
};
|
|
1322
|
+
|
|
1323
|
+
/** Moving through and choosing in the command list, from the field or from the search field opened by "+". */
|
|
1324
|
+
const commandListKey = event => {
|
|
1325
|
+
if (!commandsOpen()) return false;
|
|
1326
|
+
const matches = commandMatches();
|
|
1327
|
+
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
1328
|
+
event.preventDefault();
|
|
1329
|
+
const index = matches.indexOf(selectedCommand());
|
|
1330
|
+
const next = matches[nextChatCommandIndex(index, matches.length, event.key === "ArrowUp" ? -1 : 1)];
|
|
1331
|
+
setActiveCommandKey(next ? chatCommandKey(next) : undefined);
|
|
1332
|
+
setCommandMoved(true);
|
|
1333
|
+
setAnnouncement(undefined);
|
|
1334
|
+
return true;
|
|
1335
|
+
}
|
|
1336
|
+
// Ctrl/⌘+Enter sends, also while suggestions are open.
|
|
1337
|
+
const plain = !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
1338
|
+
if (plain && (event.key === "Tab" || event.key === "Enter") && matches.length > 0) {
|
|
1339
|
+
event.preventDefault();
|
|
1340
|
+
const command = selectedCommand();
|
|
1341
|
+
// A server row answering an earlier query may no longer match; wait for fresh results. Local rows match now.
|
|
1342
|
+
const row = commandModel().rows.find(row => chatCommandKey(row.command) === selectedCommandKey());
|
|
1343
|
+
const staleServerRow = row?.server && (searchResultsQuery() !== commandQuery()?.query || searchResultsScope() !== parsedCommandQuery().scope?.id);
|
|
1344
|
+
if (staleServerRow) return true;
|
|
1345
|
+
if (command) void executeCommand(command, event.key === "Tab");
|
|
1346
|
+
return true;
|
|
1347
|
+
}
|
|
1348
|
+
if (event.key === "Escape") {
|
|
1349
|
+
event.preventDefault();
|
|
1350
|
+
closeCommandList();
|
|
1351
|
+
return true;
|
|
1352
|
+
}
|
|
1353
|
+
return false;
|
|
1354
|
+
};
|
|
1355
|
+
const onAddSearchKeyDown = event => {
|
|
1356
|
+
// Nothing chooses while an input method composes, as in the field.
|
|
1357
|
+
if (event.isComposing || event.keyCode === 229 || addComposing) return;
|
|
1358
|
+
if (event.key === "Escape" && openingRun) {
|
|
1359
|
+
event.preventDefault();
|
|
1360
|
+
openingRun.controller.abort();
|
|
1361
|
+
endAddSearch(true);
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
if (commandListKey(event)) return;
|
|
1365
|
+
// Ctrl/⌘+Enter sends from the search field as from the field, with the list closed first.
|
|
1366
|
+
if (event.key === "Enter" && (event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey) {
|
|
1367
|
+
event.preventDefault();
|
|
1368
|
+
endAddSearch(true);
|
|
1369
|
+
void submit();
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
893
1372
|
const onKeyDown = event => {
|
|
894
1373
|
// WebKit ends the composition before the keydown of the Enter that confirms it; that keydown keeps keyCode 229.
|
|
895
1374
|
if (event.isComposing || event.keyCode === 229 || composing()) return;
|
|
1375
|
+
// Escape cancels a running `open` row, also once its list is gone because the draft moved to a new chat.
|
|
1376
|
+
if (event.key === "Escape" && openingRun) {
|
|
1377
|
+
event.preventDefault();
|
|
1378
|
+
openingRun.controller.abort();
|
|
1379
|
+
if (commandsOpen()) closeCommandList();
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
896
1382
|
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "z") {
|
|
897
1383
|
event.preventDefault();
|
|
898
1384
|
restoreHistory(event.shiftKey ? 1 : -1);
|
|
@@ -917,38 +1403,11 @@ export function ChatComposer(props) {
|
|
|
917
1403
|
return;
|
|
918
1404
|
}
|
|
919
1405
|
}
|
|
920
|
-
|
|
921
|
-
if (commandsOpen()) {
|
|
922
|
-
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
923
|
-
event.preventDefault();
|
|
924
|
-
const index = matches.indexOf(selectedCommand());
|
|
925
|
-
const next = matches[nextChatCommandIndex(index, matches.length, event.key === "ArrowUp" ? -1 : 1)];
|
|
926
|
-
setActiveCommandKey(next ? chatCommandKey(next) : undefined);
|
|
927
|
-
setCommandMoved(true);
|
|
928
|
-
setAnnouncement(undefined);
|
|
929
|
-
return;
|
|
930
|
-
}
|
|
931
|
-
// Ctrl/⌘+Enter sends, also while suggestions are open.
|
|
932
|
-
const plain = !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
933
|
-
if (plain && (event.key === "Tab" || event.key === "Enter") && matches.length > 0) {
|
|
934
|
-
event.preventDefault();
|
|
935
|
-
const command = selectedCommand();
|
|
936
|
-
// A server row answering an earlier query may no longer match; wait for fresh results. Local rows match now.
|
|
937
|
-
const row = commandModel().rows.find(row => chatCommandKey(row.command) === selectedCommandKey());
|
|
938
|
-
const staleServerRow = row?.server && (searchResultsQuery() !== commandQuery()?.query || searchResultsScope() !== parsedCommandQuery().scope?.id);
|
|
939
|
-
if (staleServerRow) return;
|
|
940
|
-
if (command) void executeCommand(command, event.key === "Tab");
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
if (event.key === "Escape") {
|
|
944
|
-
event.preventDefault();
|
|
945
|
-
setClosedAt(commandQuery()?.start);
|
|
946
|
-
return;
|
|
947
|
-
}
|
|
948
|
-
}
|
|
1406
|
+
if (commandListKey(event)) return;
|
|
949
1407
|
const format = props.formatting && textareaRef ? formatShortcut(event) : undefined;
|
|
950
1408
|
if (format && textareaRef) {
|
|
951
1409
|
event.preventDefault();
|
|
1410
|
+
if (editBlocked()) return;
|
|
952
1411
|
format.run(textareaRef);
|
|
953
1412
|
return;
|
|
954
1413
|
}
|
|
@@ -1071,8 +1530,46 @@ export function ChatComposer(props) {
|
|
|
1071
1530
|
}
|
|
1072
1531
|
});
|
|
1073
1532
|
|
|
1533
|
+
/** "+" as the way to the slash list on keyboards without a handy "/". */
|
|
1534
|
+
const addSearchButton = (extraClass = "") => _$createComponent(Tooltip.Trigger, {
|
|
1535
|
+
type: "button",
|
|
1536
|
+
"class": `k2b-chat-composer__icon-action${extraClass}`,
|
|
1537
|
+
get ["aria-label"]() {
|
|
1538
|
+
return chatMessages().addMenu;
|
|
1539
|
+
},
|
|
1540
|
+
"aria-haspopup": "listbox",
|
|
1541
|
+
get ["aria-expanded"]() {
|
|
1542
|
+
return addSearch() !== undefined;
|
|
1543
|
+
},
|
|
1544
|
+
get ["aria-controls"]() {
|
|
1545
|
+
return addSearch() ? commandListId : undefined;
|
|
1546
|
+
},
|
|
1547
|
+
get content() {
|
|
1548
|
+
return chatMessages().addMenu;
|
|
1549
|
+
},
|
|
1550
|
+
get disabled() {
|
|
1551
|
+
return blocked();
|
|
1552
|
+
},
|
|
1553
|
+
onMouseDown: keepFieldFocus,
|
|
1554
|
+
onClick: toggleAddSearch,
|
|
1555
|
+
get children() {
|
|
1556
|
+
return _$ssr(_tmpl$3, _$ssrAttribute("class", addingFiles() ? "ti ti-loader-2 k2b-spin" : "ti ti-plus", false));
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1074
1560
|
/** The conversation's attach button opens the file choice directly; other actions turn it into the add menu. */
|
|
1075
1561
|
const attachControl = () => _$createComponent(Show, {
|
|
1562
|
+
get when() {
|
|
1563
|
+
return !addOpensCommands();
|
|
1564
|
+
},
|
|
1565
|
+
get fallback() {
|
|
1566
|
+
return addSearchButton(" k2b-chat-composer__attach");
|
|
1567
|
+
},
|
|
1568
|
+
get children() {
|
|
1569
|
+
return attachChoice();
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
const attachChoice = () => _$createComponent(Show, {
|
|
1076
1573
|
get when() {
|
|
1077
1574
|
return props.menuActions?.length;
|
|
1078
1575
|
},
|
|
@@ -1093,7 +1590,7 @@ export function ChatComposer(props) {
|
|
|
1093
1590
|
get disabled() {
|
|
1094
1591
|
return !canSelectFiles();
|
|
1095
1592
|
},
|
|
1096
|
-
onClick: chooseFiles,
|
|
1593
|
+
onClick: () => chooseFiles(),
|
|
1097
1594
|
get children() {
|
|
1098
1595
|
return _$ssr(_tmpl$3, _$ssrAttribute("class", addingFiles() ? "ti ti-loader-2 k2b-spin" : "ti ti-plus", false));
|
|
1099
1596
|
}
|
|
@@ -1356,7 +1853,7 @@ export function ChatComposer(props) {
|
|
|
1356
1853
|
children: part => _$ssr(_tmpl$10, Boolean(part.mention) ? "k2b-chat-composer__mention" : "", _$escape(part.text))
|
|
1357
1854
|
})));
|
|
1358
1855
|
}
|
|
1359
|
-
})), mentions().length > 0 ? "k2b-chat-composer__textarea--highlighted" : "", _$ssrAttribute("value", _$escape(props.value, true), false), _$ssrAttribute("disabled", editBlocked(), true) + _$ssrAttribute("enterkeyhint", conversation() ? "enter" : _$escape(undefined, true), false) + _$ssrAttribute("placeholder", _$escape(props.placeholder ?? (running() ? chatMessages().addGuidance : conversation() ? chatMessages().writeConversationMessage : chatMessages().writeMessage), true), false) + _$ssrAttribute("aria-label", _$escape(props.inputLabel ?? messages().message, true), false) + _$ssrAttribute("role",
|
|
1856
|
+
})), mentions().length > 0 ? "k2b-chat-composer__textarea--highlighted" : "", _$ssrAttribute("value", _$escape(props.value, true), false), _$ssrAttribute("disabled", editBlocked() && openingRow() === undefined, true) + _$ssrAttribute("readonly", _$escape(openingRow(), true) !== _$escape(undefined, true), false) + _$ssrAttribute("enterkeyhint", conversation() ? "enter" : _$escape(undefined, true), false) + _$ssrAttribute("placeholder", _$escape(props.placeholder ?? (running() ? chatMessages().addGuidance : conversation() ? chatMessages().writeConversationMessage : chatMessages().writeMessage), true), false) + _$ssrAttribute("aria-label", _$escape(props.inputLabel ?? messages().message, true), false) + _$ssrAttribute("role", fieldOwnsList() ? "combobox" : _$escape(undefined, true), false) + _$ssrAttribute("aria-autocomplete", fieldOwnsList() ? "list" : _$escape(undefined, true), false) + _$ssrAttribute("aria-controls", fieldOwnsList() ? _$escape(commandListId, true) : _$escape(undefined, true), false) + _$ssrAttribute("aria-expanded", fieldOwnsList() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("aria-activedescendant", !fieldOwnsList() ? _$escape(undefined, true) : emojiOpen() ? `${_$escape(commandListId, true)}-${_$escape(selectedCommandIndex(), true)}` : selectedCommand() ? _$escape(commandOptionId(selectedCommand()), true) : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
|
|
1360
1857
|
get when() {
|
|
1361
1858
|
return conversation();
|
|
1362
1859
|
},
|
|
@@ -1369,7 +1866,9 @@ export function ChatComposer(props) {
|
|
|
1369
1866
|
const renderCommandRow = command => {
|
|
1370
1867
|
const highlight = () => commandRowMap().get(command)?.highlight;
|
|
1371
1868
|
const title = () => command.label ?? command.name;
|
|
1372
|
-
|
|
1869
|
+
const opening = () => openingRow() === chatCommandKey(command);
|
|
1870
|
+
const failure = () => openFailures()[chatCommandKey(command)];
|
|
1871
|
+
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-busy", opening() ? "true" : _$escape(undefined, 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, {
|
|
1373
1872
|
get when() {
|
|
1374
1873
|
return highlight();
|
|
1375
1874
|
},
|
|
@@ -1379,10 +1878,20 @@ export function ChatComposer(props) {
|
|
|
1379
1878
|
children: range => [title().slice(0, range()[0]), _$ssr(_tmpl$14, _$escape(title().slice(range()[0], range()[1]))), title().slice(range()[1])]
|
|
1380
1879
|
})), _$escape(_$createComponent(Show, {
|
|
1381
1880
|
get when() {
|
|
1382
|
-
return command.
|
|
1881
|
+
return _$memo(() => !!command.open)() && !command.reason;
|
|
1882
|
+
},
|
|
1883
|
+
get fallback() {
|
|
1884
|
+
return _$createComponent(Show, {
|
|
1885
|
+
get when() {
|
|
1886
|
+
return command.reason ?? command.description;
|
|
1887
|
+
},
|
|
1888
|
+
get children() {
|
|
1889
|
+
return _$ssr(_tmpl$15, _$ssrAttribute("id", command.reason ? `${_$escape(commandOptionId(command), true)}-reason` : _$escape(undefined, true), false), _$escape(command.reason ?? command.description));
|
|
1890
|
+
}
|
|
1891
|
+
});
|
|
1383
1892
|
},
|
|
1384
1893
|
get children() {
|
|
1385
|
-
return _$ssr(_tmpl$11, _$ssrAttribute("
|
|
1894
|
+
return _$ssr(_tmpl$11, _$ssrAttribute("data-state", opening() ? "busy" : failure() ? "failed" : _$escape(undefined, true), false), _$ssrAttribute("aria-hidden", opening() ? "true" : _$escape(undefined, true), false), _$escape(failure() ?? command.description), _$ssrAttribute("aria-hidden", opening() ? _$escape(undefined, true) : "true", false), _$escape(command.busyLabel ?? chatMessages().commandOpening));
|
|
1386
1895
|
}
|
|
1387
1896
|
})), _$escape(_$createComponent(Show, {
|
|
1388
1897
|
get when() {
|
|
@@ -1393,25 +1902,25 @@ export function ChatComposer(props) {
|
|
|
1393
1902
|
}
|
|
1394
1903
|
})));
|
|
1395
1904
|
};
|
|
1396
|
-
return _$ssr(_tmpl$
|
|
1905
|
+
return _$ssr(_tmpl$27, _$escape(_$createComponent(Show, {
|
|
1397
1906
|
get when() {
|
|
1398
1907
|
return suggestionsOpen() || hasAccessory();
|
|
1399
1908
|
},
|
|
1400
1909
|
get children() {
|
|
1401
|
-
return _$ssr(_tmpl$
|
|
1910
|
+
return _$ssr(_tmpl$22, _$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, {
|
|
1402
1911
|
get when() {
|
|
1403
1912
|
return emojiOpen();
|
|
1404
1913
|
},
|
|
1405
1914
|
get children() {
|
|
1406
|
-
return _$ssr(_tmpl$
|
|
1915
|
+
return _$ssr(_tmpl$16, _$ssrAttribute("id", _$escape(commandListId, true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().emojiSuggestions, true), false), _$escape(_$createComponent(For, {
|
|
1407
1916
|
get each() {
|
|
1408
1917
|
return emojiMatches();
|
|
1409
1918
|
},
|
|
1410
|
-
children: (entry, index) => _$ssr(_tmpl$
|
|
1919
|
+
children: (entry, index) => _$ssr(_tmpl$28, `${_$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, {
|
|
1411
1920
|
get when() {
|
|
1412
1921
|
return entry.shortcodes[0];
|
|
1413
1922
|
},
|
|
1414
|
-
children: code => _$ssr(_tmpl$
|
|
1923
|
+
children: code => _$ssr(_tmpl$29, _$escape(code()))
|
|
1415
1924
|
})))
|
|
1416
1925
|
})));
|
|
1417
1926
|
}
|
|
@@ -1420,7 +1929,14 @@ export function ChatComposer(props) {
|
|
|
1420
1929
|
return commandsOpen();
|
|
1421
1930
|
},
|
|
1422
1931
|
get children() {
|
|
1423
|
-
return _$ssr(_tmpl$
|
|
1932
|
+
return _$ssr(_tmpl$21, _$ssrAttribute("data-search", addSearch() ? "" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
|
|
1933
|
+
get when() {
|
|
1934
|
+
return addSearch();
|
|
1935
|
+
},
|
|
1936
|
+
get children() {
|
|
1937
|
+
return _$ssr(_tmpl$17, _$ssrAttribute("value", _$escape(addQuery(), true), false) + _$ssrAttribute("placeholder", _$escape(chatMessages().commandSearch, true), false) + _$ssrAttribute("aria-label", _$escape(chatMessages().commandSearchLabel, true), false), _$ssrAttribute("aria-controls", _$escape(commandListId, true), false), _$ssrAttribute("aria-activedescendant", selectedCommand() ? _$escape(commandOptionId(selectedCommand()), true) : _$escape(undefined, true), false), _$ssrAttribute("readonly", _$escape(openingRow(), true) !== _$escape(undefined, true), false));
|
|
1938
|
+
}
|
|
1939
|
+
})), _$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, {
|
|
1424
1940
|
get each() {
|
|
1425
1941
|
return commandModel().groups.map(commandGroupKey);
|
|
1426
1942
|
},
|
|
@@ -1439,52 +1955,58 @@ export function ChatComposer(props) {
|
|
|
1439
1955
|
});
|
|
1440
1956
|
},
|
|
1441
1957
|
get children() {
|
|
1442
|
-
return _$ssr(_tmpl$
|
|
1958
|
+
return _$ssr(_tmpl$31, _$ssrAttribute("aria-labelledby", _$escape(headingId(), true), false), _$ssrAttribute("id", _$escape(headingId(), true), false), _$escape(group()?.scopeTitle ?? group()?.section?.label), _$escape(_$createComponent(Show, {
|
|
1443
1959
|
get when() {
|
|
1444
1960
|
return group()?.loading;
|
|
1445
1961
|
},
|
|
1446
1962
|
get children() {
|
|
1447
|
-
return _$ssr(_tmpl$
|
|
1963
|
+
return _$ssr(_tmpl$30);
|
|
1448
1964
|
}
|
|
1449
1965
|
})), _$escape(_$createComponent(For, {
|
|
1450
1966
|
get each() {
|
|
1451
1967
|
return rows();
|
|
1452
1968
|
},
|
|
1453
1969
|
children: renderCommandRow
|
|
1454
|
-
})), _$escape(_$createComponent(
|
|
1455
|
-
get
|
|
1456
|
-
return
|
|
1970
|
+
})), _$escape(_$createComponent(Index, {
|
|
1971
|
+
get each() {
|
|
1972
|
+
return Array.from({
|
|
1973
|
+
length: Math.max(group()?.placeholder ? 1 : 0, group()?.pendingRows ?? 0)
|
|
1974
|
+
});
|
|
1457
1975
|
},
|
|
1458
|
-
|
|
1459
|
-
return _$ssr(_tmpl$29);
|
|
1460
|
-
}
|
|
1976
|
+
children: () => _$ssr(_tmpl$32)
|
|
1461
1977
|
})));
|
|
1462
1978
|
}
|
|
1463
1979
|
});
|
|
1464
1980
|
}
|
|
1465
1981
|
})), _$escape(_$createComponent(Show, {
|
|
1466
1982
|
get when() {
|
|
1467
|
-
return _$memo(() => !!(searching() &&
|
|
1983
|
+
return _$memo(() => !!(searching() && foundCommandCount() === 0))() && !commandModel().groups.some(group => group.section || group.scopeTitle);
|
|
1468
1984
|
},
|
|
1469
1985
|
get children() {
|
|
1470
|
-
return _$ssr(_tmpl$
|
|
1986
|
+
return _$ssr(_tmpl$18, _$escape(messages().loading));
|
|
1471
1987
|
}
|
|
1472
1988
|
})), _$escape(_$createComponent(Show, {
|
|
1473
1989
|
get when() {
|
|
1474
1990
|
return searchError();
|
|
1475
1991
|
},
|
|
1476
1992
|
get children() {
|
|
1477
|
-
return _$ssr(_tmpl$
|
|
1993
|
+
return _$ssr(_tmpl$19, _$escape(messages().error));
|
|
1478
1994
|
}
|
|
1479
1995
|
})), _$escape(_$createComponent(Show, {
|
|
1480
1996
|
get when() {
|
|
1481
|
-
return _$memo(() => !!(!searching() && !searchError()))() &&
|
|
1997
|
+
return _$memo(() => !!(!searching() && !searchError() && foundCommandCount() === 0))() && !commandModel().groups.some(group => group.pendingRows);
|
|
1482
1998
|
},
|
|
1483
1999
|
get children() {
|
|
1484
|
-
return _$ssr(_tmpl$
|
|
2000
|
+
return _$ssr(_tmpl$20, !parsedCommandQuery().query.trim() ? _$escape(messages().noResults) : _$escape(chatMessages().commandsNothingFound({
|
|
1485
2001
|
query: parsedCommandQuery().query.trim()
|
|
1486
2002
|
})));
|
|
1487
2003
|
}
|
|
2004
|
+
})), _$escape(_$createComponent(Show, {
|
|
2005
|
+
get when() {
|
|
2006
|
+
return commandModel().fallback?.command;
|
|
2007
|
+
},
|
|
2008
|
+
keyed: true,
|
|
2009
|
+
children: command => renderCommandRow(command)
|
|
1488
2010
|
})));
|
|
1489
2011
|
}
|
|
1490
2012
|
})));
|
|
@@ -1494,18 +2016,18 @@ export function ChatComposer(props) {
|
|
|
1494
2016
|
return showHint();
|
|
1495
2017
|
},
|
|
1496
2018
|
get children() {
|
|
1497
|
-
return _$ssr(_tmpl$
|
|
2019
|
+
return _$ssr(_tmpl$23, _$escape(_$createComponent(Show, {
|
|
1498
2020
|
get when() {
|
|
1499
2021
|
return dictationStatus();
|
|
1500
2022
|
},
|
|
1501
2023
|
get fallback() {
|
|
1502
|
-
return _$ssr(_tmpl$
|
|
2024
|
+
return _$ssr(_tmpl$33, _$escape(hint()));
|
|
1503
2025
|
},
|
|
1504
|
-
children: status => [_$ssr(_tmpl$
|
|
2026
|
+
children: status => [_$ssr(_tmpl$34, _$ssrAttribute("data-state", _$escape(dictation() ?? undefined, true), false), _$ssrAttribute("class", _$escape(status().icon, true), false), _$escape(status().text)), _$createComponent(Show, {
|
|
1505
2027
|
get when() {
|
|
1506
2028
|
return _$memo(() => dictation() === "refined")() ? props.microphone?.onRestoreOriginal : undefined;
|
|
1507
2029
|
},
|
|
1508
|
-
children: restore => _$ssr(_tmpl$
|
|
2030
|
+
children: restore => _$ssr(_tmpl$35, _$ssrAttribute("disabled", microphoneDisabled(), true), _$escape(chatMessages().restoreOriginal))
|
|
1509
2031
|
})]
|
|
1510
2032
|
})));
|
|
1511
2033
|
}
|
|
@@ -1514,16 +2036,16 @@ export function ChatComposer(props) {
|
|
|
1514
2036
|
return attachments().length > 0;
|
|
1515
2037
|
},
|
|
1516
2038
|
get children() {
|
|
1517
|
-
return _$ssr(_tmpl$
|
|
2039
|
+
return _$ssr(_tmpl$24, _$ssrAttribute("aria-label", _$escape(chatMessages().attachments, true), false), _$escape(_$createComponent(For, {
|
|
1518
2040
|
get each() {
|
|
1519
2041
|
return attachments();
|
|
1520
2042
|
},
|
|
1521
|
-
children: attachment => _$ssr(_tmpl$
|
|
2043
|
+
children: attachment => _$ssr(_tmpl$37, `k2b-chat-composer__attachment-content ${Boolean(attachment.action) ? "k2b-chat-composer__attachment-content--action" : ""}`, _$escape(_$createComponent(Show, {
|
|
1522
2044
|
get when() {
|
|
1523
2045
|
return attachment.href;
|
|
1524
2046
|
},
|
|
1525
2047
|
get fallback() {
|
|
1526
|
-
return _$ssr(_tmpl$
|
|
2048
|
+
return _$ssr(_tmpl$39, _$escape(_$createComponent(Show, {
|
|
1527
2049
|
get when() {
|
|
1528
2050
|
return _$memo(() => attachment.kind === "image")() && attachment.previewUrl;
|
|
1529
2051
|
},
|
|
@@ -1531,11 +2053,11 @@ export function ChatComposer(props) {
|
|
|
1531
2053
|
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
|
|
1532
2054
|
},
|
|
1533
2055
|
get children() {
|
|
1534
|
-
return _$ssr(_tmpl$
|
|
2056
|
+
return _$ssr(_tmpl$38, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
|
|
1535
2057
|
}
|
|
1536
2058
|
})), _$escape(renderAttachmentCopy(attachment)));
|
|
1537
2059
|
},
|
|
1538
|
-
children: href => _$ssr(_tmpl$
|
|
2060
|
+
children: href => _$ssr(_tmpl$40, _$ssrAttribute("href", _$escape(href(), true), false), _$ssrAttribute("aria-label", _$escape(chatMessages().openInNewTab({
|
|
1539
2061
|
name: attachment.name
|
|
1540
2062
|
}), true), false), _$escape(_$createComponent(Show, {
|
|
1541
2063
|
get when() {
|
|
@@ -1545,14 +2067,14 @@ export function ChatComposer(props) {
|
|
|
1545
2067
|
return _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(attachmentIcon(attachment), true), false));
|
|
1546
2068
|
},
|
|
1547
2069
|
get children() {
|
|
1548
|
-
return _$ssr(_tmpl$
|
|
2070
|
+
return _$ssr(_tmpl$38, _$ssrAttribute("src", _$escape(attachment.previewUrl, true), false) + _$ssrAttribute("alt", _$escape(attachment.alt ?? "", true), false));
|
|
1549
2071
|
}
|
|
1550
2072
|
})), _$escape(renderAttachmentCopy(attachment)))
|
|
1551
2073
|
})), _$escape(_$createComponent(Show, {
|
|
1552
2074
|
get when() {
|
|
1553
2075
|
return attachment.action;
|
|
1554
2076
|
},
|
|
1555
|
-
children: action => _$ssr(_tmpl$
|
|
2077
|
+
children: action => _$ssr(_tmpl$41, _$ssrAttribute("disabled", blocked() || action().disabled, true), _$escape(_$createComponent(Show, {
|
|
1556
2078
|
get when() {
|
|
1557
2079
|
return action().icon;
|
|
1558
2080
|
},
|
|
@@ -1563,7 +2085,7 @@ export function ChatComposer(props) {
|
|
|
1563
2085
|
return props.onAttachmentsChange;
|
|
1564
2086
|
},
|
|
1565
2087
|
get children() {
|
|
1566
|
-
return _$ssr(_tmpl$
|
|
2088
|
+
return _$ssr(_tmpl$36, _$ssrAttribute("aria-label", _$escape(selectMessages().removeNamed({
|
|
1567
2089
|
name: attachment.name
|
|
1568
2090
|
}), true), false), _$ssrAttribute("disabled", blocked(), true));
|
|
1569
2091
|
}
|
|
@@ -1580,19 +2102,29 @@ export function ChatComposer(props) {
|
|
|
1580
2102
|
return props.error;
|
|
1581
2103
|
},
|
|
1582
2104
|
get children() {
|
|
1583
|
-
return _$ssr(_tmpl$
|
|
2105
|
+
return _$ssr(_tmpl$25, _$escape(props.error));
|
|
1584
2106
|
}
|
|
1585
|
-
}), formatRow(), _$ssr(_tmpl$
|
|
2107
|
+
}), formatRow(), _$ssr(_tmpl$42, _$escape(_$createComponent(Show, {
|
|
1586
2108
|
get when() {
|
|
1587
2109
|
return footer();
|
|
1588
2110
|
},
|
|
1589
2111
|
get fallback() {
|
|
1590
|
-
return [_$ssr(_tmpl$
|
|
2112
|
+
return [_$ssr(_tmpl$43, _$escape(props.footerTools), _$escape(_$createComponent(Show, {
|
|
1591
2113
|
get when() {
|
|
1592
|
-
return
|
|
2114
|
+
return addOpensCommands();
|
|
2115
|
+
},
|
|
2116
|
+
get fallback() {
|
|
2117
|
+
return _$createComponent(Show, {
|
|
2118
|
+
get when() {
|
|
2119
|
+
return hasAddMenu();
|
|
2120
|
+
},
|
|
2121
|
+
get children() {
|
|
2122
|
+
return addMenu("ti ti-plus");
|
|
2123
|
+
}
|
|
2124
|
+
});
|
|
1593
2125
|
},
|
|
1594
2126
|
get children() {
|
|
1595
|
-
return
|
|
2127
|
+
return addSearchButton();
|
|
1596
2128
|
}
|
|
1597
2129
|
})), _$escape(fileInput()), _$escape(formatToggle()), _$escape(emojiButton()), _$escape(_$createComponent(Show, {
|
|
1598
2130
|
get when() {
|
|
@@ -1640,7 +2172,7 @@ export function ChatComposer(props) {
|
|
|
1640
2172
|
}
|
|
1641
2173
|
});
|
|
1642
2174
|
}
|
|
1643
|
-
})), _$escape(props.modelDetails)), _$ssr(_tmpl$
|
|
2175
|
+
})), _$escape(props.modelDetails)), _$ssr(_tmpl$44, _$escape(_$createComponent(For, {
|
|
1644
2176
|
get each() {
|
|
1645
2177
|
return props.contextActions;
|
|
1646
2178
|
},
|
|
@@ -1692,9 +2224,9 @@ export function ChatComposer(props) {
|
|
|
1692
2224
|
return props.error;
|
|
1693
2225
|
},
|
|
1694
2226
|
get children() {
|
|
1695
|
-
return _$ssr(_tmpl$
|
|
2227
|
+
return _$ssr(_tmpl$25, _$escape(props.error));
|
|
1696
2228
|
}
|
|
1697
|
-
}), formatRow(), _$ssr(_tmpl$
|
|
2229
|
+
}), formatRow(), _$ssr(_tmpl$26, _$escape(attachControl()), _$escape(fileInput()), _$escape(field()), _$escape(formatToggle()), _$escape(emojiButton()), _$escape(microphoneControl()), _$escape(sendControl()))];
|
|
1698
2230
|
}
|
|
1699
2231
|
})), _$escape(_$createComponent(Show, {
|
|
1700
2232
|
get when() {
|
|
@@ -1720,18 +2252,18 @@ export function ChatComposer(props) {
|
|
|
1720
2252
|
return suggestionAnnouncement();
|
|
1721
2253
|
},
|
|
1722
2254
|
keyed: true,
|
|
1723
|
-
children: announced => _$ssr(_tmpl$
|
|
2255
|
+
children: announced => _$ssr(_tmpl$45, _$escape(announced.text))
|
|
1724
2256
|
})), _$escape(_$createComponent(Show, {
|
|
1725
2257
|
get when() {
|
|
1726
2258
|
return _$memo(() => !!!suggestionsOpen())() && commandStatus();
|
|
1727
2259
|
},
|
|
1728
|
-
children: status => _$ssr(_tmpl$
|
|
2260
|
+
children: status => _$ssr(_tmpl$46, _$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))
|
|
1729
2261
|
})), _$escape(_$createComponent(Show, {
|
|
1730
2262
|
get when() {
|
|
1731
2263
|
return _$memo(() => !!suggestionsOpen())() && announcement();
|
|
1732
2264
|
},
|
|
1733
2265
|
keyed: true,
|
|
1734
|
-
children: announced => _$ssr(_tmpl$
|
|
2266
|
+
children: announced => _$ssr(_tmpl$47, _$escape(announced.text))
|
|
1735
2267
|
})));
|
|
1736
2268
|
}
|
|
1737
2269
|
//# sourceMappingURL=ChatComposer.js.map
|