@classic-homes/agent-chat 0.1.2 → 0.2.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 +40 -0
- package/dist/components/AgentChat.svelte +65 -39
- package/dist/components/AgentChat.svelte.d.ts +2 -0
- package/dist/components/AgentChat.svelte.d.ts.map +1 -1
- package/dist/components/ArtifactPanel.svelte +79 -96
- package/dist/components/ArtifactPanel.svelte.d.ts +2 -0
- package/dist/components/ArtifactPanel.svelte.d.ts.map +1 -1
- package/dist/components/ChatHeader.svelte +122 -0
- package/dist/components/ChatHeader.svelte.d.ts +27 -0
- package/dist/components/ChatHeader.svelte.d.ts.map +1 -0
- package/dist/components/Composer.svelte +78 -121
- package/dist/components/Composer.svelte.d.ts.map +1 -1
- package/dist/components/ConversationDialogs.svelte +134 -0
- package/dist/components/ConversationDialogs.svelte.d.ts +25 -0
- package/dist/components/ConversationDialogs.svelte.d.ts.map +1 -0
- package/dist/components/ConversationSidebar.svelte +135 -114
- package/dist/components/ConversationSidebar.svelte.d.ts +8 -2
- package/dist/components/ConversationSidebar.svelte.d.ts.map +1 -1
- package/dist/components/Markdown.svelte +48 -0
- package/dist/components/Markdown.svelte.d.ts +16 -0
- package/dist/components/Markdown.svelte.d.ts.map +1 -0
- package/dist/components/MessageItem.svelte +27 -116
- package/dist/components/MessageItem.svelte.d.ts.map +1 -1
- package/dist/components/MessageList.svelte +23 -34
- package/dist/components/ModeBanner.svelte +7 -13
- package/dist/components/ModeBanner.svelte.d.ts.map +1 -1
- package/dist/components/SandboxFrame.svelte +43 -0
- package/dist/components/SandboxFrame.svelte.d.ts +13 -0
- package/dist/components/SandboxFrame.svelte.d.ts.map +1 -0
- package/dist/components/ToolTimeline.svelte +17 -68
- package/dist/components/ToolTimeline.svelte.d.ts.map +1 -1
- package/dist/components/UiFrame.svelte +9 -55
- package/dist/components/UiFrame.svelte.d.ts.map +1 -1
- package/dist/components/conversation-chrome.svelte.test.d.ts +2 -0
- package/dist/components/conversation-chrome.svelte.test.d.ts.map +1 -0
- package/dist/components/conversation-chrome.svelte.test.js +127 -0
- package/dist/components/markdown-prose.svelte.test.d.ts +2 -0
- package/dist/components/markdown-prose.svelte.test.d.ts.map +1 -0
- package/dist/components/markdown-prose.svelte.test.js +26 -0
- package/dist/composer-keys.d.ts +11 -0
- package/dist/composer-keys.d.ts.map +1 -0
- package/dist/composer-keys.js +10 -0
- package/dist/composer-keys.test.d.ts +2 -0
- package/dist/composer-keys.test.d.ts.map +1 -0
- package/dist/composer-keys.test.js +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/reducer.d.ts +10 -0
- package/dist/reducer.d.ts.map +1 -1
- package/dist/reducer.js +19 -1
- package/dist/reducer.test.js +29 -1
- package/dist/session.svelte.d.ts +6 -0
- package/dist/session.svelte.d.ts.map +1 -1
- package/dist/session.svelte.js +15 -1
- package/dist/ui-frame-protocol.d.ts +2 -2
- package/dist/ui-frame-protocol.js +2 -2
- package/dist/ui-frame-relay.d.ts +16 -0
- package/dist/ui-frame-relay.d.ts.map +1 -0
- package/dist/ui-frame-relay.js +22 -0
- package/dist/ui-frame-relay.test.d.ts +2 -0
- package/dist/ui-frame-relay.test.d.ts.map +1 -0
- package/dist/ui-frame-relay.test.js +36 -0
- package/package.json +8 -5
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { Button, Icon } from '@classic-homes/theme-svelte';
|
|
2
|
+
import { Button, Icon, Textarea } from '@classic-homes/theme-svelte';
|
|
3
3
|
import type { FileRef } from '@classic-homes/agent-contracts';
|
|
4
4
|
import { LIMITS } from '@classic-homes/agent-contracts';
|
|
5
|
+
import { composerKeyAction } from '../composer-keys.js';
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
disabled?: boolean;
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
context,
|
|
31
32
|
}: Props = $props();
|
|
32
33
|
|
|
33
|
-
let textarea
|
|
34
|
+
let textarea = $state<HTMLTextAreaElement | null>(null);
|
|
34
35
|
let fileInput: HTMLInputElement | undefined = $state();
|
|
35
36
|
let uploading = $state(0);
|
|
36
37
|
let uploadError = $state<string | undefined>();
|
|
@@ -43,20 +44,18 @@
|
|
|
43
44
|
const text = value.trim();
|
|
44
45
|
if (!text || disabled || streaming || uploading > 0) return;
|
|
45
46
|
value = '';
|
|
46
|
-
if (textarea) textarea.style.height = 'auto';
|
|
47
47
|
onsend?.(text);
|
|
48
48
|
}
|
|
49
49
|
function onkeydown(event: KeyboardEvent): void {
|
|
50
|
-
|
|
50
|
+
const action = composerKeyAction(event, streaming);
|
|
51
|
+
if (action === 'send') {
|
|
51
52
|
event.preventDefault();
|
|
52
53
|
submit();
|
|
54
|
+
} else if (action === 'cancel') {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
oncancel?.();
|
|
53
57
|
}
|
|
54
58
|
}
|
|
55
|
-
function autosize(): void {
|
|
56
|
-
if (!textarea) return;
|
|
57
|
-
textarea.style.height = 'auto';
|
|
58
|
-
textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
|
|
59
|
-
}
|
|
60
59
|
async function onfiles(event: Event): Promise<void> {
|
|
61
60
|
const input = event.currentTarget as HTMLInputElement;
|
|
62
61
|
const chosen = [...(input.files ?? [])];
|
|
@@ -81,131 +80,89 @@
|
|
|
81
80
|
</script>
|
|
82
81
|
|
|
83
82
|
<form
|
|
84
|
-
class="
|
|
83
|
+
class="bg-background px-4 pb-[max(0.75rem,env(safe-area-inset-bottom))] pt-2"
|
|
85
84
|
onsubmit={(e) => {
|
|
86
85
|
e.preventDefault();
|
|
87
86
|
submit();
|
|
88
87
|
}}
|
|
89
88
|
aria-label="Send a message"
|
|
90
89
|
>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
type="button"
|
|
100
|
-
aria-label={`Remove ${file.name}`}
|
|
101
|
-
onclick={() => {
|
|
102
|
-
files = files.filter((f) => f.fileId !== file.fileId);
|
|
103
|
-
onremovefile?.(file.fileId);
|
|
104
|
-
}}>×</button
|
|
90
|
+
<div
|
|
91
|
+
class="mx-auto w-full max-w-3xl rounded-xl border border-input bg-background shadow-sm transition-shadow focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/20"
|
|
92
|
+
>
|
|
93
|
+
{#if files.length || uploadError}
|
|
94
|
+
<div class="flex flex-wrap items-center gap-1.5 px-3 pt-3 text-xs">
|
|
95
|
+
{#each files as file (file.fileId)}
|
|
96
|
+
<span
|
|
97
|
+
class="inline-flex max-w-full items-center gap-1 rounded-full bg-muted py-0.5 pl-2 pr-0.5"
|
|
105
98
|
>
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
onclick={() => fileInput?.click()}
|
|
122
|
-
>
|
|
123
|
-
{#if uploading === 0}<Icon name="upload" size={18} />{/if}
|
|
124
|
-
</Button>
|
|
99
|
+
<Icon name="file" size={12} class="shrink-0 text-muted-foreground" />
|
|
100
|
+
<span class="truncate">{file.name}</span>
|
|
101
|
+
<button
|
|
102
|
+
type="button"
|
|
103
|
+
class="inline-flex size-5 shrink-0 items-center justify-center rounded-full text-muted-foreground hover:bg-background hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
104
|
+
aria-label={`Remove ${file.name}`}
|
|
105
|
+
onclick={() => {
|
|
106
|
+
files = files.filter((f) => f.fileId !== file.fileId);
|
|
107
|
+
onremovefile?.(file.fileId);
|
|
108
|
+
}}><Icon name="close" size={12} /></button
|
|
109
|
+
>
|
|
110
|
+
</span>
|
|
111
|
+
{/each}
|
|
112
|
+
{#if uploadError}<span class="text-destructive" role="alert">{uploadError}</span>{/if}
|
|
113
|
+
</div>
|
|
125
114
|
{/if}
|
|
126
|
-
<
|
|
127
|
-
bind:
|
|
115
|
+
<Textarea
|
|
116
|
+
bind:ref={textarea}
|
|
128
117
|
bind:value
|
|
129
|
-
|
|
130
|
-
rows=
|
|
118
|
+
autosize
|
|
119
|
+
rows={1}
|
|
120
|
+
maxRows={8}
|
|
121
|
+
class="border-0 bg-transparent px-3 pb-1 pt-3 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0"
|
|
131
122
|
{placeholder}
|
|
132
123
|
aria-label="Message"
|
|
133
124
|
maxlength={LIMITS.messageChars}
|
|
134
125
|
{disabled}
|
|
135
126
|
{onkeydown}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
type="
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
127
|
+
/>
|
|
128
|
+
<div class="flex items-center gap-1 px-2 pb-2">
|
|
129
|
+
{#if upload}
|
|
130
|
+
<input bind:this={fileInput} type="file" multiple hidden onchange={onfiles} />
|
|
131
|
+
<Button
|
|
132
|
+
type="button"
|
|
133
|
+
variant="ghost"
|
|
134
|
+
size="icon"
|
|
135
|
+
class="size-8 text-muted-foreground"
|
|
136
|
+
aria-label="Attach files"
|
|
137
|
+
disabled={disabled || uploading > 0}
|
|
138
|
+
loading={uploading > 0}
|
|
139
|
+
onclick={() => fileInput?.click()}
|
|
140
|
+
>
|
|
141
|
+
{#if uploading === 0}<Icon name="paperclip" size={18} />{/if}
|
|
142
|
+
</Button>
|
|
143
|
+
{/if}
|
|
144
|
+
{#if context}<div class="min-w-0">{@render context()}</div>{/if}
|
|
145
|
+
<div class="ml-auto">
|
|
146
|
+
{#if streaming}
|
|
147
|
+
<Button
|
|
148
|
+
type="button"
|
|
149
|
+
variant="outline"
|
|
150
|
+
size="icon"
|
|
151
|
+
class="size-8"
|
|
152
|
+
aria-label="Stop"
|
|
153
|
+
onclick={() => oncancel?.()}><Icon name="stop" size={14} /></Button
|
|
154
|
+
>
|
|
155
|
+
{:else}
|
|
156
|
+
<Button
|
|
157
|
+
type="submit"
|
|
158
|
+
size="icon"
|
|
159
|
+
class="size-8"
|
|
160
|
+
aria-label="Send"
|
|
161
|
+
disabled={disabled || !value.trim() || uploading > 0}
|
|
162
|
+
><Icon name="send" size={16} /></Button
|
|
163
|
+
>
|
|
164
|
+
{/if}
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
153
167
|
</div>
|
|
154
168
|
</form>
|
|
155
|
-
|
|
156
|
-
<style>
|
|
157
|
-
.agent-composer {
|
|
158
|
-
padding: 0.75rem 1rem max(0.75rem, env(safe-area-inset-bottom));
|
|
159
|
-
border-top: 1px solid hsl(var(--border));
|
|
160
|
-
background: hsl(var(--background));
|
|
161
|
-
display: grid;
|
|
162
|
-
gap: 0.5rem;
|
|
163
|
-
}
|
|
164
|
-
.agent-composer__row {
|
|
165
|
-
display: flex;
|
|
166
|
-
align-items: flex-end;
|
|
167
|
-
gap: 0.5rem;
|
|
168
|
-
}
|
|
169
|
-
.agent-composer__field {
|
|
170
|
-
flex: 1;
|
|
171
|
-
resize: none;
|
|
172
|
-
min-height: 2.75rem;
|
|
173
|
-
max-height: 200px;
|
|
174
|
-
padding: 0.625rem 0.875rem;
|
|
175
|
-
border: 1px solid hsl(var(--border));
|
|
176
|
-
border-radius: 1rem;
|
|
177
|
-
background: hsl(var(--background));
|
|
178
|
-
color: hsl(var(--foreground));
|
|
179
|
-
font: inherit;
|
|
180
|
-
font-size: 16px;
|
|
181
|
-
line-height: 1.5;
|
|
182
|
-
}
|
|
183
|
-
.agent-composer__field:focus {
|
|
184
|
-
outline: none;
|
|
185
|
-
border-color: hsl(var(--primary));
|
|
186
|
-
box-shadow: 0 0 0 3px hsl(var(--primary) / 0.15);
|
|
187
|
-
}
|
|
188
|
-
.agent-composer__files {
|
|
189
|
-
display: flex;
|
|
190
|
-
flex-wrap: wrap;
|
|
191
|
-
gap: 0.375rem;
|
|
192
|
-
font-size: 0.75rem;
|
|
193
|
-
}
|
|
194
|
-
.agent-composer__file {
|
|
195
|
-
display: inline-flex;
|
|
196
|
-
align-items: center;
|
|
197
|
-
gap: 0.25rem;
|
|
198
|
-
padding: 0.125rem 0.5rem;
|
|
199
|
-
border-radius: 9999px;
|
|
200
|
-
background: hsl(var(--muted));
|
|
201
|
-
}
|
|
202
|
-
.agent-composer__file button {
|
|
203
|
-
border: 0;
|
|
204
|
-
background: none;
|
|
205
|
-
cursor: pointer;
|
|
206
|
-
font: inherit;
|
|
207
|
-
}
|
|
208
|
-
.agent-composer__error {
|
|
209
|
-
color: hsl(var(--destructive));
|
|
210
|
-
}
|
|
211
|
-
</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composer.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/Composer.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"Composer.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/Composer.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAK5D,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAC;CACpC;AA8GH,QAAA,MAAM,QAAQ;iBArFO,IAAI;qBAqF6B,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
Rename and delete dialogs for one conversation, shared by `ConversationSidebar` and
|
|
4
|
+
`ChatHeader`. Set `renaming` or `deleting` to a conversation to open the matching dialog.
|
|
5
|
+
A rejected `onrename` keeps the dialog open with the message; a rejected `ondelete` is
|
|
6
|
+
reported through `onerror` (the confirm dialog has already closed). Both dialogs usually open
|
|
7
|
+
from a menu item that is gone by the time they close, so focus returns to `returnFocus` (the
|
|
8
|
+
menu trigger) when it is still on the page.
|
|
9
|
+
-->
|
|
10
|
+
<script lang="ts" module>
|
|
11
|
+
export interface ConversationRef {
|
|
12
|
+
conversationId: string;
|
|
13
|
+
title: string;
|
|
14
|
+
}
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import { AlertDialog, Button, Dialog, Input } from '@classic-homes/theme-svelte';
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
renaming?: ConversationRef | null;
|
|
22
|
+
deleting?: ConversationRef | null;
|
|
23
|
+
onrename?: (conversationId: string, title: string) => void | Promise<void>;
|
|
24
|
+
ondelete?: (conversationId: string) => void | Promise<void>;
|
|
25
|
+
onerror?: (message: string) => void;
|
|
26
|
+
/** Element to focus when a dialog closes, e.g. the menu trigger that opened it. */
|
|
27
|
+
returnFocus?: HTMLElement | null;
|
|
28
|
+
}
|
|
29
|
+
let {
|
|
30
|
+
renaming = $bindable(null),
|
|
31
|
+
deleting = $bindable(null),
|
|
32
|
+
onrename,
|
|
33
|
+
ondelete,
|
|
34
|
+
onerror,
|
|
35
|
+
returnFocus = null,
|
|
36
|
+
}: Props = $props();
|
|
37
|
+
|
|
38
|
+
const uid = $props.id();
|
|
39
|
+
const formId = `${uid}-rename`;
|
|
40
|
+
const errorId = `${uid}-rename-error`;
|
|
41
|
+
const MAX_TITLE = 200;
|
|
42
|
+
let draft = $state('');
|
|
43
|
+
let saving = $state(false);
|
|
44
|
+
let renameError = $state<string | undefined>();
|
|
45
|
+
|
|
46
|
+
$effect(() => {
|
|
47
|
+
if (renaming) {
|
|
48
|
+
draft = renaming.title;
|
|
49
|
+
renameError = undefined;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
function message(err: unknown, fallback: string): string {
|
|
54
|
+
return err instanceof Error && err.message ? err.message : fallback;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function saveRename(event: SubmitEvent): Promise<void> {
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
const target = renaming;
|
|
60
|
+
const title = draft.trim();
|
|
61
|
+
if (!target || !title || saving) return;
|
|
62
|
+
if (title === target.title) {
|
|
63
|
+
renaming = null;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
saving = true;
|
|
67
|
+
renameError = undefined;
|
|
68
|
+
try {
|
|
69
|
+
await onrename?.(target.conversationId, title);
|
|
70
|
+
renaming = null;
|
|
71
|
+
} catch (err) {
|
|
72
|
+
renameError = message(err, 'Could not rename the conversation.');
|
|
73
|
+
} finally {
|
|
74
|
+
saving = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function restoreFocus(event: Event): void {
|
|
79
|
+
if (!returnFocus?.isConnected) return;
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
returnFocus.focus();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function confirmDelete(): Promise<void> {
|
|
85
|
+
const target = deleting;
|
|
86
|
+
deleting = null;
|
|
87
|
+
if (!target) return;
|
|
88
|
+
try {
|
|
89
|
+
await ondelete?.(target.conversationId);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
onerror?.(message(err, 'Could not delete the conversation.'));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<Dialog
|
|
97
|
+
open={renaming !== null}
|
|
98
|
+
onOpenChange={(open) => {
|
|
99
|
+
if (!open && !saving) renaming = null;
|
|
100
|
+
}}
|
|
101
|
+
title="Rename conversation"
|
|
102
|
+
size="sm"
|
|
103
|
+
onCloseAutoFocus={restoreFocus}
|
|
104
|
+
>
|
|
105
|
+
<form id={formId} class="grid gap-2" onsubmit={saveRename}>
|
|
106
|
+
<Input
|
|
107
|
+
bind:value={draft}
|
|
108
|
+
aria-label="Conversation title"
|
|
109
|
+
maxlength={MAX_TITLE}
|
|
110
|
+
aria-invalid={renameError ? true : undefined}
|
|
111
|
+
aria-describedby={renameError ? errorId : undefined}
|
|
112
|
+
/>
|
|
113
|
+
{#if renameError}
|
|
114
|
+
<p id={errorId} class="text-sm text-destructive" role="alert">{renameError}</p>
|
|
115
|
+
{/if}
|
|
116
|
+
</form>
|
|
117
|
+
{#snippet footer()}
|
|
118
|
+
<Button variant="outline" disabled={saving} onclick={() => (renaming = null)}>Cancel</Button>
|
|
119
|
+
<Button type="submit" form={formId} loading={saving} disabled={!draft.trim()}>Save</Button>
|
|
120
|
+
{/snippet}
|
|
121
|
+
</Dialog>
|
|
122
|
+
|
|
123
|
+
<AlertDialog
|
|
124
|
+
open={deleting !== null}
|
|
125
|
+
onOpenChange={(open) => {
|
|
126
|
+
if (!open) deleting = null;
|
|
127
|
+
}}
|
|
128
|
+
title="Delete this conversation?"
|
|
129
|
+
description={deleting ? `“${deleting.title}” will be deleted. This cannot be undone.` : undefined}
|
|
130
|
+
confirmText="Delete"
|
|
131
|
+
confirmVariant="destructive"
|
|
132
|
+
onConfirm={() => void confirmDelete()}
|
|
133
|
+
onCloseAutoFocus={restoreFocus}
|
|
134
|
+
/>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface ConversationRef {
|
|
2
|
+
conversationId: string;
|
|
3
|
+
title: string;
|
|
4
|
+
}
|
|
5
|
+
interface Props {
|
|
6
|
+
renaming?: ConversationRef | null;
|
|
7
|
+
deleting?: ConversationRef | null;
|
|
8
|
+
onrename?: (conversationId: string, title: string) => void | Promise<void>;
|
|
9
|
+
ondelete?: (conversationId: string) => void | Promise<void>;
|
|
10
|
+
onerror?: (message: string) => void;
|
|
11
|
+
/** Element to focus when a dialog closes, e.g. the menu trigger that opened it. */
|
|
12
|
+
returnFocus?: HTMLElement | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Rename and delete dialogs for one conversation, shared by `ConversationSidebar` and
|
|
16
|
+
* `ChatHeader`. Set `renaming` or `deleting` to a conversation to open the matching dialog.
|
|
17
|
+
* A rejected `onrename` keeps the dialog open with the message; a rejected `ondelete` is
|
|
18
|
+
* reported through `onerror` (the confirm dialog has already closed). Both dialogs usually open
|
|
19
|
+
* from a menu item that is gone by the time they close, so focus returns to `returnFocus` (the
|
|
20
|
+
* menu trigger) when it is still on the page.
|
|
21
|
+
*/
|
|
22
|
+
declare const ConversationDialogs: import("svelte").Component<Props, {}, "renaming" | "deleting">;
|
|
23
|
+
type ConversationDialogs = ReturnType<typeof ConversationDialogs>;
|
|
24
|
+
export default ConversationDialogs;
|
|
25
|
+
//# sourceMappingURL=ConversationDialogs.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationDialogs.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ConversationDialogs.svelte.ts"],"names":[],"mappings":"AAGE,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAMD,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAClC;AA+FH;;;;;;;GAOG;AACH,QAAA,MAAM,mBAAmB,gEAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
|