@juspay/svelte-ui-components 4.34.1 → 4.35.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/ChatComposer/ChatComposer.svelte +212 -118
- package/dist/ChatComposer/properties.d.ts +4 -0
- package/dist/CommandMenu/CommandMenu.svelte +41 -10
- package/dist/CommandMenu/CommandMenu.svelte.d.ts +1 -1
- package/dist/CommandMenu/properties.d.ts +6 -0
- package/dist/HITL/HITL.svelte +66 -24
- package/dist/HITL/properties.d.ts +9 -1
- package/dist/Select/Select.svelte +5 -0
- package/dist/Select/properties.d.ts +2 -0
- package/dist/_interaction/dismissal.js +1 -1
- package/dist-wc/index.js +2621 -2455
- package/package.json +1 -1
package/dist/HITL/HITL.svelte
CHANGED
|
@@ -32,10 +32,12 @@
|
|
|
32
32
|
title,
|
|
33
33
|
description,
|
|
34
34
|
sections,
|
|
35
|
+
details,
|
|
35
36
|
functionArguments,
|
|
36
37
|
hiddenKeys,
|
|
37
38
|
onconfirm,
|
|
38
39
|
confirmLabel = 'Confirm',
|
|
40
|
+
confirmDisabled = false,
|
|
39
41
|
cancelLabel = 'Cancel',
|
|
40
42
|
showCancel = true,
|
|
41
43
|
showConfirm = true,
|
|
@@ -90,18 +92,19 @@
|
|
|
90
92
|
let autoCancelTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
91
93
|
let originalMicState: boolean | null = null;
|
|
92
94
|
|
|
95
|
+
// Expiry from the caller takes precedence, including during a live request.
|
|
93
96
|
// History mode renders the settled state from props; live mode from local state.
|
|
94
97
|
// A history card with no initialState renders as expired rather than falling
|
|
95
98
|
// through to the pending interactive card — a replayed card must never be able
|
|
96
99
|
// to fire onconfirm.
|
|
97
100
|
const userResponse = $derived.by((): HITLResponse | null => {
|
|
101
|
+
if (initialState?.status === 'EXPIRED') {
|
|
102
|
+
return 'expired';
|
|
103
|
+
}
|
|
98
104
|
if (isHistoryMode) {
|
|
99
105
|
if (initialState === null) {
|
|
100
106
|
return 'expired';
|
|
101
107
|
}
|
|
102
|
-
if (initialState.status === 'EXPIRED') {
|
|
103
|
-
return 'expired';
|
|
104
|
-
}
|
|
105
108
|
return initialState.approved === true ? 'approved' : 'rejected';
|
|
106
109
|
}
|
|
107
110
|
return localResponse;
|
|
@@ -109,6 +112,7 @@
|
|
|
109
112
|
const isCompleted = $derived(userResponse !== null);
|
|
110
113
|
const isApproved = $derived(userResponse === 'approved' || userResponse === 'auto-approved');
|
|
111
114
|
const elapsedTime = $derived(countdownSeconds - timeRemaining);
|
|
115
|
+
const approvalBlocked = (action: HITLAction): boolean => action !== 'rejected' && confirmDisabled;
|
|
112
116
|
|
|
113
117
|
const completionText = $derived(
|
|
114
118
|
userResponse === 'auto-approved'
|
|
@@ -136,7 +140,11 @@
|
|
|
136
140
|
};
|
|
137
141
|
|
|
138
142
|
const restoreMicState = async (): Promise<void> => {
|
|
139
|
-
|
|
143
|
+
// Consume restoration before awaiting: a failed decision may be retried
|
|
144
|
+
// before the caller has updated isMicMuted, but must not toggle twice.
|
|
145
|
+
const stateToRestore = originalMicState;
|
|
146
|
+
originalMicState = null;
|
|
147
|
+
if (onmictoggle !== null && stateToRestore !== null && isMicMuted !== stateToRestore) {
|
|
140
148
|
try {
|
|
141
149
|
await onmictoggle();
|
|
142
150
|
} catch {
|
|
@@ -151,14 +159,16 @@
|
|
|
151
159
|
// updated in between.
|
|
152
160
|
let decisionPending = false;
|
|
153
161
|
|
|
154
|
-
const settle = (action: HITLAction, detail: HITLSettleDetail = {}): void => {
|
|
155
|
-
|
|
162
|
+
const settle = async (action: HITLAction, detail: HITLSettleDetail = {}): Promise<void> => {
|
|
163
|
+
// The controlled state may have changed while mic restoration was pending.
|
|
164
|
+
if (isCompleted || approvalBlocked(action)) {
|
|
165
|
+
if (approvalBlocked(action)) {
|
|
166
|
+
decisionPending = false;
|
|
167
|
+
}
|
|
156
168
|
return;
|
|
157
169
|
}
|
|
158
|
-
localResponse = action;
|
|
159
|
-
isProcessing = true;
|
|
160
170
|
try {
|
|
161
|
-
onconfirm?.({
|
|
171
|
+
await onconfirm?.({
|
|
162
172
|
confirmationId,
|
|
163
173
|
action,
|
|
164
174
|
approved: action !== 'rejected',
|
|
@@ -168,30 +178,46 @@
|
|
|
168
178
|
...(typeof detail.message === 'string' ? { message: detail.message } : {}),
|
|
169
179
|
...(Array.isArray(detail.answers) ? { answers: detail.answers } : {})
|
|
170
180
|
});
|
|
181
|
+
// Only publish success after the handoff succeeds. History/expiry updates
|
|
182
|
+
// received during the request remain authoritative.
|
|
183
|
+
if (!isCompleted && !approvalBlocked(action)) {
|
|
184
|
+
localResponse = action;
|
|
185
|
+
} else if (approvalBlocked(action)) {
|
|
186
|
+
decisionPending = false;
|
|
187
|
+
}
|
|
171
188
|
} catch {
|
|
172
189
|
// The decision failed to hand off; release the card for another attempt.
|
|
173
|
-
localResponse = null;
|
|
174
190
|
decisionPending = false;
|
|
175
|
-
} finally {
|
|
176
|
-
isProcessing = false;
|
|
177
191
|
}
|
|
178
192
|
};
|
|
179
193
|
|
|
180
194
|
const decide = async (action: HITLAction, detail: HITLSettleDetail = {}): Promise<void> => {
|
|
181
|
-
if (decisionPending || isCompleted) {
|
|
195
|
+
if (decisionPending || isCompleted || approvalBlocked(action)) {
|
|
182
196
|
return;
|
|
183
197
|
}
|
|
184
198
|
decisionPending = true;
|
|
185
|
-
|
|
186
|
-
|
|
199
|
+
isProcessing = true;
|
|
200
|
+
try {
|
|
201
|
+
await restoreMicState();
|
|
202
|
+
if (approvalBlocked(action)) {
|
|
203
|
+
decisionPending = false;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
await settle(action, detail);
|
|
207
|
+
} finally {
|
|
208
|
+
isProcessing = false;
|
|
209
|
+
}
|
|
187
210
|
};
|
|
188
211
|
|
|
189
212
|
const startCountdown = (): void => {
|
|
213
|
+
if (confirmDisabled) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
190
216
|
countdownActive = true;
|
|
191
217
|
timeRemaining = countdownSeconds;
|
|
192
218
|
countdownInterval = setInterval(() => {
|
|
193
219
|
// A sibling card's interaction pauses this countdown on its next tick.
|
|
194
|
-
if (get(pauseAllConfirmationTimers)) {
|
|
220
|
+
if (confirmDisabled || get(pauseAllConfirmationTimers)) {
|
|
195
221
|
stopCountdown();
|
|
196
222
|
return;
|
|
197
223
|
}
|
|
@@ -211,6 +237,9 @@
|
|
|
211
237
|
};
|
|
212
238
|
|
|
213
239
|
const interact = async (action: HITLAction, detail: HITLSettleDetail = {}): Promise<void> => {
|
|
240
|
+
if (approvalBlocked(action)) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
214
243
|
pauseTimers();
|
|
215
244
|
await decide(action, detail);
|
|
216
245
|
};
|
|
@@ -323,7 +352,9 @@
|
|
|
323
352
|
}
|
|
324
353
|
pauseAllConfirmationTimers.set(false);
|
|
325
354
|
if (countdownSeconds > 0) {
|
|
326
|
-
|
|
355
|
+
if (!confirmDisabled) {
|
|
356
|
+
startCountdown();
|
|
357
|
+
}
|
|
327
358
|
} else if (autoCancelSeconds > 0) {
|
|
328
359
|
autoCancelTimeout = setTimeout(() => {
|
|
329
360
|
void decide('rejected');
|
|
@@ -472,12 +503,18 @@
|
|
|
472
503
|
{/if}
|
|
473
504
|
|
|
474
505
|
<div class="confirmation-body">
|
|
475
|
-
{#
|
|
476
|
-
<div class="
|
|
477
|
-
|
|
478
|
-
<span class="parameter-value">{section.value}</span>
|
|
506
|
+
{#if typeof details === 'function'}
|
|
507
|
+
<div class="rich-details">
|
|
508
|
+
{@render details()}
|
|
479
509
|
</div>
|
|
480
|
-
{
|
|
510
|
+
{:else}
|
|
511
|
+
{#each parameterSections as section, sectionIndex (sectionIndex)}
|
|
512
|
+
<div class="params">
|
|
513
|
+
<span class="parameter-label">{section.label}</span>
|
|
514
|
+
<span class="parameter-value">{section.value}</span>
|
|
515
|
+
</div>
|
|
516
|
+
{/each}
|
|
517
|
+
{/if}
|
|
481
518
|
|
|
482
519
|
{#if isCompleted && userResponse !== null}
|
|
483
520
|
<div
|
|
@@ -640,14 +677,14 @@
|
|
|
640
677
|
{/if}
|
|
641
678
|
{#if showConfirm}
|
|
642
679
|
<div class="confirm-button">
|
|
643
|
-
{#if countdownActive}
|
|
680
|
+
{#if countdownActive && !confirmDisabled}
|
|
644
681
|
<div class="progress-anchor">
|
|
645
682
|
<Progress value={elapsedTime} max={countdownSeconds} />
|
|
646
683
|
</div>
|
|
647
684
|
{/if}
|
|
648
685
|
<Button
|
|
649
686
|
text={confirmLabel}
|
|
650
|
-
enable={!isProcessing}
|
|
687
|
+
enable={!isProcessing && !confirmDisabled}
|
|
651
688
|
testId={confirmTestId ?? (testId && `${testId}-confirm`)}
|
|
652
689
|
onclick={() => interact('approved')}
|
|
653
690
|
/>
|
|
@@ -718,6 +755,11 @@
|
|
|
718
755
|
gap: var(--hitl-param-gap, 0.25rem);
|
|
719
756
|
}
|
|
720
757
|
|
|
758
|
+
.rich-details {
|
|
759
|
+
min-width: 0;
|
|
760
|
+
width: 100%;
|
|
761
|
+
}
|
|
762
|
+
|
|
721
763
|
.parameter-label {
|
|
722
764
|
font-size: var(--hitl-param-label-font-size, 0.6875rem);
|
|
723
765
|
font-weight: var(--hitl-param-label-font-weight, 600);
|
|
@@ -106,12 +106,20 @@ export type OptionalHITLProperties = {
|
|
|
106
106
|
* formatted generically instead.
|
|
107
107
|
*/
|
|
108
108
|
sections?: HITLSection[];
|
|
109
|
+
/**
|
|
110
|
+
* Rich parameter detail replacing sections/arguments in pending and resolved
|
|
111
|
+
* cards, including history. Unlike children, this remains after a decision.
|
|
112
|
+
*/
|
|
113
|
+
details?: Snippet;
|
|
109
114
|
/** Raw arguments, formatted generically when no `sections` are given. */
|
|
110
115
|
functionArguments?: Record<string, unknown>;
|
|
111
116
|
/** Argument keys (case-insensitive) hidden from the generic formatting. */
|
|
112
117
|
hiddenKeys?: string[];
|
|
113
|
-
|
|
118
|
+
/** Awaited before completion; throwing/rejecting leaves the card pending for retry. */
|
|
119
|
+
onconfirm?: (event: HITLEvent) => void | Promise<void>;
|
|
114
120
|
confirmLabel?: string;
|
|
121
|
+
/** Blocks manual and timed approval while leaving rejection available. Defaults to false. */
|
|
122
|
+
confirmDisabled?: boolean;
|
|
115
123
|
cancelLabel?: string;
|
|
116
124
|
/** Hides the cancel button entirely — for a card whose only real dispositions come through `actions`. Default `true`. */
|
|
117
125
|
showCancel?: boolean;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
searchable = false,
|
|
18
18
|
searchPosition = 'trigger',
|
|
19
19
|
placeholder = '',
|
|
20
|
+
ariaLabel,
|
|
20
21
|
disabled = false,
|
|
21
22
|
error = false,
|
|
22
23
|
errorMessage,
|
|
@@ -754,6 +755,7 @@
|
|
|
754
755
|
onclick={handleTriggerClick}
|
|
755
756
|
onkeydown={handleKeydown}
|
|
756
757
|
role="combobox"
|
|
758
|
+
aria-label={ariaLabel}
|
|
757
759
|
aria-expanded={open}
|
|
758
760
|
aria-haspopup="listbox"
|
|
759
761
|
aria-controls={listboxId}
|
|
@@ -779,6 +781,7 @@
|
|
|
779
781
|
<input
|
|
780
782
|
class="select-search"
|
|
781
783
|
type="text"
|
|
784
|
+
aria-label={ariaLabel}
|
|
782
785
|
value={query}
|
|
783
786
|
oninput={handleSearchInput}
|
|
784
787
|
onfocus={handleSearchFocus}
|
|
@@ -807,6 +810,7 @@
|
|
|
807
810
|
<input
|
|
808
811
|
class="select-search"
|
|
809
812
|
type="text"
|
|
813
|
+
aria-label={ariaLabel}
|
|
810
814
|
value={query}
|
|
811
815
|
oninput={handleSearchInput}
|
|
812
816
|
onfocus={handleSearchFocus}
|
|
@@ -828,6 +832,7 @@
|
|
|
828
832
|
<input
|
|
829
833
|
class="select-search"
|
|
830
834
|
type="text"
|
|
835
|
+
aria-label={ariaLabel}
|
|
831
836
|
value={open ? query : displayText}
|
|
832
837
|
oninput={handleSearchInput}
|
|
833
838
|
onfocus={handleSearchFocus}
|
|
@@ -55,6 +55,8 @@ export type OptionalSelectProperties = {
|
|
|
55
55
|
*/
|
|
56
56
|
searchPosition?: SelectSearchPosition;
|
|
57
57
|
placeholder?: string;
|
|
58
|
+
/** Accessible name for the combobox trigger. Omitted to preserve the default unnamed behavior. */
|
|
59
|
+
ariaLabel?: string;
|
|
58
60
|
disabled?: boolean;
|
|
59
61
|
/**
|
|
60
62
|
* Renders the error treatment on the trigger — a red border that outranks
|
|
@@ -33,7 +33,7 @@ function startedInside(event, node) {
|
|
|
33
33
|
return eventHitsInside(node, event);
|
|
34
34
|
}
|
|
35
35
|
function handleKeydown(event) {
|
|
36
|
-
if (event.key !== 'Escape') {
|
|
36
|
+
if (event.key !== 'Escape' || event.isComposing || event.keyCode === 229) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
topmost()?.onEscape?.();
|