@urbicon-ui/blocks 6.43.0 → 6.44.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/components/Calendar/calendar.variants.d.ts +63 -63
- package/dist/components/Chat/ChatMessage/ChatMessage.svelte +93 -67
- package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +7 -0
- package/dist/components/Chat/ChatMessage/chat-message.variants.js +45 -12
- package/dist/components/Chat/ChatMessage/index.d.ts +20 -5
- package/dist/components/Chat/CodeBlock/CodeBlock.svelte +59 -33
- package/dist/components/Chat/CodeBlock/code-block.variants.d.ts +7 -0
- package/dist/components/Chat/CodeBlock/code-block.variants.js +28 -13
- package/dist/components/Chat/CodeBlock/index.d.ts +39 -4
- package/dist/components/Chat/PromptInput/PromptInput.svelte +9 -16
- package/dist/components/Chat/PromptInput/prompt-input.variants.js +16 -15
- package/dist/components/Chat/ToolCallCard/ToolCallCard.svelte +9 -4
- package/dist/components/Chat/ToolCallCard/index.d.ts +4 -3
- package/dist/components/Chat/ToolCallCard/tool-call-card.variants.d.ts +0 -3
- package/dist/components/Chat/ToolCallCard/tool-call-card.variants.js +4 -4
- package/dist/components/CopyButton/CopyButton.svelte +9 -19
- package/dist/components/CopyButton/copy-button.variants.d.ts +4 -4
- package/dist/components/FileUpload/fileUpload.variants.js +6 -1
- package/dist/components/PinInput/PinInput.svelte +12 -20
- package/dist/components/TimeInput/TimeInput.svelte +12 -20
- package/dist/i18n/index.d.ts +398 -2
- package/dist/internal/copy-state.svelte.d.ts +60 -0
- package/dist/internal/copy-state.svelte.js +76 -0
- package/dist/internal/core/CoreFieldMessage.svelte +81 -0
- package/dist/internal/core/CoreFieldMessage.svelte.d.ts +23 -0
- package/dist/internal/field-chrome.js +2 -2
- package/dist/primitives/Alert/alert.variants.d.ts +8 -8
- package/dist/primitives/Checkbox/Checkbox.svelte +10 -20
- package/dist/primitives/Checkbox/checkbox.variants.js +1 -1
- package/dist/primitives/Combobox/Combobox.svelte +16 -18
- package/dist/primitives/Combobox/combobox.variants.js +12 -5
- package/dist/primitives/Input/Input.svelte +10 -20
- package/dist/primitives/JourneyTimeline/journey-timeline.variants.d.ts +22 -22
- package/dist/primitives/RadioGroup/RadioGroup.svelte +10 -20
- package/dist/primitives/RadioGroup/radioGroup.variants.js +7 -2
- package/dist/primitives/Select/Select.svelte +10 -20
- package/dist/primitives/Select/select.variants.js +2 -2
- package/dist/primitives/Slider/Slider.svelte +10 -20
- package/dist/primitives/Spinner/spinner.variants.d.ts +16 -16
- package/dist/primitives/Stepper/stepper.variants.d.ts +11 -11
- package/dist/primitives/Stepper/stepper.variants.js +2 -1
- package/dist/primitives/Tab/tab.variants.js +5 -2
- package/dist/primitives/Textarea/Textarea.svelte +10 -15
- package/dist/primitives/Textarea/textarea.variants.js +2 -2
- package/dist/primitives/Toast/toast.variants.d.ts +12 -12
- package/dist/primitives/Toggle/Toggle.svelte +10 -20
- package/dist/primitives/Toggle/toggle.variants.js +9 -7
- package/dist/style/foundation.css +19 -9
- package/dist/style/semantic.css +59 -2
- package/dist/style/themes/forest.css +2 -2
- package/dist/style/themes/neutral.css +2 -2
- package/dist/style/themes/ocean.css +2 -2
- package/dist/style/themes/rose.css +2 -2
- package/dist/style/themes/sunset.css +2 -2
- package/dist/utils/figma-token-export.js +7 -3
- package/package.json +3 -3
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { tv } from '../../../utils/variants.js';
|
|
2
2
|
export const codeBlockVariants = tv({
|
|
3
3
|
slots: {
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
],
|
|
10
|
-
// Header only renders when there is something to show (lang / copy / actions).
|
|
11
|
-
header: [
|
|
12
|
-
'flex items-center justify-between gap-2',
|
|
13
|
-
'px-3 py-1.5 border-b border-border-subtle'
|
|
14
|
-
],
|
|
15
|
-
langLabel: ['font-mono text-xs text-text-tertiary select-none'],
|
|
4
|
+
root: ['relative block w-full overflow-hidden box-border'],
|
|
5
|
+
// Header only renders when there is something to show (label / lang / copy /
|
|
6
|
+
// actions).
|
|
7
|
+
header: ['flex items-center justify-between gap-2'],
|
|
8
|
+
langLabel: ['text-xs text-text-tertiary select-none'],
|
|
16
9
|
copyButton: [
|
|
17
10
|
'inline-flex items-center gap-1.5',
|
|
18
11
|
'px-2 py-1 rounded-modify',
|
|
@@ -26,12 +19,33 @@ export const codeBlockVariants = tv({
|
|
|
26
19
|
// never the page. Focusable + role=region so keyboard users can reach the
|
|
27
20
|
// scroll (a11y for scrollable content).
|
|
28
21
|
pre: [
|
|
29
|
-
'm-0
|
|
22
|
+
'm-0',
|
|
30
23
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-inset'
|
|
31
24
|
],
|
|
32
25
|
code: ['font-mono text-sm text-text-primary']
|
|
33
26
|
},
|
|
34
27
|
variants: {
|
|
28
|
+
/**
|
|
29
|
+
* `card` — the standalone block: own surface, own outline, own radius. This
|
|
30
|
+
* is the right frame when the code sits directly in a reading flow (a fenced
|
|
31
|
+
* block in streamed markdown).
|
|
32
|
+
*
|
|
33
|
+
* `plain` — the EMBEDDED block: no surface, no border, no radius, no padding
|
|
34
|
+
* of its own. A card inside a card is the single loudest source of visual
|
|
35
|
+
* noise in this family — nested outlines at the same radius, two header rows
|
|
36
|
+
* and three divider lines for one JSON payload. When the parent already
|
|
37
|
+
* frames the content (ToolCallCard), the code only needs its monospace face
|
|
38
|
+
* to read as code. The parent owns the frame; the child owns the text.
|
|
39
|
+
*/
|
|
40
|
+
variant: {
|
|
41
|
+
card: {
|
|
42
|
+
root: 'bg-surface-elevated border border-border-subtle rounded-contain',
|
|
43
|
+
header: 'px-3 py-1.5 border-b border-border-subtle',
|
|
44
|
+
langLabel: 'font-mono',
|
|
45
|
+
pre: 'px-3 py-2.5'
|
|
46
|
+
},
|
|
47
|
+
plain: {}
|
|
48
|
+
},
|
|
35
49
|
// false → single-line semantics, horizontal scroll inside the block.
|
|
36
50
|
// true → soft-wrap long lines, no horizontal scroll.
|
|
37
51
|
wrap: {
|
|
@@ -46,6 +60,7 @@ export const codeBlockVariants = tv({
|
|
|
46
60
|
}
|
|
47
61
|
},
|
|
48
62
|
defaultVariants: {
|
|
63
|
+
variant: 'card',
|
|
49
64
|
wrap: false
|
|
50
65
|
}
|
|
51
66
|
});
|
|
@@ -2,11 +2,14 @@ import type { Snippet } from 'svelte';
|
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
3
|
import type { CodeBlockSlots, CodeBlockVariants } from './code-block.variants.js';
|
|
4
4
|
/**
|
|
5
|
-
* @description Read-only code display
|
|
5
|
+
* @description Read-only code display with a one-click copy interaction: the copy
|
|
6
6
|
* button swaps its icon and label to a confirmation for two seconds and fires `onCopy`.
|
|
7
7
|
* Renders raw text only — no built-in syntax highlighting; a consumer or the
|
|
8
8
|
* StreamingMarkdown renderer can layer highlighting in via a snippet. Used by
|
|
9
9
|
* StreamingMarkdown for fenced code blocks, and standalone for any code snippet.
|
|
10
|
+
* `variant="card"` (default) brings its own surface, outline and radius;
|
|
11
|
+
* `variant="plain"` drops all three for embedding inside a container that already
|
|
12
|
+
* frames the content (as ToolCallCard does), so nested outlines never stack.
|
|
10
13
|
*
|
|
11
14
|
* @tag ai
|
|
12
15
|
* @tag display
|
|
@@ -23,6 +26,13 @@ export interface CodeBlockProps extends CodeBlockVariants, Omit<HTMLAttributes<H
|
|
|
23
26
|
code: string;
|
|
24
27
|
/** Language label shown in the header. Display-only — does not drive highlighting. */
|
|
25
28
|
lang?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Header caption, shown instead of `lang`. For an embedded block, what the
|
|
31
|
+
* payload *is* ("Input", "Response body") says more than the language it is
|
|
32
|
+
* serialised in — and rendering both states the same fact twice. `lang` still
|
|
33
|
+
* names the scrollable region for screen readers when both are given.
|
|
34
|
+
*/
|
|
35
|
+
label?: string;
|
|
26
36
|
/** Show the copy button in the header. */
|
|
27
37
|
showCopy?: boolean;
|
|
28
38
|
/**
|
|
@@ -30,19 +40,44 @@ export interface CodeBlockProps extends CodeBlockVariants, Omit<HTMLAttributes<H
|
|
|
30
40
|
* block; `true` wraps with `whitespace-pre-wrap` + word breaking.
|
|
31
41
|
*/
|
|
32
42
|
wrap?: boolean;
|
|
33
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Accessible label / tooltip for the copy button at rest. These three labels
|
|
45
|
+
* are plain English defaults rather than translations on purpose: pulling the
|
|
46
|
+
* i18n registry into this leaf costs +5 KB gz, which StreamingMarkdown and
|
|
47
|
+
* ReasoningDisclosure would inherit by embedding it. Pass your own strings to
|
|
48
|
+
* localise.
|
|
49
|
+
* @default 'Copy'
|
|
50
|
+
*/
|
|
34
51
|
copyLabel?: string;
|
|
35
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Label shown for two seconds after a successful copy.
|
|
54
|
+
* @default 'Copied'
|
|
55
|
+
*/
|
|
36
56
|
copiedLabel?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Label shown for two seconds after a FAILED copy — e.g. a denied clipboard
|
|
59
|
+
* permission or a non-secure context.
|
|
60
|
+
* @default 'Copy failed'
|
|
61
|
+
*/
|
|
62
|
+
copyFailedLabel?: string;
|
|
37
63
|
/** Called with the copied code after a successful clipboard write. */
|
|
38
64
|
onCopy?: (code: string) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Called with the thrown reason when the clipboard write fails. Without a
|
|
67
|
+
* handler the failure is logged; either way the button reports it.
|
|
68
|
+
*/
|
|
69
|
+
onCopyError?: (error: unknown) => void;
|
|
39
70
|
/** Extra header actions rendered to the right, before the copy button. */
|
|
40
71
|
actions?: Snippet;
|
|
41
72
|
/** Extra classes merged onto the root element. */
|
|
42
73
|
class?: string;
|
|
43
74
|
/** Remove all default tv classes. */
|
|
44
75
|
unstyled?: boolean;
|
|
45
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* Per-slot class overrides. Slots: root | header | langLabel | copyButton | pre | code.
|
|
78
|
+
* Note `variant="plain"` deliberately leaves root/header/pre without surface,
|
|
79
|
+
* outline or padding — the embedding parent supplies those.
|
|
80
|
+
*/
|
|
46
81
|
slotClasses?: Partial<Record<CodeBlockSlots, string>>;
|
|
47
82
|
/**
|
|
48
83
|
* Apply a named preset registered via `<BlocksProvider presets={{ CodeBlock: {...} }}>`.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { onDestroy, tick } from 'svelte';
|
|
3
3
|
import { useBlocksI18n } from '../../..';
|
|
4
4
|
import { getBlocksConfig, resolveSlotClasses } from '../../../provider';
|
|
5
|
+
import CoreIconButton from '../../../internal/core/CoreIconButton.svelte';
|
|
5
6
|
import { resolveIcon } from '../../../icons';
|
|
6
7
|
import SendIconDefault from '../../../icons/SendIcon.svelte';
|
|
7
8
|
import SquareIconDefault from '../../../icons/SquareIcon.svelte';
|
|
@@ -350,15 +351,14 @@
|
|
|
350
351
|
</span>
|
|
351
352
|
<span class={cls('attachmentName')} title={entry.file.name}>{entry.file.name}</span>
|
|
352
353
|
<span class={cls('attachmentSize')}>{formatFileSize(entry.file.size)}</span>
|
|
353
|
-
<
|
|
354
|
-
type="button"
|
|
354
|
+
<CoreIconButton
|
|
355
355
|
class={cls('attachmentRemove')}
|
|
356
356
|
data-attachment-remove
|
|
357
357
|
aria-label={removeAttachmentLabel(entry.file.name)}
|
|
358
358
|
onclick={() => removeAttachment(entry, i)}
|
|
359
359
|
>
|
|
360
360
|
<CloseIcon size={14} />
|
|
361
|
-
</
|
|
361
|
+
</CoreIconButton>
|
|
362
362
|
</li>
|
|
363
363
|
{/each}
|
|
364
364
|
</ul>
|
|
@@ -382,15 +382,14 @@
|
|
|
382
382
|
<div class={cls('actions')}>
|
|
383
383
|
<div class={cls('leading')}>
|
|
384
384
|
{#if allowAttachments}
|
|
385
|
-
<
|
|
386
|
-
type="button"
|
|
385
|
+
<CoreIconButton
|
|
387
386
|
class={cls('attachButton')}
|
|
388
387
|
aria-label={attachLabel}
|
|
389
388
|
{disabled}
|
|
390
389
|
onclick={openFilePicker}
|
|
391
390
|
>
|
|
392
391
|
<PaperclipIcon size={iconSize} />
|
|
393
|
-
</
|
|
392
|
+
</CoreIconButton>
|
|
394
393
|
{/if}
|
|
395
394
|
{@render leading?.()}
|
|
396
395
|
</div>
|
|
@@ -398,24 +397,18 @@
|
|
|
398
397
|
<div class={cls('trailing')}>
|
|
399
398
|
{@render trailing?.()}
|
|
400
399
|
{#if busy}
|
|
401
|
-
<
|
|
402
|
-
type="button"
|
|
403
|
-
class={cls('stopButton')}
|
|
404
|
-
aria-label={stopLabel}
|
|
405
|
-
onclick={() => onStop?.()}
|
|
406
|
-
>
|
|
400
|
+
<CoreIconButton class={cls('stopButton')} aria-label={stopLabel} onclick={() => onStop?.()}>
|
|
407
401
|
<SquareIcon size={iconSize} />
|
|
408
|
-
</
|
|
402
|
+
</CoreIconButton>
|
|
409
403
|
{:else}
|
|
410
|
-
<
|
|
411
|
-
type="button"
|
|
404
|
+
<CoreIconButton
|
|
412
405
|
class={cls('sendButton')}
|
|
413
406
|
aria-label={sendLabel}
|
|
414
407
|
disabled={!canSubmit}
|
|
415
408
|
onclick={submit}
|
|
416
409
|
>
|
|
417
410
|
<SendIcon size={iconSize} />
|
|
418
|
-
</
|
|
411
|
+
</CoreIconButton>
|
|
419
412
|
{/if}
|
|
420
413
|
</div>
|
|
421
414
|
</div>
|
|
@@ -29,13 +29,19 @@ export const promptInputVariants = tv({
|
|
|
29
29
|
],
|
|
30
30
|
attachmentName: ['truncate text-xs text-text-primary min-w-0'],
|
|
31
31
|
attachmentSize: ['shrink-0 text-2xs text-text-tertiary tabular-nums'],
|
|
32
|
+
// The icon-only controls below render through CoreIconButton, so they carry
|
|
33
|
+
// only what it does NOT supply. Its plumbing is flex centring, cursor/select,
|
|
34
|
+
// `focus-visible:outline-none` and the disabled trio (opacity, cursor,
|
|
35
|
+
// pointer-events) — repeating any of those here would be resolved by
|
|
36
|
+
// stylesheet order rather than the override ladder, since the core runs no
|
|
37
|
+
// variant engine. `disabled:hover:*` is likewise unnecessary: the core's
|
|
38
|
+
// `disabled:pointer-events-none` already stops hover from firing.
|
|
32
39
|
attachmentRemove: [
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'text-text-tertiary cursor-pointer',
|
|
40
|
+
'shrink-0 size-5 rounded-modify',
|
|
41
|
+
'text-text-tertiary',
|
|
36
42
|
'transition-[color,background-color] duration-[var(--blocks-duration-fast)] ease-out',
|
|
37
43
|
'hover:bg-surface-hover hover:text-text-primary',
|
|
38
|
-
'focus-visible:
|
|
44
|
+
'focus-visible:ring-2 focus-visible:ring-primary'
|
|
39
45
|
],
|
|
40
46
|
// Chromeless auto-growing textarea — the composer surface owns the border.
|
|
41
47
|
textarea: [
|
|
@@ -50,29 +56,24 @@ export const promptInputVariants = tv({
|
|
|
50
56
|
trailing: ['flex items-center gap-1 shrink-0'],
|
|
51
57
|
// Icon-only affordance buttons.
|
|
52
58
|
attachButton: [
|
|
53
|
-
'
|
|
54
|
-
'rounded-modify text-text-secondary cursor-pointer',
|
|
59
|
+
'shrink-0 rounded-modify text-text-secondary',
|
|
55
60
|
'transition-[color,background-color] duration-[var(--blocks-duration-fast)] ease-out',
|
|
56
61
|
'hover:bg-surface-hover hover:text-text-primary',
|
|
57
|
-
'focus-visible:
|
|
58
|
-
'disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent'
|
|
62
|
+
'focus-visible:ring-2 focus-visible:ring-primary'
|
|
59
63
|
],
|
|
60
64
|
sendButton: [
|
|
61
|
-
'
|
|
62
|
-
'rounded-modify cursor-pointer',
|
|
65
|
+
'shrink-0 rounded-modify',
|
|
63
66
|
'bg-primary text-text-on-primary',
|
|
64
67
|
'transition-[color,background-color,opacity] duration-[var(--blocks-duration-fast)] ease-out',
|
|
65
68
|
'hover:bg-primary-hover active:bg-primary-active',
|
|
66
|
-
'focus-visible:
|
|
67
|
-
'disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-primary'
|
|
69
|
+
'focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2'
|
|
68
70
|
],
|
|
69
71
|
stopButton: [
|
|
70
|
-
'
|
|
71
|
-
'rounded-modify cursor-pointer',
|
|
72
|
+
'shrink-0 rounded-modify',
|
|
72
73
|
'bg-neutral text-text-on-primary',
|
|
73
74
|
'transition-[color,background-color] duration-[var(--blocks-duration-fast)] ease-out',
|
|
74
75
|
'hover:bg-neutral-hover active:bg-neutral-active',
|
|
75
|
-
'focus-visible:
|
|
76
|
+
'focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2'
|
|
76
77
|
],
|
|
77
78
|
// Compact inline validation line (first rejection). role=status is set in
|
|
78
79
|
// the component; the empty state renders no box.
|
|
@@ -153,20 +153,25 @@
|
|
|
153
153
|
{#if children}
|
|
154
154
|
{@render children(toolCall)}
|
|
155
155
|
{:else}
|
|
156
|
+
<!--
|
|
157
|
+
The payloads render as `plain` CodeBlocks: this card already IS the frame,
|
|
158
|
+
so a bordered child card would stack a second outline at the same radius
|
|
159
|
+
inside the first. The section caption moved into the block's own header
|
|
160
|
+
too — "Input" above a header reading "json" was one chrome row and one
|
|
161
|
+
label too many for a single payload.
|
|
162
|
+
-->
|
|
156
163
|
<div class={cls('body')}>
|
|
157
164
|
{#if toolCall.errorMessage}
|
|
158
165
|
<p class={cls('errorMessage')}>{toolCall.errorMessage}</p>
|
|
159
166
|
{/if}
|
|
160
167
|
{#if toolCall.input !== undefined}
|
|
161
168
|
<div class={cls('section')}>
|
|
162
|
-
<
|
|
163
|
-
<CodeBlock lang="json" code={stringify(toolCall.input)} />
|
|
169
|
+
<CodeBlock variant="plain" label={inputLabel} code={stringify(toolCall.input)} />
|
|
164
170
|
</div>
|
|
165
171
|
{/if}
|
|
166
172
|
{#if toolCall.output !== undefined}
|
|
167
173
|
<div class={cls('section')}>
|
|
168
|
-
<
|
|
169
|
-
<CodeBlock lang="json" code={stringify(toolCall.output)} />
|
|
174
|
+
<CodeBlock variant="plain" label={outputLabel} code={stringify(toolCall.output)} />
|
|
170
175
|
</div>
|
|
171
176
|
{/if}
|
|
172
177
|
</div>
|
|
@@ -59,9 +59,9 @@ export interface ToolCallCardProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
59
59
|
completeLabel?: string;
|
|
60
60
|
/** Header badge label for the `error` state. @default 'Failed' */
|
|
61
61
|
errorLabel?: string;
|
|
62
|
-
/**
|
|
62
|
+
/** Caption in the input payload's header. @default 'Input' */
|
|
63
63
|
inputLabel?: string;
|
|
64
|
-
/**
|
|
64
|
+
/** Caption in the output payload's header. @default 'Output' */
|
|
65
65
|
outputLabel?: string;
|
|
66
66
|
/** Extra classes merged onto the root card element. */
|
|
67
67
|
class?: string;
|
|
@@ -70,7 +70,8 @@ export interface ToolCallCardProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
70
70
|
/**
|
|
71
71
|
* Per-slot class overrides. Slots: `trigger` (header button), `triggerLeft`,
|
|
72
72
|
* `triggerRight`, `spinner`, `toolName`, `chevron`, `body`, `section`,
|
|
73
|
-
* `
|
|
73
|
+
* `errorMessage`. The payloads render as `variant="plain"` CodeBlocks — style
|
|
74
|
+
* those through `<BlocksProvider presets={{ CodeBlock: {...} }}>`.
|
|
74
75
|
*/
|
|
75
76
|
slotClasses?: Partial<Record<ToolCallCardSlots, string>>;
|
|
76
77
|
/**
|
|
@@ -24,9 +24,6 @@ export declare const toolCallCardVariants: ((props?: {} | undefined) => {
|
|
|
24
24
|
section: (props?: ({} & {
|
|
25
25
|
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;
|
|
26
26
|
}) | undefined) => string;
|
|
27
|
-
sectionLabel: (props?: ({} & {
|
|
28
|
-
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;
|
|
29
|
-
}) | undefined) => string;
|
|
30
27
|
errorMessage: (props?: ({} & {
|
|
31
28
|
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;
|
|
32
29
|
}) | undefined) => string;
|
|
@@ -28,10 +28,10 @@ export const toolCallCardVariants = tv({
|
|
|
28
28
|
],
|
|
29
29
|
// Default body wrapper (input/output sections + error line).
|
|
30
30
|
body: 'flex flex-col gap-3',
|
|
31
|
-
// One
|
|
32
|
-
|
|
33
|
-
//
|
|
34
|
-
|
|
31
|
+
// One payload block. The caption lives in the CodeBlock's own header (it is
|
|
32
|
+
// passed as `label`), so this is a plain positioning wrapper — no heading row
|
|
33
|
+
// of its own, which is what removed a whole chrome level from the card.
|
|
34
|
+
section: 'flex flex-col',
|
|
35
35
|
// Error message line shown above the sections.
|
|
36
36
|
errorMessage: 'text-sm text-danger'
|
|
37
37
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { resolveIcon } from '../../icons';
|
|
4
4
|
import CheckIconDefault from '../../icons/CheckIcon.svelte';
|
|
5
5
|
import CopyIconDefault from '../../icons/CopyIcon.svelte';
|
|
6
|
+
import { createCopyState } from '../../internal/copy-state.svelte';
|
|
6
7
|
import { Button } from '../../primitives/Button';
|
|
7
8
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
8
9
|
import { copyButtonVariants } from './copy-button.variants';
|
|
@@ -40,8 +41,11 @@
|
|
|
40
41
|
const blocksConfig = getBlocksConfig();
|
|
41
42
|
const unstyled = $derived(unstyledProp || blocksConfig?.unstyled || false);
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
// Shares the clipboard state machine with CodeBlock and ChatMessage — see
|
|
45
|
+
// internal/copy-state.svelte.ts for why the outcome is returned rather than
|
|
46
|
+
// delivered through callbacks captured at init.
|
|
47
|
+
const copyState = createCopyState({ timeout: () => timeout });
|
|
48
|
+
const state = $derived(copyState.phase);
|
|
45
49
|
|
|
46
50
|
const copyText = $derived(label ?? bt('accessibility.copy'));
|
|
47
51
|
const copiedText = $derived(copiedLabel ?? bt('accessibility.copied'));
|
|
@@ -91,25 +95,11 @@
|
|
|
91
95
|
// visible text be the name (WCAG 2.5.3), keeping any consumer aria-label.
|
|
92
96
|
const ariaLabel = $derived(label ? ariaLabelProp : (ariaLabelProp ?? copyText));
|
|
93
97
|
|
|
94
|
-
function scheduleReset() {
|
|
95
|
-
clearTimeout(timer);
|
|
96
|
-
if (timeout > 0) timer = setTimeout(() => (state = 'idle'), timeout);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
98
|
async function handleCopy() {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
state = 'copied';
|
|
104
|
-
onCopy?.(value);
|
|
105
|
-
} catch (error) {
|
|
106
|
-
state = 'error';
|
|
107
|
-
onError?.(error);
|
|
108
|
-
}
|
|
109
|
-
scheduleReset();
|
|
99
|
+
const result = await copyState.copy(value);
|
|
100
|
+
if (result.ok) onCopy?.(value);
|
|
101
|
+
else onError?.(result.error);
|
|
110
102
|
}
|
|
111
|
-
|
|
112
|
-
$effect(() => () => clearTimeout(timer));
|
|
113
103
|
</script>
|
|
114
104
|
|
|
115
105
|
<span class="contents">
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { type SlotNames, type VariantProps } from '../../utils/variants.js';
|
|
2
2
|
export declare const copyButtonVariants: ((props?: {
|
|
3
3
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xs" | undefined;
|
|
4
|
-
state?: "
|
|
4
|
+
state?: "copied" | "error" | "idle" | undefined;
|
|
5
5
|
} | undefined) => {
|
|
6
6
|
base: (props?: ({
|
|
7
7
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xs" | undefined;
|
|
8
|
-
state?: "
|
|
8
|
+
state?: "copied" | "error" | "idle" | undefined;
|
|
9
9
|
} & {
|
|
10
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
11
|
}) | undefined) => string;
|
|
12
12
|
icon: (props?: ({
|
|
13
13
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xs" | undefined;
|
|
14
|
-
state?: "
|
|
14
|
+
state?: "copied" | "error" | "idle" | undefined;
|
|
15
15
|
} & {
|
|
16
16
|
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;
|
|
17
17
|
}) | undefined) => string;
|
|
18
18
|
label: (props?: ({
|
|
19
19
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xs" | undefined;
|
|
20
|
-
state?: "
|
|
20
|
+
state?: "copied" | "error" | "idle" | undefined;
|
|
21
21
|
} & {
|
|
22
22
|
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;
|
|
23
23
|
}) | undefined) => string;
|
|
@@ -120,8 +120,13 @@ export const fileUploadVariants = tv({
|
|
|
120
120
|
},
|
|
121
121
|
disabled: {
|
|
122
122
|
true: {
|
|
123
|
+
// No `hover:` neutralisers here: `pointer-events-none` on the root
|
|
124
|
+
// already makes the dropzone unhoverable, so any hover class on it is
|
|
125
|
+
// unreachable. The two that used to sit here (`hover:border-border-default
|
|
126
|
+
// hover:bg-surface-base`) were dead, and `bg-surface-base` would have
|
|
127
|
+
// *lightened* a disabled dropzone resting on an elevated card.
|
|
123
128
|
root: 'opacity-50 pointer-events-none',
|
|
124
|
-
dropzone: 'cursor-not-allowed
|
|
129
|
+
dropzone: 'cursor-not-allowed'
|
|
125
130
|
},
|
|
126
131
|
false: {}
|
|
127
132
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { untrack } from 'svelte';
|
|
3
3
|
import { useBlocksI18n } from '../..';
|
|
4
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
4
5
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
5
6
|
import { getTierContext } from '../../utils';
|
|
6
7
|
import type { PinInputProps } from './index';
|
|
@@ -299,26 +300,17 @@
|
|
|
299
300
|
{/each}
|
|
300
301
|
</div>
|
|
301
302
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
<div
|
|
314
|
-
id={messageId}
|
|
315
|
-
class={unstyled
|
|
316
|
-
? (slotClasses?.message ?? '')
|
|
317
|
-
: styles.message({ class: slotClasses?.message })}
|
|
318
|
-
>
|
|
319
|
-
{helper}
|
|
320
|
-
</div>
|
|
321
|
-
{/if}
|
|
303
|
+
<!-- Both arms share one id: `describedBy` points at `messageId` regardless of
|
|
304
|
+
which arm renders, since only one ever does. -->
|
|
305
|
+
<CoreFieldMessage
|
|
306
|
+
{error}
|
|
307
|
+
{helper}
|
|
308
|
+
errorId={messageId}
|
|
309
|
+
helperId={messageId}
|
|
310
|
+
class={unstyled
|
|
311
|
+
? (slotClasses?.message ?? '')
|
|
312
|
+
: styles.message({ class: slotClasses?.message })}
|
|
313
|
+
/>
|
|
322
314
|
|
|
323
315
|
{#if name}
|
|
324
316
|
<input type="hidden" {name} {value} />
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { untrack } from 'svelte';
|
|
3
3
|
import { useBlocksI18n } from '../..';
|
|
4
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
4
5
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
5
6
|
import { getTierContext } from '../../utils';
|
|
6
7
|
import { resolveIcon } from '../../icons';
|
|
@@ -509,26 +510,17 @@
|
|
|
509
510
|
{/if}
|
|
510
511
|
</div>
|
|
511
512
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
<div
|
|
524
|
-
id={messageId}
|
|
525
|
-
class={unstyled
|
|
526
|
-
? (slotClasses?.message ?? '')
|
|
527
|
-
: styles.message({ class: slotClasses?.message })}
|
|
528
|
-
>
|
|
529
|
-
{helper}
|
|
530
|
-
</div>
|
|
531
|
-
{/if}
|
|
513
|
+
<!-- Both arms share one id: `describedBy` points at `messageId` regardless of
|
|
514
|
+
which arm renders, since only one ever does. -->
|
|
515
|
+
<CoreFieldMessage
|
|
516
|
+
{error}
|
|
517
|
+
{helper}
|
|
518
|
+
errorId={messageId}
|
|
519
|
+
helperId={messageId}
|
|
520
|
+
class={unstyled
|
|
521
|
+
? (slotClasses?.message ?? '')
|
|
522
|
+
: styles.message({ class: slotClasses?.message })}
|
|
523
|
+
/>
|
|
532
524
|
|
|
533
525
|
{#if name}
|
|
534
526
|
<input type="hidden" {name} value={value ?? ''} />
|