@juspay/svelte-ui-components 2.130.1 → 2.132.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/Status/Status.svelte +14 -5
- package/dist/Status/properties.d.ts +23 -0
- package/dist/TaskList/TaskList.svelte +268 -0
- package/dist/TaskList/TaskList.svelte.d.ts +4 -0
- package/dist/TaskList/properties.d.ts +24 -0
- package/dist/TaskList/properties.js +1 -0
- package/dist/ThinkingIndicator/ThinkingIndicator.svelte +621 -35
- package/dist/ThinkingIndicator/ThinkingIndicator.svelte.d.ts +1 -1
- package/dist/ThinkingIndicator/properties.d.ts +63 -3
- package/dist/ToolCallLog/ToolCallLog.svelte +418 -0
- package/dist/ToolCallLog/ToolCallLog.svelte.d.ts +4 -0
- package/dist/ToolCallLog/properties.d.ts +27 -0
- package/dist/ToolCallLog/properties.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/soundKit/properties.d.ts +29 -0
- package/dist/soundKit/properties.js +1 -0
- package/dist/soundKit/soundKit.d.ts +2 -0
- package/dist/soundKit/soundKit.js +284 -0
- package/package.json +1 -1
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
classes,
|
|
12
12
|
onbuttonClick,
|
|
13
13
|
icon,
|
|
14
|
+
descriptionSnippet,
|
|
15
|
+
children,
|
|
14
16
|
testId
|
|
15
17
|
}: StatusProperties = $props();
|
|
16
18
|
</script>
|
|
@@ -30,12 +32,19 @@
|
|
|
30
32
|
</div>
|
|
31
33
|
<div class="status-text">{statusText}</div>
|
|
32
34
|
<div class="status-description">
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
{#if typeof descriptionSnippet === 'function'}
|
|
36
|
+
{@render descriptionSnippet()}
|
|
37
|
+
{:else}
|
|
38
|
+
<!-- eslint-disable-next-line -->
|
|
39
|
+
{@html statusDescription}
|
|
40
|
+
{/if}
|
|
35
41
|
</div>
|
|
36
42
|
{#if typeof buttonProperties === 'object'}
|
|
37
43
|
<Button {...buttonProperties} onclick={onbuttonClick} />
|
|
38
44
|
{/if}
|
|
45
|
+
{#if typeof children === 'function'}
|
|
46
|
+
{@render children()}
|
|
47
|
+
{/if}
|
|
39
48
|
</div>
|
|
40
49
|
</div>
|
|
41
50
|
|
|
@@ -75,9 +84,9 @@
|
|
|
75
84
|
}
|
|
76
85
|
@supports ((-webkit-backdrop-filter: none) or (backdrop-filter: none)) {
|
|
77
86
|
.order-status {
|
|
78
|
-
background-color: rgba(255, 255, 255, 0.6);
|
|
79
|
-
-webkit-backdrop-filter: blur(60px);
|
|
80
|
-
backdrop-filter: blur(60px);
|
|
87
|
+
background-color: var(--status-panel-background, rgba(255, 255, 255, 0.6));
|
|
88
|
+
-webkit-backdrop-filter: var(--status-panel-backdrop-filter, blur(60px));
|
|
89
|
+
backdrop-filter: var(--status-panel-backdrop-filter, blur(60px));
|
|
81
90
|
}
|
|
82
91
|
}
|
|
83
92
|
</style>
|
|
@@ -12,6 +12,29 @@ export type StatusProperties = StatusEventProperties & {
|
|
|
12
12
|
* priority over `statusIcon` when provided.
|
|
13
13
|
*/
|
|
14
14
|
icon?: Snippet;
|
|
15
|
+
/**
|
|
16
|
+
* Optional snippet that replaces the `statusDescription` string at render
|
|
17
|
+
* time. When provided, `statusDescription` is not rendered — only the snippet
|
|
18
|
+
* is. Mirrors `EmptyState`'s `descriptionSnippet`.
|
|
19
|
+
*
|
|
20
|
+
* `statusDescription` is interpolated with `{@html}`, which is what a caller
|
|
21
|
+
* supplying its own trusted markup wants, but is the wrong tool for a message
|
|
22
|
+
* that originates from an API, a user, or any other source the caller does not
|
|
23
|
+
* control. There was previously no way to render such a message as text. Use
|
|
24
|
+
* this snippet for that: `{#snippet descriptionSnippet()}{message}{/snippet}`
|
|
25
|
+
* escapes it the way ordinary Svelte interpolation does.
|
|
26
|
+
*/
|
|
27
|
+
descriptionSnippet?: Snippet;
|
|
28
|
+
/**
|
|
29
|
+
* Action area rendered below the description, alongside the optional
|
|
30
|
+
* `buttonProperties` button. Mirrors `EmptyState`'s `children`.
|
|
31
|
+
*
|
|
32
|
+
* `descriptionSnippet` sits inside `.status-description`, which carries the
|
|
33
|
+
* component's own horizontal padding and bottom margin. Content that is not
|
|
34
|
+
* part of the description — a button, a link, a countdown — belongs here
|
|
35
|
+
* instead, outside that box, where `buttonProperties` already renders.
|
|
36
|
+
*/
|
|
37
|
+
children?: Snippet;
|
|
15
38
|
testId?: string;
|
|
16
39
|
};
|
|
17
40
|
export type StatusEventProperties = {
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Action } from 'svelte/action';
|
|
3
|
+
import Loader from '../Loader/Loader.svelte';
|
|
4
|
+
import Button from '../Button/Button.svelte';
|
|
5
|
+
import type { TaskListProperties } from './properties';
|
|
6
|
+
|
|
7
|
+
let { rows, onretry, testId, classes }: TaskListProperties = $props();
|
|
8
|
+
|
|
9
|
+
// Rows appended in one update stagger relative to the batch, not the list start —
|
|
10
|
+
// mirrors ThinkingTrace's growthWatcher so a host that streams rows in gets the
|
|
11
|
+
// same "only the new ones animate in" behaviour.
|
|
12
|
+
let staggerBase = $state(0);
|
|
13
|
+
|
|
14
|
+
const growthWatcher: Action<HTMLElement, number> = (_node, initialCount) => {
|
|
15
|
+
let previousCount = initialCount;
|
|
16
|
+
return {
|
|
17
|
+
update(count: number): void {
|
|
18
|
+
if (count > previousCount) {
|
|
19
|
+
staggerBase = previousCount;
|
|
20
|
+
}
|
|
21
|
+
previousCount = count;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const rowDelay = (index: number): string => {
|
|
27
|
+
return `${Math.max(0, index - staggerBase) * 120}ms`;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const handleRetry = (index: number): void => {
|
|
31
|
+
onretry?.(index);
|
|
32
|
+
};
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div
|
|
36
|
+
class="task-list {classes ?? ''}"
|
|
37
|
+
use:growthWatcher={rows.length}
|
|
38
|
+
data-pw={typeof testId === 'string' ? testId : null}
|
|
39
|
+
testID={typeof testId === 'string' ? testId : null}
|
|
40
|
+
>
|
|
41
|
+
{#each rows as row, index (index)}
|
|
42
|
+
<div
|
|
43
|
+
class="task-row"
|
|
44
|
+
class:pending={row.status === 'pending'}
|
|
45
|
+
style:animation-delay={rowDelay(index)}
|
|
46
|
+
data-pw={typeof testId === 'string' ? `${testId}-row-${index}` : null}
|
|
47
|
+
testID={typeof testId === 'string' ? `${testId}-row-${index}` : null}
|
|
48
|
+
>
|
|
49
|
+
<span class="row-glyph">
|
|
50
|
+
{#key row.status}
|
|
51
|
+
<span class="glyph-inner" data-status={row.status} aria-hidden="true">
|
|
52
|
+
{#if row.status === 'pending'}
|
|
53
|
+
<span class="glyph-dot"></span>
|
|
54
|
+
{:else if row.status === 'running'}
|
|
55
|
+
<span class="glyph-spinner">
|
|
56
|
+
<Loader />
|
|
57
|
+
</span>
|
|
58
|
+
{:else if row.status === 'done'}
|
|
59
|
+
<span class="glyph-check">
|
|
60
|
+
<svg
|
|
61
|
+
viewBox="0 0 24 24"
|
|
62
|
+
fill="none"
|
|
63
|
+
stroke="currentColor"
|
|
64
|
+
stroke-width="2.4"
|
|
65
|
+
stroke-linecap="round"
|
|
66
|
+
stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></svg
|
|
67
|
+
>
|
|
68
|
+
</span>
|
|
69
|
+
{:else if row.status === 'failed'}
|
|
70
|
+
<span class="glyph-x">
|
|
71
|
+
<svg
|
|
72
|
+
viewBox="0 0 24 24"
|
|
73
|
+
fill="none"
|
|
74
|
+
stroke="currentColor"
|
|
75
|
+
stroke-width="2.4"
|
|
76
|
+
stroke-linecap="round"
|
|
77
|
+
stroke-linejoin="round"><path d="M6 6l12 12M18 6 6 18" /></svg
|
|
78
|
+
>
|
|
79
|
+
</span>
|
|
80
|
+
{/if}
|
|
81
|
+
</span>
|
|
82
|
+
{/key}
|
|
83
|
+
</span>
|
|
84
|
+
|
|
85
|
+
<span class="row-text">
|
|
86
|
+
<span class="row-label">{row.label}</span>
|
|
87
|
+
{#if typeof row.secondary === 'string' && row.secondary.length > 0}
|
|
88
|
+
<span class="row-secondary" class:mono={row.mono}>{row.secondary}</span>
|
|
89
|
+
{/if}
|
|
90
|
+
</span>
|
|
91
|
+
|
|
92
|
+
{#if row.status === 'failed' && typeof row.retryLabel === 'string' && row.retryLabel.length > 0}
|
|
93
|
+
<div class="row-retry">
|
|
94
|
+
<Button
|
|
95
|
+
text={row.retryLabel}
|
|
96
|
+
size="sm"
|
|
97
|
+
onclick={() => handleRetry(index)}
|
|
98
|
+
{...typeof testId === 'string' ? { testId: `${testId}-row-${index}-retry` } : {}}
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
{/if}
|
|
102
|
+
</div>
|
|
103
|
+
{/each}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<style>
|
|
107
|
+
@keyframes task-list-fade-up {
|
|
108
|
+
from {
|
|
109
|
+
opacity: 0;
|
|
110
|
+
transform: translateY(9px);
|
|
111
|
+
}
|
|
112
|
+
to {
|
|
113
|
+
opacity: 1;
|
|
114
|
+
transform: none;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
@keyframes task-list-glyph-fade {
|
|
118
|
+
from {
|
|
119
|
+
opacity: 0;
|
|
120
|
+
}
|
|
121
|
+
to {
|
|
122
|
+
opacity: 1;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
@keyframes task-list-check-pop {
|
|
126
|
+
from {
|
|
127
|
+
opacity: 0;
|
|
128
|
+
transform: scale(0.5);
|
|
129
|
+
}
|
|
130
|
+
to {
|
|
131
|
+
opacity: 1;
|
|
132
|
+
transform: scale(1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.task-list {
|
|
137
|
+
display: flex;
|
|
138
|
+
flex-direction: column;
|
|
139
|
+
gap: var(--task-list-row-gap, 10px);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.task-row {
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: baseline;
|
|
145
|
+
gap: var(--task-list-row-inline-gap, 10px);
|
|
146
|
+
animation: task-list-fade-up 320ms var(--task-list-ease, cubic-bezier(0.23, 1, 0.32, 1)) both;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.row-glyph {
|
|
150
|
+
display: inline-flex;
|
|
151
|
+
align-self: center;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: center;
|
|
154
|
+
width: var(--task-list-glyph-size, 16px);
|
|
155
|
+
height: var(--task-list-glyph-size, 16px);
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.glyph-inner {
|
|
160
|
+
display: inline-flex;
|
|
161
|
+
align-items: center;
|
|
162
|
+
justify-content: center;
|
|
163
|
+
animation: task-list-glyph-fade 150ms ease both;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.glyph-dot {
|
|
167
|
+
width: 6px;
|
|
168
|
+
height: 6px;
|
|
169
|
+
border-radius: 50%;
|
|
170
|
+
background: var(--task-list-dot-color, #9a9a9a);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Loader draws its own ring via a rotating gradient rather than a bordered arc, so the old
|
|
174
|
+
track/spinner two-tone maps onto the gradient's start/end stops: --loader-foreground is the
|
|
175
|
+
bright leading edge, --loader-foreground-end the dimmer trailing one. The size vars are
|
|
176
|
+
calc()'d off a single token so before/after stay proportional if a consumer overrides it. */
|
|
177
|
+
.glyph-spinner {
|
|
178
|
+
display: inline-flex;
|
|
179
|
+
--loader-foreground: var(--task-list-spinner-color, #6b6b6b);
|
|
180
|
+
--loader-foreground-end: var(--task-list-spinner-track-color, #dcdcdc);
|
|
181
|
+
--loader-width: var(--task-list-spinner-size, 11px);
|
|
182
|
+
--loader-height: var(--task-list-spinner-size, 11px);
|
|
183
|
+
--loader-before-width: calc(var(--task-list-spinner-size, 11px) * 0.5);
|
|
184
|
+
--loader-before-height: calc(var(--task-list-spinner-size, 11px) * 0.5);
|
|
185
|
+
--loader-after-width: calc(var(--task-list-spinner-size, 11px) * 0.75);
|
|
186
|
+
--loader-after-height: calc(var(--task-list-spinner-size, 11px) * 0.75);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.glyph-check,
|
|
190
|
+
.glyph-x {
|
|
191
|
+
display: inline-flex;
|
|
192
|
+
}
|
|
193
|
+
.glyph-check svg,
|
|
194
|
+
.glyph-x svg {
|
|
195
|
+
width: 12px;
|
|
196
|
+
height: 12px;
|
|
197
|
+
}
|
|
198
|
+
.glyph-check {
|
|
199
|
+
color: var(--task-list-done-color, #6b6b6b);
|
|
200
|
+
animation: task-list-check-pop 200ms var(--task-list-ease, cubic-bezier(0.23, 1, 0.32, 1)) both;
|
|
201
|
+
}
|
|
202
|
+
.glyph-x {
|
|
203
|
+
color: var(--task-list-error-color, #c93f38);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.row-text {
|
|
207
|
+
flex: 1;
|
|
208
|
+
min-width: 0;
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: baseline;
|
|
211
|
+
gap: var(--task-list-text-gap, 8px);
|
|
212
|
+
}
|
|
213
|
+
.task-row.pending .row-text {
|
|
214
|
+
opacity: var(--task-list-pending-opacity, 0.55);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.row-label {
|
|
218
|
+
font-size: var(--task-list-row-font-size, 0.875rem);
|
|
219
|
+
font-weight: var(--task-list-row-weight, 500);
|
|
220
|
+
color: var(--task-list-row-color, #2b2b2b);
|
|
221
|
+
white-space: nowrap;
|
|
222
|
+
overflow: hidden;
|
|
223
|
+
text-overflow: ellipsis;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.row-secondary {
|
|
227
|
+
font-size: var(--task-list-secondary-font-size, 0.75rem);
|
|
228
|
+
color: var(--task-list-secondary-color, #9a9a9a);
|
|
229
|
+
white-space: nowrap;
|
|
230
|
+
}
|
|
231
|
+
.row-secondary.mono {
|
|
232
|
+
font-family: var(--task-list-mono-font, ui-monospace, Menlo, monospace);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Themes the embedded Button into the compact error-tinted pill via its own custom
|
|
236
|
+
properties — these inherit down into Button's internal rules regardless of the
|
|
237
|
+
component boundary, the same wrapper-div pattern Banner uses for its dismiss button. */
|
|
238
|
+
.row-retry {
|
|
239
|
+
margin-left: auto;
|
|
240
|
+
flex-shrink: 0;
|
|
241
|
+
align-self: center;
|
|
242
|
+
--button-color: var(--task-list-retry-background, rgba(201, 63, 56, 0.12));
|
|
243
|
+
--button-text-color: var(--task-list-retry-color, #c93f38);
|
|
244
|
+
--button-hover-color: var(--task-list-retry-hover-background, rgba(201, 63, 56, 0.2));
|
|
245
|
+
--button-hover-text-color: var(--task-list-retry-color, #c93f38);
|
|
246
|
+
--button-border: none;
|
|
247
|
+
--button-padding: var(--task-list-retry-padding, 3px 10px);
|
|
248
|
+
--button-border-radius: var(--task-list-retry-radius, 999px);
|
|
249
|
+
--button-font-size: var(--task-list-retry-font-size, 0.75rem);
|
|
250
|
+
--button-font-weight: var(--task-list-retry-weight, 600);
|
|
251
|
+
--button-transition: background 150ms ease;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@media (prefers-reduced-motion: reduce) {
|
|
255
|
+
.task-row,
|
|
256
|
+
.glyph-inner,
|
|
257
|
+
.glyph-check {
|
|
258
|
+
animation-duration: 0.001s;
|
|
259
|
+
}
|
|
260
|
+
/* Loader's spin lives on its own internally-scoped element, reached here via :global()
|
|
261
|
+
scoped to a descendant of our local .glyph-spinner wrapper — the 3-class specificity
|
|
262
|
+
that produces reliably beats Loader's own 2-class rule regardless of stylesheet order. */
|
|
263
|
+
.glyph-spinner :global(.loader) {
|
|
264
|
+
animation: none;
|
|
265
|
+
-webkit-animation: none;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type TaskStatus = 'pending' | 'running' | 'failed' | 'done';
|
|
2
|
+
export type TaskListRow = {
|
|
3
|
+
/** The task/step description. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** A count, file, or command shown after the label. */
|
|
6
|
+
secondary?: string;
|
|
7
|
+
/** Render `secondary` in the mono face (filenames, commands). */
|
|
8
|
+
mono?: boolean;
|
|
9
|
+
/** Current state of the row's status machine. */
|
|
10
|
+
status: TaskStatus;
|
|
11
|
+
/** Failed rows: when set, renders an inline retry button with this text. */
|
|
12
|
+
retryLabel?: string;
|
|
13
|
+
};
|
|
14
|
+
export type TaskListProperties = MandatoryTaskListProperties & OptionalTaskListProperties;
|
|
15
|
+
export type MandatoryTaskListProperties = {
|
|
16
|
+
/** The work-plan rows, host-owned. Append rows or flip `status` in place — the component never invents its own timings. */
|
|
17
|
+
rows: TaskListRow[];
|
|
18
|
+
};
|
|
19
|
+
export type OptionalTaskListProperties = {
|
|
20
|
+
/** Fires when a failed row's retry button is clicked, with that row's index. */
|
|
21
|
+
onretry?: (index: number) => void;
|
|
22
|
+
testId?: string;
|
|
23
|
+
classes?: string;
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|