@juspay/svelte-ui-components 2.134.0 → 2.135.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/Chat/Chat.svelte +26 -2
- package/dist/ChipInput/ChipInput.svelte +2 -0
- package/dist/ChipInput/properties.d.ts +6 -0
- package/dist/Input/Input.svelte +29 -3
- package/dist/ThinkingIndicator/ThinkingIndicator.svelte +93 -5
- package/dist/ThinkingIndicator/properties.d.ts +7 -3
- package/dist-wc/index.js +2010 -1989
- package/package.json +1 -1
package/dist/Chat/Chat.svelte
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import ChatMessageList from '../ChatMessageList/ChatMessageList.svelte';
|
|
4
4
|
import ChatComposer from '../ChatComposer/ChatComposer.svelte';
|
|
5
5
|
import ChatSuggestions from '../ChatSuggestions/ChatSuggestions.svelte';
|
|
6
|
-
import
|
|
6
|
+
import ThinkingIndicator from '../ThinkingIndicator/ThinkingIndicator.svelte';
|
|
7
7
|
import type { ChatProperties } from './properties';
|
|
8
8
|
|
|
9
9
|
let {
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
<ChatSuggestions items={suggestions} {disabled} onselect={handleSuggestion} />
|
|
107
107
|
{/if}
|
|
108
108
|
{#if toolStatus !== null}
|
|
109
|
-
<div class="tool-status"><
|
|
109
|
+
<div class="tool-status"><ThinkingIndicator label={toolStatus.label} variant="chip" /></div>
|
|
110
110
|
{/if}
|
|
111
111
|
<ChatComposer
|
|
112
112
|
bind:value
|
|
@@ -156,5 +156,29 @@
|
|
|
156
156
|
.tool-status {
|
|
157
157
|
display: flex;
|
|
158
158
|
justify-content: var(--chat-tool-status-justify, center);
|
|
159
|
+
/* This row is ThinkingIndicator's chip variant internally now, not the standalone
|
|
160
|
+
ChatToolStatus component -- but its public theming contract stays
|
|
161
|
+
--chat-tool-status-*, unchanged, so an existing consumer's overrides keep working
|
|
162
|
+
exactly as before. Defaults below match ChatToolStatus's own byte for byte. */
|
|
163
|
+
--thinking-indicator-chip-gap: var(--chat-tool-status-gap, 8px);
|
|
164
|
+
--thinking-indicator-chip-padding: var(--chat-tool-status-padding, 8px 14px);
|
|
165
|
+
--thinking-indicator-chip-background: var(--chat-tool-status-background, #ffffff);
|
|
166
|
+
--thinking-indicator-chip-border: var(--chat-tool-status-border, 1px solid #e4e4e7);
|
|
167
|
+
--thinking-indicator-chip-border-radius: var(--chat-tool-status-border-radius, 999px);
|
|
168
|
+
--thinking-indicator-chip-box-shadow: var(
|
|
169
|
+
--chat-tool-status-box-shadow,
|
|
170
|
+
0 6px 20px rgba(0, 0, 0, 0.08)
|
|
171
|
+
);
|
|
172
|
+
--thinking-indicator-chip-max-width: var(--chat-tool-status-max-width, 100%);
|
|
173
|
+
--thinking-indicator-chip-color: var(--chat-tool-status-color, #52525b);
|
|
174
|
+
--thinking-indicator-chip-font-size: var(--chat-tool-status-font-size, 0.85rem);
|
|
175
|
+
--thinking-indicator-chip-font-weight: var(--chat-tool-status-font-weight, 500);
|
|
176
|
+
--thinking-indicator-chip-icon-color: var(--chat-tool-status-indicator-color, currentColor);
|
|
177
|
+
--thinking-indicator-chip-spinner-color: var(--chat-tool-status-spinner-color, currentColor);
|
|
178
|
+
--thinking-indicator-chip-spinner-color-end: var(
|
|
179
|
+
--chat-tool-status-spinner-color-end,
|
|
180
|
+
transparent
|
|
181
|
+
);
|
|
182
|
+
--thinking-indicator-chip-spinner-size: var(--chat-tool-status-spinner-size, 14px);
|
|
159
183
|
}
|
|
160
184
|
</style>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
let {
|
|
7
7
|
values = $bindable([]),
|
|
8
|
+
ariaLabel,
|
|
8
9
|
placeholder = 'Add value…',
|
|
9
10
|
disabled = false,
|
|
10
11
|
testId,
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
{placeholder}
|
|
67
68
|
dataType="text"
|
|
68
69
|
name=""
|
|
70
|
+
{ariaLabel}
|
|
69
71
|
autoComplete="off"
|
|
70
72
|
actionInput={false}
|
|
71
73
|
disable={disabled}
|
|
@@ -9,6 +9,12 @@ export type MandatoryChipInputProperties = {
|
|
|
9
9
|
values: string[];
|
|
10
10
|
};
|
|
11
11
|
export type OptionalChipInputProperties = {
|
|
12
|
+
/**
|
|
13
|
+
* Names the draft field for assistive technology. ChipInput renders no visible label of its
|
|
14
|
+
* own, so without this the control reaches the accessibility tree unnamed however the caption
|
|
15
|
+
* beside it reads on screen. Pass the same words as that caption.
|
|
16
|
+
*/
|
|
17
|
+
ariaLabel?: string;
|
|
12
18
|
placeholder?: string;
|
|
13
19
|
disabled?: boolean;
|
|
14
20
|
testId?: string;
|
package/dist/Input/Input.svelte
CHANGED
|
@@ -122,6 +122,26 @@
|
|
|
122
122
|
// forceError lets consumers drive the error border from server/runtime validation,
|
|
123
123
|
// independent of validationPattern.
|
|
124
124
|
const showError = $derived(showErrorMessage || forceError);
|
|
125
|
+
// The error text has to be reachable FROM the field it describes and announced when it
|
|
126
|
+
// appears. Without both, a screen-reader user submits, hears nothing, and is left on a form
|
|
127
|
+
// that did not move -- the message is on screen and absent from the accessibility tree.
|
|
128
|
+
const errorMessageId = $derived(`${effectiveId}-error`);
|
|
129
|
+
// `onErrorMessage` is `string | null`, so null has to be excluded explicitly: `null !== ''`
|
|
130
|
+
// is true, which would describe the field by an alert element carrying no message.
|
|
131
|
+
const isShowingError = $derived(
|
|
132
|
+
onErrorMessage != null && onErrorMessage !== '' && showError && !actionInput
|
|
133
|
+
);
|
|
134
|
+
const infoMessageId = $derived(`${effectiveId}-info`);
|
|
135
|
+
const isShowingInfo = $derived(infoMessage !== '' && !actionInput);
|
|
136
|
+
// Helper text is part of the field's description, not decoration: a consumer's `infoMessage`
|
|
137
|
+
// ("Enter a percentage between 1 and 100") is exactly the guidance a screen-reader user needs
|
|
138
|
+
// BEFORE they trip an error. Reference both, in reading order, so the field is described by
|
|
139
|
+
// everything visibly attached to it rather than only by its failure.
|
|
140
|
+
const describedBy = $derived(
|
|
141
|
+
[isShowingError ? errorMessageId : null, isShowingInfo ? infoMessageId : null]
|
|
142
|
+
.filter(Boolean)
|
|
143
|
+
.join(' ')
|
|
144
|
+
);
|
|
125
145
|
const hasLeftIcon = $derived(typeof leftIcon === 'function');
|
|
126
146
|
const hasRightIcon = $derived(typeof rightIcon === 'function');
|
|
127
147
|
|
|
@@ -301,6 +321,8 @@
|
|
|
301
321
|
aria-controls={ariaControls}
|
|
302
322
|
aria-activedescendant={ariaActivedescendant}
|
|
303
323
|
aria-required={mandatory || null}
|
|
324
|
+
aria-invalid={showError ? 'true' : null}
|
|
325
|
+
aria-describedby={describedBy || null}
|
|
304
326
|
required={mandatory || null}
|
|
305
327
|
onfocus={onFocus}
|
|
306
328
|
onfocusout={_onFocusOut}
|
|
@@ -337,6 +359,8 @@
|
|
|
337
359
|
aria-controls={ariaControls}
|
|
338
360
|
aria-activedescendant={ariaActivedescendant}
|
|
339
361
|
aria-required={mandatory || null}
|
|
362
|
+
aria-invalid={showError ? 'true' : null}
|
|
363
|
+
aria-describedby={describedBy || null}
|
|
340
364
|
required={mandatory || null}
|
|
341
365
|
onfocus={onFocus}
|
|
342
366
|
onfocusout={_onFocusOut}
|
|
@@ -399,8 +423,10 @@
|
|
|
399
423
|
{@render fieldElement()}
|
|
400
424
|
{/if}
|
|
401
425
|
|
|
402
|
-
{#if
|
|
426
|
+
{#if isShowingError}
|
|
403
427
|
<div
|
|
428
|
+
id={errorMessageId}
|
|
429
|
+
role="alert"
|
|
404
430
|
class="error-message"
|
|
405
431
|
data-pw={typeof testId === 'string' && testId.length > 0 ? `${testId}-error-message` : null}
|
|
406
432
|
testID={typeof testId === 'string' && testId.length > 0 ? `${testId}-error-message` : null}
|
|
@@ -408,8 +434,8 @@
|
|
|
408
434
|
{onErrorMessage}
|
|
409
435
|
</div>
|
|
410
436
|
{/if}
|
|
411
|
-
{#if
|
|
412
|
-
<div class="info-message">
|
|
437
|
+
{#if isShowingInfo}
|
|
438
|
+
<div id={infoMessageId} class="info-message">
|
|
413
439
|
{infoMessage}
|
|
414
440
|
</div>
|
|
415
441
|
{/if}
|
|
@@ -40,16 +40,20 @@
|
|
|
40
40
|
|
|
41
41
|
// A detail string or a trace is what makes the indicator expandable. Without either
|
|
42
42
|
// there is nothing to reveal, so it renders as a plain live status line instead of a
|
|
43
|
-
// disclosure control. `bare`
|
|
43
|
+
// disclosure control. `bare` and `chip` both override that entirely — neither has
|
|
44
|
+
// room (or a documented reason) to expand.
|
|
44
45
|
const isExpandable = $derived(
|
|
45
|
-
variant
|
|
46
|
+
variant === 'default' && (hasTraceMode || (typeof detail === 'string' && detail.length > 0))
|
|
46
47
|
);
|
|
47
48
|
|
|
48
49
|
// Backward-compatible shimmer rule: without an explicit `busy`, the expandable
|
|
49
50
|
// summary holds still (settled) and every other shape shimmers (live) — exactly
|
|
50
|
-
// today's released behaviour.
|
|
51
|
-
// in
|
|
52
|
-
|
|
51
|
+
// today's released behaviour. `chip` is the one exception, defaulting to static:
|
|
52
|
+
// it exists to be a drop-in for ChatToolStatus, which never shimmered, so a
|
|
53
|
+
// caller porting that usage 1:1 shouldn't have to also learn `busy={false}` just
|
|
54
|
+
// to avoid an unexpected shimmer. Passing `busy` takes direct control of the
|
|
55
|
+
// shimmer in every shape, including `bare` and `chip`.
|
|
56
|
+
const labelIsBusy = $derived(busy ?? (variant === 'chip' ? false : !isExpandable));
|
|
53
57
|
|
|
54
58
|
// Set once a person clicks the disclosure open/closed — from then on the automatic
|
|
55
59
|
// busy-driven machine below leaves `expanded` alone for the rest of this mount.
|
|
@@ -406,6 +410,21 @@
|
|
|
406
410
|
>{label}</span
|
|
407
411
|
>{:else}{label}{/if}</span
|
|
408
412
|
>
|
|
413
|
+
{:else if variant === 'chip'}
|
|
414
|
+
<div
|
|
415
|
+
class="thinking-indicator-chip {classes ?? ''}"
|
|
416
|
+
aria-live="polite"
|
|
417
|
+
aria-atomic="true"
|
|
418
|
+
data-pw={typeof testId === 'string' ? testId : null}
|
|
419
|
+
testID={typeof testId === 'string' ? testId : null}
|
|
420
|
+
>
|
|
421
|
+
<span class="chip-icon">
|
|
422
|
+
{#if avatar}{@render avatar()}{:else}<Loader />{/if}
|
|
423
|
+
</span>
|
|
424
|
+
<span class="chip-label" class:static-label={!labelIsBusy} data-pw={labelTestId ?? null}
|
|
425
|
+
>{label}</span
|
|
426
|
+
>
|
|
427
|
+
</div>
|
|
409
428
|
{:else}
|
|
410
429
|
<div
|
|
411
430
|
class="thinking-indicator status-host {classes ?? ''}"
|
|
@@ -558,6 +577,69 @@
|
|
|
558
577
|
-webkit-text-fill-color: var(--thinking-indicator-label-color, #858585);
|
|
559
578
|
}
|
|
560
579
|
|
|
580
|
+
/* ---- chip variant: a self-contained floating pill (no ancestor supplies
|
|
581
|
+
background/layout, unlike bare) — deliberately not `width: 100%`/box-sizing
|
|
582
|
+
from `.thinking-indicator`, since a pill hugs its content. */
|
|
583
|
+
.thinking-indicator-chip {
|
|
584
|
+
box-sizing: border-box;
|
|
585
|
+
display: inline-flex;
|
|
586
|
+
align-items: center;
|
|
587
|
+
gap: var(--thinking-indicator-chip-gap, 8px);
|
|
588
|
+
width: fit-content;
|
|
589
|
+
padding: var(--thinking-indicator-chip-padding, 8px 14px);
|
|
590
|
+
background: var(--thinking-indicator-chip-background, #ffffff);
|
|
591
|
+
border: var(--thinking-indicator-chip-border, 1px solid #e4e4e7);
|
|
592
|
+
border-radius: var(--thinking-indicator-chip-border-radius, 999px);
|
|
593
|
+
box-shadow: var(--thinking-indicator-chip-box-shadow, 0 6px 20px rgba(0, 0, 0, 0.08));
|
|
594
|
+
max-width: var(--thinking-indicator-chip-max-width, 100%);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.chip-icon {
|
|
598
|
+
display: inline-flex;
|
|
599
|
+
align-items: center;
|
|
600
|
+
flex-shrink: 0;
|
|
601
|
+
color: var(--thinking-indicator-chip-icon-color, currentColor);
|
|
602
|
+
--loader-foreground: var(--thinking-indicator-chip-spinner-color, currentColor);
|
|
603
|
+
--loader-foreground-end: var(--thinking-indicator-chip-spinner-color-end, transparent);
|
|
604
|
+
--loader-width: var(--thinking-indicator-chip-spinner-size, 14px);
|
|
605
|
+
--loader-height: var(--thinking-indicator-chip-spinner-size, 14px);
|
|
606
|
+
--loader-before-width: 7px;
|
|
607
|
+
--loader-before-height: 7px;
|
|
608
|
+
--loader-after-width: 11px;
|
|
609
|
+
--loader-after-height: 11px;
|
|
610
|
+
--loader-background: var(--thinking-indicator-chip-background, #ffffff);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.chip-label {
|
|
614
|
+
flex: 0 1 auto;
|
|
615
|
+
min-width: 0;
|
|
616
|
+
white-space: nowrap;
|
|
617
|
+
overflow: hidden;
|
|
618
|
+
text-overflow: ellipsis;
|
|
619
|
+
font-size: var(--thinking-indicator-chip-font-size, 0.85rem);
|
|
620
|
+
font-weight: var(--thinking-indicator-chip-font-weight, 500);
|
|
621
|
+
color: var(--thinking-indicator-chip-color, #52525b);
|
|
622
|
+
background: var(
|
|
623
|
+
--thinking-indicator-chip-shimmer-gradient,
|
|
624
|
+
linear-gradient(90deg, #52525b 0%, #a0a0a0 50%, #52525b 100%)
|
|
625
|
+
);
|
|
626
|
+
background-size: 200% 100%;
|
|
627
|
+
background-clip: text;
|
|
628
|
+
-webkit-text-fill-color: transparent;
|
|
629
|
+
animation: thinking-indicator-shimmer var(--thinking-indicator-chip-shimmer-duration, 2s) linear
|
|
630
|
+
infinite;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/* Chip defaults to a static label (unlike the default/bare variants) since it
|
|
634
|
+
mirrors ChatToolStatus, which never shimmered — pass `busy` explicitly to
|
|
635
|
+
opt in. Higher specificity than the generic `.static-label` rule above, so
|
|
636
|
+
it correctly overrides with the chip's own color token, not the default
|
|
637
|
+
variant's. */
|
|
638
|
+
.chip-label.static-label {
|
|
639
|
+
animation: none;
|
|
640
|
+
-webkit-text-fill-color: var(--thinking-indicator-chip-color, #52525b);
|
|
641
|
+
}
|
|
642
|
+
|
|
561
643
|
.arrow {
|
|
562
644
|
display: inline-flex;
|
|
563
645
|
align-items: center;
|
|
@@ -784,6 +866,7 @@
|
|
|
784
866
|
|
|
785
867
|
@media (prefers-reduced-motion: reduce) {
|
|
786
868
|
.status-label,
|
|
869
|
+
.chip-label,
|
|
787
870
|
.trace-row,
|
|
788
871
|
.trace-more {
|
|
789
872
|
animation-duration: 0.001s;
|
|
@@ -799,5 +882,10 @@
|
|
|
799
882
|
animation: none;
|
|
800
883
|
-webkit-text-fill-color: var(--thinking-indicator-label-color, #858585);
|
|
801
884
|
}
|
|
885
|
+
|
|
886
|
+
.chip-label {
|
|
887
|
+
animation: none;
|
|
888
|
+
-webkit-text-fill-color: var(--thinking-indicator-chip-color, #52525b);
|
|
889
|
+
}
|
|
802
890
|
}
|
|
803
891
|
</style>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
-
export type ThinkingIndicatorVariant = 'default' | 'bare';
|
|
2
|
+
export type ThinkingIndicatorVariant = 'default' | 'bare' | 'chip';
|
|
3
3
|
export type ThinkingIndicatorKind = 'steps' | 'reasoning' | 'search' | 'coding';
|
|
4
4
|
export type ThinkingIndicatorTraceRow = {
|
|
5
5
|
/** The step, sentence, source title, or file action. */
|
|
@@ -29,14 +29,18 @@ export type OptionalThinkingIndicatorProperties = {
|
|
|
29
29
|
expanded?: boolean;
|
|
30
30
|
/**
|
|
31
31
|
* `bare` renders only the shimmering label — for chat bubbles where the surrounding
|
|
32
|
-
* UI already supplies the avatar and layout.
|
|
32
|
+
* UI already supplies the avatar and layout. `chip` renders a self-contained pill
|
|
33
|
+
* (bordered, shadowed, its own background) for a live status floating above other
|
|
34
|
+
* content, e.g. a tool-call indicator above a composer — pass `busy={false}` for a
|
|
35
|
+
* static (non-shimmering) label, matching a plain status badge. Neither `bare` nor
|
|
36
|
+
* `chip` ever becomes expandable.
|
|
33
37
|
*/
|
|
34
38
|
variant?: ThinkingIndicatorVariant;
|
|
35
39
|
/**
|
|
36
40
|
* Renders an elapsed `Ns` counter while the label is live. Starts at 0 when a busy
|
|
37
41
|
* phase begins, ticks every second, and freezes at its final value once the label
|
|
38
42
|
* settles (driven by `busy` when set, otherwise by the legacy status-line/detail
|
|
39
|
-
* shape). No effect on the `bare`
|
|
43
|
+
* shape). No effect on the `bare` or `chip` variants.
|
|
40
44
|
*/
|
|
41
45
|
showElapsed?: boolean;
|
|
42
46
|
onToggle?: () => void;
|