@urbicon-ui/blocks 6.34.0 → 6.36.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 +11 -1
- package/dist/components/Calendar/CalendarHeader.svelte +32 -26
- package/dist/components/Calendar/CalendarMiniMonth.svelte +10 -10
- package/dist/components/Calendar/calendar.variants.js +19 -5
- package/dist/components/Chat/Chat/Chat.svelte +53 -0
- package/dist/components/Chat/Chat/Chat.svelte.d.ts +4 -0
- package/dist/components/Chat/Chat/chat.variants.d.ts +20 -0
- package/dist/components/Chat/Chat/chat.variants.js +15 -0
- package/dist/components/Chat/Chat/index.d.ts +47 -0
- package/dist/components/Chat/Chat/index.js +2 -0
- package/dist/components/Chat/ChatMessage/ChatMessage.svelte +342 -0
- package/dist/components/Chat/ChatMessage/ChatMessage.svelte.d.ts +4 -0
- package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +138 -0
- package/dist/components/Chat/ChatMessage/chat-message.variants.js +118 -0
- package/dist/components/Chat/ChatMessage/index.d.ts +102 -0
- package/dist/components/Chat/ChatMessage/index.js +2 -0
- package/dist/components/Chat/ChatMessageList/ChatMessageList.svelte +301 -0
- package/dist/components/Chat/ChatMessageList/ChatMessageList.svelte.d.ts +6 -0
- package/dist/components/Chat/ChatMessageList/chat-message-list.variants.d.ts +23 -0
- package/dist/components/Chat/ChatMessageList/chat-message-list.variants.js +32 -0
- package/dist/components/Chat/ChatMessageList/chat-scroll.d.ts +45 -0
- package/dist/components/Chat/ChatMessageList/chat-scroll.js +52 -0
- package/dist/components/Chat/ChatMessageList/index.d.ts +93 -0
- package/dist/components/Chat/ChatMessageList/index.js +3 -0
- package/dist/components/Chat/CitationChip/CitationChip.svelte +107 -0
- package/dist/components/Chat/CitationChip/CitationChip.svelte.d.ts +4 -0
- package/dist/components/Chat/CitationChip/citation-chip.variants.d.ts +40 -0
- package/dist/components/Chat/CitationChip/citation-chip.variants.js +42 -0
- package/dist/components/Chat/CitationChip/index.d.ts +69 -0
- package/dist/components/Chat/CitationChip/index.js +2 -0
- package/dist/components/Chat/CodeBlock/CodeBlock.svelte +120 -0
- package/dist/components/Chat/CodeBlock/CodeBlock.svelte.d.ts +4 -0
- package/dist/components/Chat/CodeBlock/code-block.variants.d.ts +40 -0
- package/dist/components/Chat/CodeBlock/code-block.variants.js +51 -0
- package/dist/components/Chat/CodeBlock/index.d.ts +55 -0
- package/dist/components/Chat/CodeBlock/index.js +2 -0
- package/dist/components/Chat/PromptInput/PromptInput.svelte +432 -0
- package/dist/components/Chat/PromptInput/PromptInput.svelte.d.ts +4 -0
- package/dist/components/Chat/PromptInput/index.d.ts +165 -0
- package/dist/components/Chat/PromptInput/index.js +2 -0
- package/dist/components/Chat/PromptInput/prompt-input.variants.d.ts +90 -0
- package/dist/components/Chat/PromptInput/prompt-input.variants.js +102 -0
- package/dist/components/Chat/ReasoningDisclosure/ReasoningDisclosure.svelte +107 -0
- package/dist/components/Chat/ReasoningDisclosure/ReasoningDisclosure.svelte.d.ts +4 -0
- package/dist/components/Chat/ReasoningDisclosure/index.d.ts +85 -0
- package/dist/components/Chat/ReasoningDisclosure/index.js +2 -0
- package/dist/components/Chat/ReasoningDisclosure/reasoning-disclosure.variants.d.ts +20 -0
- package/dist/components/Chat/ReasoningDisclosure/reasoning-disclosure.variants.js +31 -0
- package/dist/components/Chat/StreamingMarkdown/MdBlock.svelte +99 -0
- package/dist/components/Chat/StreamingMarkdown/MdBlock.svelte.d.ts +9 -0
- package/dist/components/Chat/StreamingMarkdown/MdInline.svelte +82 -0
- package/dist/components/Chat/StreamingMarkdown/MdInline.svelte.d.ts +9 -0
- package/dist/components/Chat/StreamingMarkdown/StreamingMarkdown.svelte +118 -0
- package/dist/components/Chat/StreamingMarkdown/StreamingMarkdown.svelte.d.ts +4 -0
- package/dist/components/Chat/StreamingMarkdown/index.d.ts +86 -0
- package/dist/components/Chat/StreamingMarkdown/index.js +2 -0
- package/dist/components/Chat/StreamingMarkdown/md-context.d.ts +58 -0
- package/dist/components/Chat/StreamingMarkdown/md-context.js +1 -0
- package/dist/components/Chat/StreamingMarkdown/streaming-markdown.variants.d.ts +145 -0
- package/dist/components/Chat/StreamingMarkdown/streaming-markdown.variants.js +73 -0
- package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte +174 -0
- package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte.d.ts +4 -0
- package/dist/components/Chat/ToolCallCard/index.d.ts +84 -0
- package/dist/components/Chat/ToolCallCard/index.js +2 -0
- package/dist/components/Chat/ToolCallCard/tool-call-card.variants.d.ts +38 -0
- package/dist/components/Chat/ToolCallCard/tool-call-card.variants.js +38 -0
- package/dist/components/Chat/chat.types.d.ts +82 -0
- package/dist/components/Chat/chat.types.js +7 -0
- package/dist/components/Chat/index.d.ts +22 -0
- package/dist/components/Chat/index.js +14 -0
- package/dist/components/Chat/markdown/blocks.d.ts +54 -0
- package/dist/components/Chat/markdown/blocks.js +462 -0
- package/dist/components/Chat/markdown/inline.d.ts +31 -0
- package/dist/components/Chat/markdown/inline.js +446 -0
- package/dist/components/Chat/markdown/repair.d.ts +23 -0
- package/dist/components/Chat/markdown/repair.js +337 -0
- package/dist/components/Chat/markdown/streaming-harness.d.ts +23 -0
- package/dist/components/Chat/markdown/streaming-harness.js +62 -0
- package/dist/components/Chat/markdown/types.d.ts +139 -0
- package/dist/components/Chat/markdown/types.js +13 -0
- package/dist/components/Chat/markdown/url-policy.d.ts +33 -0
- package/dist/components/Chat/markdown/url-policy.js +109 -0
- package/dist/components/FileUpload/FileUpload.svelte +52 -125
- package/dist/components/FileUpload/FileUpload.svelte.d.ts +1 -1
- package/dist/components/FileUpload/index.d.ts +2 -28
- package/dist/components/Planner/PlannerHeader.svelte +16 -13
- package/dist/components/Planner/planner.variants.js +14 -3
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/i18n/index.d.ts +268 -382
- package/dist/i18n/index.js +83 -9
- package/dist/internal/core/CoreIconButton.svelte +66 -0
- package/dist/internal/core/CoreIconButton.svelte.d.ts +13 -0
- package/dist/internal/core/CoreSpinner.svelte +49 -0
- package/dist/internal/core/CoreSpinner.svelte.d.ts +8 -0
- package/dist/internal/core/spinner-geometry.d.ts +6 -0
- package/dist/internal/core/spinner-geometry.js +6 -0
- package/dist/mint/registry.d.ts +20 -2
- package/dist/mint/registry.js +20 -2
- package/dist/primitives/Badge/Badge.svelte +5 -5
- package/dist/primitives/Badge/badge.variants.js +17 -1
- package/dist/primitives/Button/Button.svelte +4 -2
- package/dist/primitives/Collapsible/Collapsible.svelte +5 -0
- package/dist/primitives/Dialog/Dialog.svelte +7 -5
- package/dist/primitives/Dialog/dialog.variants.d.ts +7 -0
- package/dist/primitives/Dialog/dialog.variants.js +17 -0
- package/dist/primitives/Drawer/Drawer.svelte +7 -5
- package/dist/primitives/Drawer/drawer.variants.d.ts +8 -0
- package/dist/primitives/Drawer/drawer.variants.js +17 -0
- package/dist/primitives/Spinner/Spinner.svelte +3 -1
- package/dist/primitives/SplitPane/SplitPane.svelte +293 -0
- package/dist/primitives/SplitPane/SplitPane.svelte.d.ts +4 -0
- package/dist/primitives/SplitPane/index.d.ts +88 -0
- package/dist/primitives/SplitPane/index.js +2 -0
- package/dist/primitives/SplitPane/split-pane.utils.d.ts +73 -0
- package/dist/primitives/SplitPane/split-pane.utils.js +94 -0
- package/dist/primitives/SplitPane/split-pane.variants.d.ts +40 -0
- package/dist/primitives/SplitPane/split-pane.variants.js +56 -0
- package/dist/primitives/Toast/Toaster.svelte +17 -2
- package/dist/primitives/index.d.ts +2 -0
- package/dist/primitives/index.js +1 -0
- package/dist/utils/file-intake.d.ts +78 -0
- package/dist/utils/file-intake.js +144 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/variants.js +44 -10
- package/package.json +4 -6
package/README.md
CHANGED
|
@@ -107,7 +107,17 @@ Re-exports `@urbicon-ui/i18n`. Components with text content (Pagination, Menu, C
|
|
|
107
107
|
</I18nProvider>
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
**English is bundled eagerly; German is lazy.** The `de` catalog is a dynamic-import chunk, so an English-only app never bundles it. Before that chunk loads, `de` keys resolve to the English fallback (never the raw key). The provider loads `de` client-side on mount, which means a **server-rendered German app** would paint English first and flip on hydration. Fix it by registering `de` eagerly once at server start:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
// src/hooks.server.ts (evaluated once at server start — SSR-safe, static data)
|
|
114
|
+
import { registerBlocksLocale } from '@urbicon-ui/blocks';
|
|
115
|
+
import de from '@urbicon-ui/blocks/i18n/de';
|
|
116
|
+
|
|
117
|
+
registerBlocksLocale('de', de);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
For the provider/hook API, typed keys, SSR locale resolution, and the code-splitting + eager-register details see the [@urbicon-ui/i18n](../i18n/) package.
|
|
111
121
|
|
|
112
122
|
## Development
|
|
113
123
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import { Tooltip } from '../../primitives/Tooltip';
|
|
4
4
|
import { Popover } from '../../primitives/Popover';
|
|
5
5
|
import { SegmentGroup, SegmentItem } from '../../primitives/SegmentGroup';
|
|
6
|
-
import
|
|
6
|
+
// internal core, not the public component — keeps the public-to-public import graph clean (see internal/core/)
|
|
7
|
+
import CoreIconButton from '../../internal/core/CoreIconButton.svelte';
|
|
7
8
|
import ChevronLeftIcon from '../../icons/ChevronLeftIcon.svelte';
|
|
8
9
|
import ChevronRightIcon from '../../icons/ChevronRightIcon.svelte';
|
|
9
10
|
import ChevronDownIcon from '../../icons/ChevronDownIcon.svelte';
|
|
@@ -125,18 +126,24 @@
|
|
|
125
126
|
{@render children()}
|
|
126
127
|
</div>
|
|
127
128
|
{:else}
|
|
129
|
+
<!--
|
|
130
|
+
All header buttons render on the internal CoreIconButton (was `<Button
|
|
131
|
+
unstyled mint="none">`, which emitted only the call-site classes). The
|
|
132
|
+
core's plumbing overlaps the navButton slot's old baseline (inline-flex
|
|
133
|
+
centring, focus-visible reset, disabled opacity/cursor — now supplied by
|
|
134
|
+
the core, stripped from the slot); the deliberate deltas it introduces are
|
|
135
|
+
documented on the slot in calendar.variants.ts.
|
|
136
|
+
-->
|
|
128
137
|
<div class={slot('header', className)} {...restProps}>
|
|
129
138
|
<div class={slot('nav')}>
|
|
130
|
-
<
|
|
131
|
-
unstyled
|
|
132
|
-
mint="none"
|
|
139
|
+
<CoreIconButton
|
|
133
140
|
class={slot('navButton')}
|
|
134
141
|
onclick={() => ctx.navigate(-1)}
|
|
135
142
|
disabled={!ctx.canGoBack || ctx.disabled}
|
|
136
143
|
aria-label={prevLabel}
|
|
137
144
|
>
|
|
138
145
|
<ChevronLeftIcon size={navIconSize} />
|
|
139
|
-
</
|
|
146
|
+
</CoreIconButton>
|
|
140
147
|
</div>
|
|
141
148
|
|
|
142
149
|
<div class="flex items-center gap-2">
|
|
@@ -162,40 +169,43 @@
|
|
|
162
169
|
{/snippet}
|
|
163
170
|
<div class="min-w-48 p-3">
|
|
164
171
|
<div class="mb-2 flex items-center justify-between">
|
|
165
|
-
<
|
|
166
|
-
unstyled
|
|
167
|
-
mint="none"
|
|
172
|
+
<CoreIconButton
|
|
168
173
|
class={slot('navButton')}
|
|
169
174
|
onclick={() => pickerYear--}
|
|
170
175
|
aria-label={bt('calendar.previousYear')}
|
|
171
176
|
>
|
|
172
177
|
<ChevronLeftIcon size={pickerIconSize} />
|
|
173
|
-
</
|
|
178
|
+
</CoreIconButton>
|
|
174
179
|
<span class="text-text-primary font-semibold tabular-nums">{pickerYear}</span>
|
|
175
|
-
<
|
|
176
|
-
unstyled
|
|
177
|
-
mint="none"
|
|
180
|
+
<CoreIconButton
|
|
178
181
|
class={slot('navButton')}
|
|
179
182
|
onclick={() => pickerYear++}
|
|
180
183
|
aria-label={bt('calendar.nextYear')}
|
|
181
184
|
>
|
|
182
185
|
<ChevronRightIcon size={pickerIconSize} />
|
|
183
|
-
</
|
|
186
|
+
</CoreIconButton>
|
|
184
187
|
</div>
|
|
185
188
|
<div class="grid grid-cols-3 gap-1">
|
|
186
189
|
{#each months as m (m.index)}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
<!--
|
|
191
|
+
Text-labelled month cell on the same CoreIconButton as the nav
|
|
192
|
+
buttons (removes the last CalendarHeader→Button edge). The core
|
|
193
|
+
REQUIRES aria-label, so it gets the visible label — the accessible
|
|
194
|
+
name stays the identical string. Never rendered disabled (the
|
|
195
|
+
picker closes when the calendar is disabled), so the core's
|
|
196
|
+
disabled plumbing is inert here.
|
|
197
|
+
-->
|
|
198
|
+
<CoreIconButton
|
|
190
199
|
class="text-text-primary rounded-md px-2 py-1.5 text-sm transition-colors
|
|
191
200
|
{m.isCurrent
|
|
192
201
|
? 'bg-primary-subtle ring-primary text-primary font-semibold ring-1'
|
|
193
202
|
: 'hover:bg-surface-hover'}
|
|
194
|
-
focus-visible:ring-primary/50 focus-visible:ring-2
|
|
203
|
+
focus-visible:ring-primary/50 focus-visible:ring-2"
|
|
195
204
|
onclick={() => selectMonth(m.index)}
|
|
205
|
+
aria-label={m.label}
|
|
196
206
|
>
|
|
197
207
|
{m.label}
|
|
198
|
-
</
|
|
208
|
+
</CoreIconButton>
|
|
199
209
|
{/each}
|
|
200
210
|
</div>
|
|
201
211
|
</div>
|
|
@@ -221,29 +231,25 @@
|
|
|
221
231
|
|
|
222
232
|
{#if showToday}
|
|
223
233
|
<Tooltip label={bt('calendar.today')}>
|
|
224
|
-
<
|
|
225
|
-
unstyled
|
|
226
|
-
mint="none"
|
|
234
|
+
<CoreIconButton
|
|
227
235
|
class="{slot('navButton')} ml-1"
|
|
228
236
|
onclick={() => ctx.goToToday()}
|
|
229
237
|
disabled={!ctx.canGoToToday || ctx.disabled}
|
|
230
238
|
aria-label={bt('calendar.today')}
|
|
231
239
|
>
|
|
232
240
|
<CalendarIcon size={navIconSize} />
|
|
233
|
-
</
|
|
241
|
+
</CoreIconButton>
|
|
234
242
|
</Tooltip>
|
|
235
243
|
{/if}
|
|
236
244
|
|
|
237
|
-
<
|
|
238
|
-
unstyled
|
|
239
|
-
mint="none"
|
|
245
|
+
<CoreIconButton
|
|
240
246
|
class={slot('navButton')}
|
|
241
247
|
onclick={() => ctx.navigate(1)}
|
|
242
248
|
disabled={!ctx.canGoForward || ctx.disabled}
|
|
243
249
|
aria-label={nextLabel}
|
|
244
250
|
>
|
|
245
251
|
<ChevronRightIcon size={navIconSize} />
|
|
246
|
-
</
|
|
252
|
+
</CoreIconButton>
|
|
247
253
|
</div>
|
|
248
254
|
</div>
|
|
249
255
|
{/if}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useBlocksI18n } from '../..';
|
|
3
|
-
import
|
|
3
|
+
// internal core, not the public component — keeps the public-to-public import graph clean (see internal/core/)
|
|
4
|
+
import CoreIconButton from '../../internal/core/CoreIconButton.svelte';
|
|
4
5
|
import { getCalendarContext, createSlotHelper } from './calendar.context';
|
|
5
6
|
import {
|
|
6
7
|
getMonthGrid,
|
|
@@ -118,27 +119,26 @@
|
|
|
118
119
|
</script>
|
|
119
120
|
|
|
120
121
|
<div class={slot('miniCalendar', className)}>
|
|
121
|
-
<!-- Mini header
|
|
122
|
+
<!-- Mini header. Nav buttons render on the internal CoreIconButton (was
|
|
123
|
+
`<Button unstyled mint="none">`); the plumbing/slot split is documented
|
|
124
|
+
on the miniCalendarNavButton slot in calendar.variants.ts. Never
|
|
125
|
+
disabled, so the core's disabled plumbing is inert here. -->
|
|
122
126
|
<div class={slot('miniCalendarHeader')}>
|
|
123
|
-
<
|
|
124
|
-
unstyled
|
|
125
|
-
mint="none"
|
|
127
|
+
<CoreIconButton
|
|
126
128
|
class={slot('miniCalendarNavButton')}
|
|
127
129
|
onclick={() => navigateMini(-1)}
|
|
128
130
|
aria-label={bt('calendar.previousMonth')}
|
|
129
131
|
>
|
|
130
132
|
‹
|
|
131
|
-
</
|
|
133
|
+
</CoreIconButton>
|
|
132
134
|
<span class={slot('miniCalendarTitle')}>{miniTitle}</span>
|
|
133
|
-
<
|
|
134
|
-
unstyled
|
|
135
|
-
mint="none"
|
|
135
|
+
<CoreIconButton
|
|
136
136
|
class={slot('miniCalendarNavButton')}
|
|
137
137
|
onclick={() => navigateMini(1)}
|
|
138
138
|
aria-label={bt('calendar.nextMonth')}
|
|
139
139
|
>
|
|
140
140
|
›
|
|
141
|
-
</
|
|
141
|
+
</CoreIconButton>
|
|
142
142
|
</div>
|
|
143
143
|
|
|
144
144
|
<!-- Weekday headers — narrow names duplicate in many locales (de-DE: M, D,
|
|
@@ -7,12 +7,23 @@ export const calendarVariants = tv({
|
|
|
7
7
|
header: ['flex items-center justify-between', 'border-b border-border-hairline'],
|
|
8
8
|
title: 'font-semibold text-text-primary select-none',
|
|
9
9
|
nav: 'flex items-center gap-1',
|
|
10
|
+
// Rendered on the internal CoreIconButton (behaviour-only base: inline-flex
|
|
11
|
+
// centring, cursor/select affordance, focus-visible reset, disabled
|
|
12
|
+
// opacity/cursor/inertness), so this slot carries only the visual identity
|
|
13
|
+
// on top — the classes the core already supplies (inline-flex items-center
|
|
14
|
+
// justify-center, focus-visible:outline-none, disabled:opacity-50,
|
|
15
|
+
// disabled:cursor-not-allowed) are not repeated here. Deliberate deltas vs.
|
|
16
|
+
// the old `<Button unstyled mint="none">` render (which had NO plumbing):
|
|
17
|
+
// `cursor-pointer` (was the UA arrow — Tailwind 4 preflight doesn't set it;
|
|
18
|
+
// now consistent with every styled Button) and `disabled:pointer-events-none`
|
|
19
|
+
// (a disabled nav button is fully inert: no more hover-bg feedback or
|
|
20
|
+
// not-allowed cursor while disabled — matching the styled Button base).
|
|
21
|
+
// Mirrors planner.variants navButton. See internal/core/.
|
|
10
22
|
navButton: [
|
|
11
|
-
'
|
|
23
|
+
'rounded-md',
|
|
12
24
|
'text-text-secondary hover:bg-surface-hover hover:text-text-primary',
|
|
13
25
|
'transition-colors duration-[var(--blocks-duration-fast)]',
|
|
14
|
-
'focus-visible:
|
|
15
|
-
'disabled:opacity-50 disabled:cursor-not-allowed'
|
|
26
|
+
'focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2'
|
|
16
27
|
],
|
|
17
28
|
// Grid
|
|
18
29
|
grid: 'w-full',
|
|
@@ -131,11 +142,14 @@ export const calendarVariants = tv({
|
|
|
131
142
|
miniCalendar: ['shrink-0 flex flex-col', 'border-r border-border-hairline'],
|
|
132
143
|
miniCalendarHeader: 'flex items-center justify-between',
|
|
133
144
|
miniCalendarTitle: 'font-semibold text-text-primary text-center select-none',
|
|
145
|
+
// Rendered on the internal CoreIconButton — same plumbing/slot split as
|
|
146
|
+
// `navButton` above (and the same deliberate cursor-pointer delta); these
|
|
147
|
+
// buttons are never disabled, so the disabled plumbing is inert.
|
|
134
148
|
miniCalendarNavButton: [
|
|
135
|
-
'
|
|
149
|
+
'rounded-md',
|
|
136
150
|
'text-text-secondary hover:bg-surface-hover hover:text-text-primary',
|
|
137
151
|
'transition-colors duration-[var(--blocks-duration-fast)]',
|
|
138
|
-
'focus-visible:
|
|
152
|
+
'focus-visible:ring-2 focus-visible:ring-primary/50'
|
|
139
153
|
],
|
|
140
154
|
miniCalendarWeekday: 'text-center text-text-tertiary select-none font-medium',
|
|
141
155
|
miniCalendarDay: [
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getBlocksConfig, resolveSlotClasses } from '../../../provider';
|
|
3
|
+
import { chatVariants } from './chat.variants';
|
|
4
|
+
import type { ChatProps } from './index';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
children,
|
|
8
|
+
header,
|
|
9
|
+
composer,
|
|
10
|
+
class: className,
|
|
11
|
+
unstyled: unstyledProp = false,
|
|
12
|
+
slotClasses: slotClassesProp = {},
|
|
13
|
+
preset,
|
|
14
|
+
...restProps
|
|
15
|
+
}: ChatProps = $props();
|
|
16
|
+
|
|
17
|
+
const blocksConfig = getBlocksConfig();
|
|
18
|
+
const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
|
|
19
|
+
|
|
20
|
+
const styles = chatVariants();
|
|
21
|
+
const slotClasses = $derived(
|
|
22
|
+
resolveSlotClasses(blocksConfig, 'Chat', preset, {}, slotClassesProp)
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
function cls(name: keyof typeof slotClasses, extra?: string | (string | undefined)[]) {
|
|
26
|
+
if (unstyled) {
|
|
27
|
+
const own = slotClasses?.[name];
|
|
28
|
+
return [own, ...(Array.isArray(extra) ? extra : [extra])].filter(Boolean).join(' ');
|
|
29
|
+
}
|
|
30
|
+
const slotFns = styles as Record<string, (args: { class?: unknown }) => string>;
|
|
31
|
+
return slotFns[name]({
|
|
32
|
+
class: [slotClasses?.[name], ...(Array.isArray(extra) ? extra : [extra])]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<div class={cls('root', className)} {...restProps}>
|
|
38
|
+
{#if header}
|
|
39
|
+
<div class={cls('header')}>
|
|
40
|
+
{@render header()}
|
|
41
|
+
</div>
|
|
42
|
+
{/if}
|
|
43
|
+
|
|
44
|
+
<div class={cls('body')}>
|
|
45
|
+
{@render children?.()}
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
{#if composer}
|
|
49
|
+
<div class={cls('composer')}>
|
|
50
|
+
{@render composer()}
|
|
51
|
+
</div>
|
|
52
|
+
{/if}
|
|
53
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type SlotNames, type VariantProps } from '../../../utils/variants.js';
|
|
2
|
+
export declare const chatVariants: ((props?: {} | undefined) => {
|
|
3
|
+
root: (props?: ({} & {
|
|
4
|
+
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
5
|
+
}) | undefined) => string;
|
|
6
|
+
header: (props?: ({} & {
|
|
7
|
+
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
8
|
+
}) | undefined) => string;
|
|
9
|
+
body: (props?: ({} & {
|
|
10
|
+
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
11
|
+
}) | undefined) => string;
|
|
12
|
+
composer: (props?: ({} & {
|
|
13
|
+
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
14
|
+
}) | undefined) => string;
|
|
15
|
+
}) & {
|
|
16
|
+
readonly config: import("../../../utils/variants.js").TVConfig;
|
|
17
|
+
};
|
|
18
|
+
export type ChatVariants = VariantProps<typeof chatVariants>;
|
|
19
|
+
/** Slot names derived from the tv() config — single source of truth for slotClasses. */
|
|
20
|
+
export type ChatSlots = SlotNames<typeof chatVariants>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { tv } from '../../../utils/variants.js';
|
|
2
|
+
export const chatVariants = tv({
|
|
3
|
+
slots: {
|
|
4
|
+
// Fills its parent's height as a flex column. `min-h-0` is the discipline
|
|
5
|
+
// that lets the body child own the scroll instead of overflowing the page.
|
|
6
|
+
root: ['flex h-full min-h-0 w-full flex-col bg-surface-base'],
|
|
7
|
+
// Pinned header — never scrolls.
|
|
8
|
+
header: ['shrink-0 border-b border-border-subtle'],
|
|
9
|
+
// The conversation area. Flexes to fill and clamps to min-h-0 so its own
|
|
10
|
+
// scrollable child (ChatMessageList) can scroll; the container never does.
|
|
11
|
+
body: ['min-h-0 min-w-0 flex-1'],
|
|
12
|
+
// Pinned composer at the bottom.
|
|
13
|
+
composer: ['shrink-0 border-t border-border-subtle bg-surface-base']
|
|
14
|
+
}
|
|
15
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { ChatSlots, ChatVariants } from './chat.variants.js';
|
|
4
|
+
/**
|
|
5
|
+
* @description Thin full-height layout shell for a chat surface: an optional pinned
|
|
6
|
+
* `header` (border-b), the scrollable conversation area as `children` (the consumer
|
|
7
|
+
* drops a ChatMessageList here — the shell itself never scrolls, the body child does),
|
|
8
|
+
* and an optional pinned `composer` at the bottom (border-t, e.g. PromptInput). No
|
|
9
|
+
* state, no context, no provider — pure structure with `min-h-0` flex discipline so it
|
|
10
|
+
* fills its parent and hands scrolling to its body.
|
|
11
|
+
*
|
|
12
|
+
* @tag ai
|
|
13
|
+
* @tag layout
|
|
14
|
+
* @related ChatMessageList
|
|
15
|
+
* @related PromptInput
|
|
16
|
+
* @stability experimental
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```svelte
|
|
20
|
+
* <Chat>
|
|
21
|
+
* {#snippet header()}<Toolbar>…</Toolbar>{/snippet}
|
|
22
|
+
* <ChatMessageList {messages} />
|
|
23
|
+
* {#snippet composer()}<PromptInput onSubmit={send} />{/snippet}
|
|
24
|
+
* </Chat>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export interface ChatProps extends ChatVariants, Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'class'> {
|
|
28
|
+
/** The scrollable conversation area — typically a ChatMessageList. */
|
|
29
|
+
children?: Snippet;
|
|
30
|
+
/** Optional pinned header rendered above the conversation (border-b). */
|
|
31
|
+
header?: Snippet;
|
|
32
|
+
/** Optional pinned composer rendered below the conversation (border-t) — e.g. PromptInput. */
|
|
33
|
+
composer?: Snippet;
|
|
34
|
+
/** Extra classes merged onto the root element. */
|
|
35
|
+
class?: string;
|
|
36
|
+
/** Remove all default tv classes. */
|
|
37
|
+
unstyled?: boolean;
|
|
38
|
+
/** Per-slot class overrides. Slots: root | header | body | composer */
|
|
39
|
+
slotClasses?: Partial<Record<ChatSlots, string>>;
|
|
40
|
+
/**
|
|
41
|
+
* Apply a named preset registered via `<BlocksProvider presets={{ Chat: {...} }}>`.
|
|
42
|
+
* Prefer this over `class` overrides for reusable custom looks.
|
|
43
|
+
*/
|
|
44
|
+
preset?: string;
|
|
45
|
+
}
|
|
46
|
+
export { default as Chat } from './Chat.svelte';
|
|
47
|
+
export { type ChatSlots, type ChatVariants, chatVariants } from './chat.variants.js';
|