@signal9/era-ui 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/actions/action.svelte +41 -0
- package/dist/ai/actions/action.svelte.d.ts +12 -0
- package/dist/ai/actions/actions.svelte +15 -0
- package/dist/ai/actions/actions.svelte.d.ts +8 -0
- package/dist/ai/actions/index.d.ts +2 -0
- package/dist/ai/actions/index.js +2 -0
- package/dist/ai/artifact/artifact-actions.svelte +7 -0
- package/dist/ai/artifact/artifact-actions.svelte.d.ts +8 -0
- package/dist/ai/artifact/artifact-close.svelte +9 -0
- package/dist/ai/artifact/artifact-close.svelte.d.ts +6 -0
- package/dist/ai/artifact/artifact-content.svelte +7 -0
- package/dist/ai/artifact/artifact-content.svelte.d.ts +8 -0
- package/dist/ai/artifact/artifact-description.svelte +7 -0
- package/dist/ai/artifact/artifact-description.svelte.d.ts +8 -0
- package/dist/ai/artifact/artifact-header.svelte +16 -0
- package/dist/ai/artifact/artifact-header.svelte.d.ts +8 -0
- package/dist/ai/artifact/artifact-title.svelte +7 -0
- package/dist/ai/artifact/artifact-title.svelte.d.ts +8 -0
- package/dist/ai/artifact/artifact.svelte +16 -0
- package/dist/ai/artifact/artifact.svelte.d.ts +8 -0
- package/dist/ai/artifact/index.d.ts +8 -0
- package/dist/ai/artifact/index.js +8 -0
- package/dist/ai/chain-of-thought/chain-of-thought-step.svelte +39 -0
- package/dist/ai/chain-of-thought/chain-of-thought-step.svelte.d.ts +11 -0
- package/dist/ai/chain-of-thought/chain-of-thought.svelte +30 -0
- package/dist/ai/chain-of-thought/chain-of-thought.svelte.d.ts +11 -0
- package/dist/ai/chain-of-thought/index.d.ts +3 -0
- package/dist/ai/chain-of-thought/index.js +3 -0
- package/dist/ai/checkpoint.svelte +27 -0
- package/dist/ai/checkpoint.svelte.d.ts +10 -0
- package/dist/ai/confirmation/confirmation-actions.svelte +9 -0
- package/dist/ai/confirmation/confirmation-actions.svelte.d.ts +8 -0
- package/dist/ai/confirmation/confirmation.svelte +36 -0
- package/dist/ai/confirmation/confirmation.svelte.d.ts +11 -0
- package/dist/ai/confirmation/index.d.ts +2 -0
- package/dist/ai/confirmation/index.js +2 -0
- package/dist/ai/context/context.svelte +49 -0
- package/dist/ai/context/context.svelte.d.ts +9 -0
- package/dist/ai/context/index.d.ts +1 -0
- package/dist/ai/context/index.js +1 -0
- package/dist/ai/conversation/context.d.ts +3 -0
- package/dist/ai/conversation/context.js +12 -0
- package/dist/ai/conversation/conversation-content.svelte +32 -0
- package/dist/ai/conversation/conversation-content.svelte.d.ts +8 -0
- package/dist/ai/conversation/conversation-empty-state.svelte +32 -0
- package/dist/ai/conversation/conversation-empty-state.svelte.d.ts +11 -0
- package/dist/ai/conversation/conversation-scroll-button.svelte +27 -0
- package/dist/ai/conversation/conversation-scroll-button.svelte.d.ts +6 -0
- package/dist/ai/conversation/conversation.svelte +21 -0
- package/dist/ai/conversation/conversation.svelte.d.ts +8 -0
- package/dist/ai/conversation/index.d.ts +5 -0
- package/dist/ai/conversation/index.js +5 -0
- package/dist/ai/copy-button.svelte +42 -0
- package/dist/ai/copy-button.svelte.d.ts +8 -0
- package/dist/ai/image.svelte +19 -0
- package/dist/ai/image.svelte.d.ts +8 -0
- package/dist/ai/index.d.ts +29 -0
- package/dist/ai/index.js +31 -0
- package/dist/ai/inline-citation/index.d.ts +1 -0
- package/dist/ai/inline-citation/index.js +1 -0
- package/dist/ai/inline-citation/inline-citation.svelte +66 -0
- package/dist/ai/inline-citation/inline-citation.svelte.d.ts +11 -0
- package/dist/ai/loader.svelte +8 -0
- package/dist/ai/loader.svelte.d.ts +6 -0
- package/dist/ai/message/branch.svelte.d.ts +10 -0
- package/dist/ai/message/branch.svelte.js +28 -0
- package/dist/ai/message/context.d.ts +6 -0
- package/dist/ai/message/context.js +1 -0
- package/dist/ai/message/index.d.ts +8 -0
- package/dist/ai/message/index.js +7 -0
- package/dist/ai/message/message-branch-content.svelte +24 -0
- package/dist/ai/message/message-branch-content.svelte.d.ts +10 -0
- package/dist/ai/message/message-branch-selector.svelte +25 -0
- package/dist/ai/message/message-branch-selector.svelte.d.ts +6 -0
- package/dist/ai/message/message-branch.svelte +25 -0
- package/dist/ai/message/message-branch.svelte.d.ts +9 -0
- package/dist/ai/message/message-content.svelte +24 -0
- package/dist/ai/message/message-content.svelte.d.ts +8 -0
- package/dist/ai/message/message-toolbar.svelte +23 -0
- package/dist/ai/message/message-toolbar.svelte.d.ts +8 -0
- package/dist/ai/message/message.svelte +27 -0
- package/dist/ai/message/message.svelte.d.ts +10 -0
- package/dist/ai/model-selector/index.d.ts +1 -0
- package/dist/ai/model-selector/index.js +1 -0
- package/dist/ai/model-selector/model-selector.svelte +61 -0
- package/dist/ai/model-selector/model-selector.svelte.d.ts +15 -0
- package/dist/ai/open-in-chat/index.d.ts +1 -0
- package/dist/ai/open-in-chat/index.js +1 -0
- package/dist/ai/open-in-chat/open-in-chat.svelte +41 -0
- package/dist/ai/open-in-chat/open-in-chat.svelte.d.ts +32 -0
- package/dist/ai/plan/index.d.ts +3 -0
- package/dist/ai/plan/index.js +3 -0
- package/dist/ai/plan/plan-content.svelte +13 -0
- package/dist/ai/plan/plan-content.svelte.d.ts +8 -0
- package/dist/ai/plan/plan-header.svelte +22 -0
- package/dist/ai/plan/plan-header.svelte.d.ts +9 -0
- package/dist/ai/plan/plan.svelte +23 -0
- package/dist/ai/plan/plan.svelte.d.ts +10 -0
- package/dist/ai/prompt-input/attachments.svelte.d.ts +27 -0
- package/dist/ai/prompt-input/attachments.svelte.js +60 -0
- package/dist/ai/prompt-input/index.d.ts +7 -0
- package/dist/ai/prompt-input/index.js +7 -0
- package/dist/ai/prompt-input/prompt-input-add-attachments.svelte +12 -0
- package/dist/ai/prompt-input/prompt-input-add-attachments.svelte.d.ts +6 -0
- package/dist/ai/prompt-input/prompt-input-attachments.svelte +40 -0
- package/dist/ai/prompt-input/prompt-input-attachments.svelte.d.ts +18 -0
- package/dist/ai/prompt-input/prompt-input-submit.svelte +49 -0
- package/dist/ai/prompt-input/prompt-input-submit.svelte.d.ts +10 -0
- package/dist/ai/prompt-input/prompt-input-textarea.svelte +57 -0
- package/dist/ai/prompt-input/prompt-input-textarea.svelte.d.ts +7 -0
- package/dist/ai/prompt-input/prompt-input-toolbar.svelte +15 -0
- package/dist/ai/prompt-input/prompt-input-toolbar.svelte.d.ts +8 -0
- package/dist/ai/prompt-input/prompt-input.svelte +98 -0
- package/dist/ai/prompt-input/prompt-input.svelte.d.ts +17 -0
- package/dist/ai/queue/index.d.ts +2 -0
- package/dist/ai/queue/index.js +2 -0
- package/dist/ai/queue/queue-item.svelte +26 -0
- package/dist/ai/queue/queue-item.svelte.d.ts +9 -0
- package/dist/ai/queue/queue.svelte +14 -0
- package/dist/ai/queue/queue.svelte.d.ts +8 -0
- package/dist/ai/reasoning/index.d.ts +3 -0
- package/dist/ai/reasoning/index.js +3 -0
- package/dist/ai/reasoning/reasoning-trigger.svelte +22 -0
- package/dist/ai/reasoning/reasoning-trigger.svelte.d.ts +9 -0
- package/dist/ai/reasoning/reasoning.svelte +52 -0
- package/dist/ai/reasoning/reasoning.svelte.d.ts +13 -0
- package/dist/ai/response/index.d.ts +2 -0
- package/dist/ai/response/index.js +2 -0
- package/dist/ai/response/repair.d.ts +7 -0
- package/dist/ai/response/repair.js +26 -0
- package/dist/ai/response/response.svelte +112 -0
- package/dist/ai/response/response.svelte.d.ts +10 -0
- package/dist/ai/shimmer.svelte +15 -0
- package/dist/ai/shimmer.svelte.d.ts +9 -0
- package/dist/ai/sources/index.d.ts +4 -0
- package/dist/ai/sources/index.js +4 -0
- package/dist/ai/sources/source.svelte +16 -0
- package/dist/ai/sources/source.svelte.d.ts +7 -0
- package/dist/ai/sources/sources-trigger.svelte +12 -0
- package/dist/ai/sources/sources-trigger.svelte.d.ts +8 -0
- package/dist/ai/sources/sources.svelte +15 -0
- package/dist/ai/sources/sources.svelte.d.ts +9 -0
- package/dist/ai/stick-to-bottom.svelte.d.ts +38 -0
- package/dist/ai/stick-to-bottom.svelte.js +133 -0
- package/dist/ai/suggestion/index.d.ts +2 -0
- package/dist/ai/suggestion/index.js +2 -0
- package/dist/ai/suggestion/suggestion.svelte +25 -0
- package/dist/ai/suggestion/suggestion.svelte.d.ts +10 -0
- package/dist/ai/suggestion/suggestions.svelte +18 -0
- package/dist/ai/suggestion/suggestions.svelte.d.ts +8 -0
- package/dist/ai/task/index.d.ts +5 -0
- package/dist/ai/task/index.js +5 -0
- package/dist/ai/task/task-content.svelte +14 -0
- package/dist/ai/task/task-content.svelte.d.ts +8 -0
- package/dist/ai/task/task-item-file.svelte +8 -0
- package/dist/ai/task/task-item-file.svelte.d.ts +7 -0
- package/dist/ai/task/task-item.svelte +8 -0
- package/dist/ai/task/task-item.svelte.d.ts +8 -0
- package/dist/ai/task/task-trigger.svelte +12 -0
- package/dist/ai/task/task-trigger.svelte.d.ts +8 -0
- package/dist/ai/task/task.svelte +17 -0
- package/dist/ai/task/task.svelte.d.ts +11 -0
- package/dist/ai/tool/index.d.ts +5 -0
- package/dist/ai/tool/index.js +5 -0
- package/dist/ai/tool/tool-header.svelte +20 -0
- package/dist/ai/tool/tool-header.svelte.d.ts +9 -0
- package/dist/ai/tool/tool-input.svelte +10 -0
- package/dist/ai/tool/tool-input.svelte.d.ts +6 -0
- package/dist/ai/tool/tool-output.svelte +20 -0
- package/dist/ai/tool/tool-output.svelte.d.ts +7 -0
- package/dist/ai/tool/tool.svelte +41 -0
- package/dist/ai/tool/tool.svelte.d.ts +12 -0
- package/dist/ai/web-preview/index.d.ts +1 -0
- package/dist/ai/web-preview/index.js +1 -0
- package/dist/ai/web-preview/web-preview.svelte +48 -0
- package/dist/ai/web-preview/web-preview.svelte.d.ts +8 -0
- package/dist/ai/workflow/canvas.svelte +19 -0
- package/dist/ai/workflow/canvas.svelte.d.ts +11 -0
- package/dist/ai/workflow/index.d.ts +2 -0
- package/dist/ai/workflow/index.js +2 -0
- package/dist/ai/workflow/node.svelte +27 -0
- package/dist/ai/workflow/node.svelte.d.ts +9 -0
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/llms-full.txt +56 -0
- package/dist/generated-docs/llms.txt +1 -1
- package/dist/generated-docs/manifest.json +14 -0
- package/dist/generated-docs/step.md +51 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/os/motion.d.ts +1 -19
- package/dist/os/motion.js +3 -44
- package/dist/os/taskbar.svelte +6 -3
- package/dist/styles/index.css +26 -0
- package/dist/ui/command-bar/command-bar.svelte +8 -6
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +1 -0
- package/dist/ui/step/context.d.ts +8 -0
- package/dist/ui/step/context.js +8 -0
- package/dist/ui/step/index.d.ts +5 -0
- package/dist/ui/step/index.js +4 -0
- package/dist/ui/step/step-content.svelte +55 -0
- package/dist/ui/step/step-content.svelte.d.ts +5 -0
- package/dist/ui/step/step-root.svelte +31 -0
- package/dist/ui/step/step-root.svelte.d.ts +9 -0
- package/dist/ui/step/step-section.svelte +23 -0
- package/dist/ui/step/step-section.svelte.d.ts +10 -0
- package/dist/ui/step/step-summary.svelte +55 -0
- package/dist/ui/step/step-summary.svelte.d.ts +5 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/motion.d.ts +19 -0
- package/dist/utils/motion.js +44 -0
- package/package.json +14 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Dialog from '../../ui/dialog/index.js';
|
|
3
|
+
import * as Command from '../../ui/command/index.js';
|
|
4
|
+
import Search from '@lucide/svelte/icons/search';
|
|
5
|
+
import { cn } from '../../utils/index.js';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
open = $bindable(false),
|
|
9
|
+
models,
|
|
10
|
+
value = $bindable(''),
|
|
11
|
+
onSelect,
|
|
12
|
+
class: className
|
|
13
|
+
}: {
|
|
14
|
+
open?: boolean;
|
|
15
|
+
/** `provider` keys models.dev logo slugs (e.g. `openai`, `anthropic`). */
|
|
16
|
+
models: { id: string; name: string; provider?: string }[];
|
|
17
|
+
value?: string;
|
|
18
|
+
onSelect?: (id: string) => void;
|
|
19
|
+
class?: string;
|
|
20
|
+
} = $props();
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<Dialog.Root bind:open>
|
|
24
|
+
<Dialog.Content class={cn('max-w-md p-(--era-gap)', className)}>
|
|
25
|
+
<Command.Root bare>
|
|
26
|
+
<Command.Input icon={Search} placeholder="Search models…" autofocus />
|
|
27
|
+
<Command.List>
|
|
28
|
+
<Command.Viewport>
|
|
29
|
+
<Command.Empty>No models found.</Command.Empty>
|
|
30
|
+
<Command.Group>
|
|
31
|
+
<Command.GroupItems>
|
|
32
|
+
{#each models as m (m.id)}
|
|
33
|
+
<Command.Item
|
|
34
|
+
value={m.id}
|
|
35
|
+
keywords={[m.name, m.provider ?? '']}
|
|
36
|
+
onSelect={() => {
|
|
37
|
+
value = m.id;
|
|
38
|
+
onSelect?.(m.id);
|
|
39
|
+
open = false;
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
{#if m.provider}
|
|
43
|
+
<img
|
|
44
|
+
src="https://models.dev/logos/{m.provider}.svg"
|
|
45
|
+
alt=""
|
|
46
|
+
class="size-(--era-h-xs) shrink-0 dark:invert"
|
|
47
|
+
/>
|
|
48
|
+
{/if}
|
|
49
|
+
<span class="truncate">{m.name}</span>
|
|
50
|
+
{#if value === m.id}
|
|
51
|
+
<span class="ml-auto text-body text-muted">current</span>
|
|
52
|
+
{/if}
|
|
53
|
+
</Command.Item>
|
|
54
|
+
{/each}
|
|
55
|
+
</Command.GroupItems>
|
|
56
|
+
</Command.Group>
|
|
57
|
+
</Command.Viewport>
|
|
58
|
+
</Command.List>
|
|
59
|
+
</Command.Root>
|
|
60
|
+
</Dialog.Content>
|
|
61
|
+
</Dialog.Root>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
open?: boolean;
|
|
3
|
+
/** `provider` keys models.dev logo slugs (e.g. `openai`, `anthropic`). */
|
|
4
|
+
models: {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
provider?: string;
|
|
8
|
+
}[];
|
|
9
|
+
value?: string;
|
|
10
|
+
onSelect?: (id: string) => void;
|
|
11
|
+
class?: string;
|
|
12
|
+
};
|
|
13
|
+
declare const ModelSelector: import("svelte").Component<$$ComponentProps, {}, "value" | "open">;
|
|
14
|
+
type ModelSelector = ReturnType<typeof ModelSelector>;
|
|
15
|
+
export default ModelSelector;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Root, providers } from './open-in-chat.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Root, providers } from './open-in-chat.svelte';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/** Deep-link builders for "continue this prompt elsewhere". */
|
|
3
|
+
export const providers = {
|
|
4
|
+
chatgpt: { title: 'ChatGPT', url: (q: string) => `https://chatgpt.com/?${new URLSearchParams({ q })}` },
|
|
5
|
+
claude: { title: 'Claude', url: (q: string) => `https://claude.ai/new?${new URLSearchParams({ q })}` },
|
|
6
|
+
t3: { title: 'T3 Chat', url: (q: string) => `https://t3.chat/new?${new URLSearchParams({ q })}` },
|
|
7
|
+
scira: { title: 'Scira', url: (q: string) => `https://scira.ai/?${new URLSearchParams({ q })}` },
|
|
8
|
+
v0: { title: 'v0', url: (q: string) => `https://v0.dev/chat?${new URLSearchParams({ q })}` }
|
|
9
|
+
} as const;
|
|
10
|
+
export type ProviderId = keyof typeof providers;
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import ChevronDown from '@lucide/svelte/icons/chevron-down';
|
|
15
|
+
import ExternalLink from '@lucide/svelte/icons/external-link';
|
|
16
|
+
import * as DropdownMenu from '../../ui/dropdown-menu/index.js';
|
|
17
|
+
import { cn } from '../../utils/index.js';
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
query,
|
|
21
|
+
include = Object.keys(providers) as ProviderId[],
|
|
22
|
+
class: className
|
|
23
|
+
}: { query: string; include?: ProviderId[]; class?: string } = $props();
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<DropdownMenu.Root>
|
|
27
|
+
<DropdownMenu.Trigger class={cn(className)}>
|
|
28
|
+
Open in chat
|
|
29
|
+
<ChevronDown class="size-(--era-h-xs)" />
|
|
30
|
+
</DropdownMenu.Trigger>
|
|
31
|
+
<DropdownMenu.Content align="start">
|
|
32
|
+
{#each include as id (id)}
|
|
33
|
+
<DropdownMenu.Item
|
|
34
|
+
onSelect={() => window.open(providers[id].url(query), '_blank', 'noreferrer')}
|
|
35
|
+
>
|
|
36
|
+
<ExternalLink class="size-(--era-h-xs) text-muted" />
|
|
37
|
+
{providers[id].title}
|
|
38
|
+
</DropdownMenu.Item>
|
|
39
|
+
{/each}
|
|
40
|
+
</DropdownMenu.Content>
|
|
41
|
+
</DropdownMenu.Root>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Deep-link builders for "continue this prompt elsewhere". */
|
|
2
|
+
export declare const providers: {
|
|
3
|
+
readonly chatgpt: {
|
|
4
|
+
readonly title: "ChatGPT";
|
|
5
|
+
readonly url: (q: string) => string;
|
|
6
|
+
};
|
|
7
|
+
readonly claude: {
|
|
8
|
+
readonly title: "Claude";
|
|
9
|
+
readonly url: (q: string) => string;
|
|
10
|
+
};
|
|
11
|
+
readonly t3: {
|
|
12
|
+
readonly title: "T3 Chat";
|
|
13
|
+
readonly url: (q: string) => string;
|
|
14
|
+
};
|
|
15
|
+
readonly scira: {
|
|
16
|
+
readonly title: "Scira";
|
|
17
|
+
readonly url: (q: string) => string;
|
|
18
|
+
};
|
|
19
|
+
readonly v0: {
|
|
20
|
+
readonly title: "v0";
|
|
21
|
+
readonly url: (q: string) => string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export type ProviderId = keyof typeof providers;
|
|
25
|
+
type $$ComponentProps = {
|
|
26
|
+
query: string;
|
|
27
|
+
include?: ProviderId[];
|
|
28
|
+
class?: string;
|
|
29
|
+
};
|
|
30
|
+
declare const OpenInChat: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
31
|
+
type OpenInChat = ReturnType<typeof OpenInChat>;
|
|
32
|
+
export default OpenInChat;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { Collapsible } from 'bits-ui';
|
|
4
|
+
import { cn } from '../../utils/index.js';
|
|
5
|
+
|
|
6
|
+
let { children, class: className }: { children?: Snippet; class?: string } = $props();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<Collapsible.Content
|
|
10
|
+
class={cn('flex flex-col gap-(--era-gap) overflow-hidden p-(--era-inset-md)', className)}
|
|
11
|
+
>
|
|
12
|
+
{@render children?.()}
|
|
13
|
+
</Collapsible.Content>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
children?: Snippet;
|
|
4
|
+
class?: string;
|
|
5
|
+
};
|
|
6
|
+
declare const PlanContent: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type PlanContent = ReturnType<typeof PlanContent>;
|
|
8
|
+
export default PlanContent;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import ChevronsUpDown from '@lucide/svelte/icons/chevrons-up-down';
|
|
4
|
+
import { Collapsible } from 'bits-ui';
|
|
5
|
+
import { cn } from '../../utils/index.js';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
title,
|
|
9
|
+
children,
|
|
10
|
+
class: className
|
|
11
|
+
}: { title?: string; children?: Snippet; class?: string } = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Collapsible.Trigger
|
|
15
|
+
class={cn(
|
|
16
|
+
'flex h-(--era-h-md) w-full cursor-pointer era-interactive items-center gap-(--era-gap) rounded-(--era-rd-md) px-(--era-inset-md) text-body text-bright hover:bg-(--era-highlight)',
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
>
|
|
20
|
+
{#if children}{@render children()}{:else}<span class="truncate font-medium">{title}</span>{/if}
|
|
21
|
+
<ChevronsUpDown class="ml-auto size-(--era-h-xs) shrink-0 text-muted" />
|
|
22
|
+
</Collapsible.Trigger>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
title?: string;
|
|
4
|
+
children?: Snippet;
|
|
5
|
+
class?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const PlanHeader: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type PlanHeader = ReturnType<typeof PlanHeader>;
|
|
9
|
+
export default PlanHeader;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { Collapsible } from 'bits-ui';
|
|
4
|
+
import { cn } from '../../utils/index.js';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
open = $bindable(true),
|
|
8
|
+
streaming = false,
|
|
9
|
+
children,
|
|
10
|
+
class: className
|
|
11
|
+
}: { open?: boolean; streaming?: boolean; children?: Snippet; class?: string } = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Collapsible.Root
|
|
15
|
+
bind:open
|
|
16
|
+
data-streaming={streaming || undefined}
|
|
17
|
+
class={cn(
|
|
18
|
+
'group/plan flex flex-col rounded-(--era-rd-lg) bg-(--era-surface-bg) p-(--era-pad-sm) shadow-(--era-shadow)',
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
>
|
|
22
|
+
{@render children?.()}
|
|
23
|
+
</Collapsible.Root>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
streaming?: boolean;
|
|
5
|
+
children?: Snippet;
|
|
6
|
+
class?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const Plan: import("svelte").Component<$$ComponentProps, {}, "open">;
|
|
9
|
+
type Plan = ReturnType<typeof Plan>;
|
|
10
|
+
export default Plan;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface PromptAttachment {
|
|
2
|
+
id: string;
|
|
3
|
+
file: File;
|
|
4
|
+
filename: string;
|
|
5
|
+
mediaType: string;
|
|
6
|
+
previewUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PromptMessage {
|
|
9
|
+
text: string;
|
|
10
|
+
attachments: PromptAttachment[];
|
|
11
|
+
}
|
|
12
|
+
export type ChatStatus = 'ready' | 'submitted' | 'streaming' | 'error';
|
|
13
|
+
/** The composer's attachment basket — add/remove with object-URL hygiene. */
|
|
14
|
+
export declare class Attachments {
|
|
15
|
+
#private;
|
|
16
|
+
items: PromptAttachment[];
|
|
17
|
+
accept: string;
|
|
18
|
+
maxFiles: number;
|
|
19
|
+
fileInput: HTMLInputElement | null;
|
|
20
|
+
onError?: (code: 'accept' | 'max_files', file: File) => void;
|
|
21
|
+
add(files: Iterable<File>): void;
|
|
22
|
+
remove(id: string): void;
|
|
23
|
+
clear(): void;
|
|
24
|
+
openFileDialog(): void;
|
|
25
|
+
}
|
|
26
|
+
export declare function setAttachmentsContext(ctx: Attachments): Attachments;
|
|
27
|
+
export declare function getAttachmentsContext(): Attachments;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
/** The composer's attachment basket — add/remove with object-URL hygiene. */
|
|
3
|
+
export class Attachments {
|
|
4
|
+
items = $state([]);
|
|
5
|
+
accept = '';
|
|
6
|
+
maxFiles = Infinity;
|
|
7
|
+
fileInput = null;
|
|
8
|
+
onError;
|
|
9
|
+
add(files) {
|
|
10
|
+
for (const file of files) {
|
|
11
|
+
if (this.items.length >= this.maxFiles) {
|
|
12
|
+
this.onError?.('max_files', file);
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
if (this.accept && !this.#matches(file)) {
|
|
16
|
+
this.onError?.('accept', file);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
this.items.push({
|
|
20
|
+
id: crypto.randomUUID(),
|
|
21
|
+
file,
|
|
22
|
+
filename: file.name,
|
|
23
|
+
mediaType: file.type,
|
|
24
|
+
previewUrl: file.type.startsWith('image/') ? URL.createObjectURL(file) : undefined
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
remove(id) {
|
|
29
|
+
const item = this.items.find((a) => a.id === id);
|
|
30
|
+
if (item?.previewUrl)
|
|
31
|
+
URL.revokeObjectURL(item.previewUrl);
|
|
32
|
+
this.items = this.items.filter((a) => a.id !== id);
|
|
33
|
+
}
|
|
34
|
+
clear() {
|
|
35
|
+
for (const a of this.items)
|
|
36
|
+
if (a.previewUrl)
|
|
37
|
+
URL.revokeObjectURL(a.previewUrl);
|
|
38
|
+
this.items = [];
|
|
39
|
+
}
|
|
40
|
+
openFileDialog() {
|
|
41
|
+
this.fileInput?.click();
|
|
42
|
+
}
|
|
43
|
+
#matches(file) {
|
|
44
|
+
return this.accept.split(',').some((pattern) => {
|
|
45
|
+
const p = pattern.trim();
|
|
46
|
+
return p.endsWith('/*') ? file.type.startsWith(p.slice(0, -1)) : file.type === p;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const KEY = Symbol('era-ai-attachments');
|
|
51
|
+
export function setAttachmentsContext(ctx) {
|
|
52
|
+
setContext(KEY, ctx);
|
|
53
|
+
return ctx;
|
|
54
|
+
}
|
|
55
|
+
export function getAttachmentsContext() {
|
|
56
|
+
const ctx = getContext(KEY);
|
|
57
|
+
if (!ctx)
|
|
58
|
+
throw new Error('PromptInput parts must be used inside <PromptInput.Root>.');
|
|
59
|
+
return ctx;
|
|
60
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Root } from './prompt-input.svelte';
|
|
2
|
+
export { default as Textarea } from './prompt-input-textarea.svelte';
|
|
3
|
+
export { default as Submit } from './prompt-input-submit.svelte';
|
|
4
|
+
export { default as Toolbar } from './prompt-input-toolbar.svelte';
|
|
5
|
+
export { default as Attachments } from './prompt-input-attachments.svelte';
|
|
6
|
+
export { default as AddAttachments } from './prompt-input-add-attachments.svelte';
|
|
7
|
+
export { Attachments as AttachmentsStore, getAttachmentsContext, setAttachmentsContext, type PromptAttachment, type PromptMessage, type ChatStatus } from './attachments.svelte.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Root } from './prompt-input.svelte';
|
|
2
|
+
export { default as Textarea } from './prompt-input-textarea.svelte';
|
|
3
|
+
export { default as Submit } from './prompt-input-submit.svelte';
|
|
4
|
+
export { default as Toolbar } from './prompt-input-toolbar.svelte';
|
|
5
|
+
export { default as Attachments } from './prompt-input-attachments.svelte';
|
|
6
|
+
export { default as AddAttachments } from './prompt-input-add-attachments.svelte';
|
|
7
|
+
export { Attachments as AttachmentsStore, getAttachmentsContext, setAttachmentsContext } from './attachments.svelte.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Plus from '@lucide/svelte/icons/plus';
|
|
3
|
+
import { Button } from '../../ui/button/index.js';
|
|
4
|
+
import { getAttachmentsContext } from './attachments.svelte.js';
|
|
5
|
+
|
|
6
|
+
let { label = 'Add attachments' }: { label?: string } = $props();
|
|
7
|
+
const attachments = getAttachmentsContext();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<Button icon size="default" aria-label={label} onclick={() => attachments.openFileDialog()}>
|
|
11
|
+
<Plus class="size-(--era-h-xs)" />
|
|
12
|
+
</Button>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
label?: string;
|
|
3
|
+
};
|
|
4
|
+
declare const PromptInputAddAttachments: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
5
|
+
type PromptInputAddAttachments = ReturnType<typeof PromptInputAddAttachments>;
|
|
6
|
+
export default PromptInputAddAttachments;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import X from '@lucide/svelte/icons/x';
|
|
3
|
+
import Paperclip from '@lucide/svelte/icons/paperclip';
|
|
4
|
+
import { Button } from '../../ui/button/index.js';
|
|
5
|
+
import { getAttachmentsContext } from './attachments.svelte.js';
|
|
6
|
+
|
|
7
|
+
const attachments = getAttachmentsContext();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
{#if attachments.items.length}
|
|
11
|
+
<div class="flex flex-wrap gap-(--era-gap) pb-(--era-gap)">
|
|
12
|
+
{#each attachments.items as a (a.id)}
|
|
13
|
+
<div class="group/att relative">
|
|
14
|
+
{#if a.previewUrl}
|
|
15
|
+
<img
|
|
16
|
+
src={a.previewUrl}
|
|
17
|
+
alt={a.filename}
|
|
18
|
+
class="size-16 rounded-(--era-rd-sm) object-cover shadow-(--era-shadow)"
|
|
19
|
+
/>
|
|
20
|
+
{:else}
|
|
21
|
+
<div
|
|
22
|
+
class="flex h-(--era-h-md) items-center gap-(--era-gap) rounded-(--era-rd-md) bg-(--era-surface-bg) px-(--era-inset-md) text-body text-muted shadow-(--era-shadow)"
|
|
23
|
+
>
|
|
24
|
+
<Paperclip class="size-(--era-h-xs) shrink-0" />
|
|
25
|
+
<span class="max-w-32 truncate">{a.filename}</span>
|
|
26
|
+
</div>
|
|
27
|
+
{/if}
|
|
28
|
+
<Button
|
|
29
|
+
icon
|
|
30
|
+
size="icon"
|
|
31
|
+
aria-label="Remove {a.filename}"
|
|
32
|
+
class="absolute -top-1 -right-1 rounded-full opacity-0 shadow-(--era-shadow) group-hover/att:opacity-100 focus-visible:opacity-100"
|
|
33
|
+
onclick={() => attachments.remove(a.id)}
|
|
34
|
+
>
|
|
35
|
+
<X class="size-[calc(var(--era-h-xs)-4px)]" />
|
|
36
|
+
</Button>
|
|
37
|
+
</div>
|
|
38
|
+
{/each}
|
|
39
|
+
</div>
|
|
40
|
+
{/if}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const PromptInputAttachments: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type PromptInputAttachments = InstanceType<typeof PromptInputAttachments>;
|
|
18
|
+
export default PromptInputAttachments;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ArrowUp from '@lucide/svelte/icons/arrow-up';
|
|
3
|
+
import Square from '@lucide/svelte/icons/square';
|
|
4
|
+
import LoaderCircle from '@lucide/svelte/icons/loader-circle';
|
|
5
|
+
import { Button } from '../../ui/button/index.js';
|
|
6
|
+
import { cn } from '../../utils/index.js';
|
|
7
|
+
import type { ChatStatus } from './attachments.svelte.js';
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
status = 'ready',
|
|
11
|
+
disabled = false,
|
|
12
|
+
onStop,
|
|
13
|
+
class: className
|
|
14
|
+
}: {
|
|
15
|
+
status?: ChatStatus;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
onStop?: () => void;
|
|
18
|
+
class?: string;
|
|
19
|
+
} = $props();
|
|
20
|
+
|
|
21
|
+
const generating = $derived(status === 'submitted' || status === 'streaming');
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<!-- One button, morphing by stream state: send → (spinner) → stop. While
|
|
25
|
+
generating it becomes type=button so pressing it stops instead of
|
|
26
|
+
resubmitting. -->
|
|
27
|
+
<Button
|
|
28
|
+
icon
|
|
29
|
+
size="default"
|
|
30
|
+
tone={generating ? 'default' : 'accent'}
|
|
31
|
+
type={generating ? 'button' : 'submit'}
|
|
32
|
+
aria-label={generating ? 'Stop' : 'Send'}
|
|
33
|
+
disabled={disabled && !generating}
|
|
34
|
+
class={cn('shrink-0 self-end', className)}
|
|
35
|
+
onclick={(e: MouseEvent) => {
|
|
36
|
+
if (generating) {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
onStop?.();
|
|
39
|
+
}
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
{#if status === 'submitted'}
|
|
43
|
+
<LoaderCircle class="size-(--era-h-xs) animate-spin" />
|
|
44
|
+
{:else if status === 'streaming'}
|
|
45
|
+
<Square class="size-[calc(var(--era-h-xs)-4px)]" fill="currentColor" />
|
|
46
|
+
{:else}
|
|
47
|
+
<ArrowUp class="size-(--era-h-xs)" />
|
|
48
|
+
{/if}
|
|
49
|
+
</Button>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ChatStatus } from './attachments.svelte.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
status?: ChatStatus;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
onStop?: () => void;
|
|
6
|
+
class?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const PromptInputSubmit: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type PromptInputSubmit = ReturnType<typeof PromptInputSubmit>;
|
|
10
|
+
export default PromptInputSubmit;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLTextareaAttributes } from 'svelte/elements';
|
|
3
|
+
import { cn } from '../../utils/index.js';
|
|
4
|
+
import { getAttachmentsContext } from './attachments.svelte.js';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(null),
|
|
8
|
+
value = $bindable(''),
|
|
9
|
+
placeholder = 'Message…',
|
|
10
|
+
class: className,
|
|
11
|
+
...restProps
|
|
12
|
+
}: HTMLTextareaAttributes & { ref?: HTMLTextAreaElement | null } = $props();
|
|
13
|
+
|
|
14
|
+
const attachments = getAttachmentsContext();
|
|
15
|
+
|
|
16
|
+
function onKeydown(e: KeyboardEvent) {
|
|
17
|
+
// Enter submits, Shift+Enter breaks the line — and NEVER submit while
|
|
18
|
+
// the user is composing CJK input (both checks: the event flag and the
|
|
19
|
+
// composition events, per the reference implementations).
|
|
20
|
+
if (e.key === 'Enter' && !e.shiftKey && !e.isComposing) {
|
|
21
|
+
e.preventDefault();
|
|
22
|
+
(e.currentTarget as HTMLTextAreaElement).form?.requestSubmit();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function onPaste(e: ClipboardEvent) {
|
|
27
|
+
const files = [...(e.clipboardData?.items ?? [])]
|
|
28
|
+
.filter((i) => i.kind === 'file')
|
|
29
|
+
.map((i) => i.getAsFile())
|
|
30
|
+
.filter((f): f is File => !!f);
|
|
31
|
+
if (files.length) {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
attachments.add(files);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<!-- field-sizing auto-grows the textarea with its content up to max-h, then
|
|
39
|
+
it scrolls internally; the composer stays typing-enabled during streaming
|
|
40
|
+
(only the submit path is gated). -->
|
|
41
|
+
<textarea
|
|
42
|
+
bind:this={ref}
|
|
43
|
+
bind:value
|
|
44
|
+
name="message"
|
|
45
|
+
rows="1"
|
|
46
|
+
{placeholder}
|
|
47
|
+
autocapitalize="off"
|
|
48
|
+
autocomplete="off"
|
|
49
|
+
spellcheck="false"
|
|
50
|
+
onkeydown={onKeydown}
|
|
51
|
+
onpaste={onPaste}
|
|
52
|
+
class={cn(
|
|
53
|
+
'field-sizing-content max-h-48 w-full resize-none bg-transparent p-(--era-inset-sm) text-body leading-relaxed text-bright outline-none placeholder:text-muted',
|
|
54
|
+
className
|
|
55
|
+
)}
|
|
56
|
+
{...restProps}
|
|
57
|
+
></textarea>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HTMLTextareaAttributes } from 'svelte/elements';
|
|
2
|
+
type $$ComponentProps = HTMLTextareaAttributes & {
|
|
3
|
+
ref?: HTMLTextAreaElement | null;
|
|
4
|
+
};
|
|
5
|
+
declare const PromptInputTextarea: import("svelte").Component<$$ComponentProps, {}, "value" | "ref">;
|
|
6
|
+
type PromptInputTextarea = ReturnType<typeof PromptInputTextarea>;
|
|
7
|
+
export default PromptInputTextarea;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { cn } from '../../utils/index.js';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
children,
|
|
8
|
+
class: className,
|
|
9
|
+
...restProps
|
|
10
|
+
}: HTMLAttributes<HTMLDivElement> & { children?: Snippet } = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div class={cn('flex items-end justify-between gap-(--era-gap)', className)} {...restProps}>
|
|
14
|
+
{@render children?.()}
|
|
15
|
+
</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
4
|
+
children?: Snippet;
|
|
5
|
+
};
|
|
6
|
+
declare const PromptInputToolbar: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type PromptInputToolbar = ReturnType<typeof PromptInputToolbar>;
|
|
8
|
+
export default PromptInputToolbar;
|