@juspay/svelte-ui-components 2.134.1 → 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.
@@ -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 ChatToolStatus from '../ChatToolStatus/ChatToolStatus.svelte';
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"><ChatToolStatus label={toolStatus.label} /></div>
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>
@@ -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` overrides that entirely.
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 !== 'bare' && (hasTraceMode || (typeof detail === 'string' && detail.length > 0))
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. Passing `busy` takes direct control of the shimmer
51
- // in every shape, including `bare`.
52
- const labelIsBusy = $derived(busy ?? !isExpandable);
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. It never becomes expandable.
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` variant.
43
+ * shape). No effect on the `bare` or `chip` variants.
40
44
  */
41
45
  showElapsed?: boolean;
42
46
  onToggle?: () => void;