@juspay/svelte-ui-components 4.5.0 → 4.7.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/HITL/HITL.svelte
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
import Card from '../Card/Card.svelte';
|
|
6
6
|
import Progress from '../Progress/Progress.svelte';
|
|
7
7
|
import { pauseAllConfirmationTimers } from './timers';
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
HITLAction,
|
|
10
|
+
HITLExtraAction,
|
|
11
|
+
HITLProperties,
|
|
12
|
+
HITLResponse,
|
|
13
|
+
HITLSection
|
|
14
|
+
} from './properties';
|
|
9
15
|
|
|
10
16
|
/**
|
|
11
17
|
* Human-in-the-loop approval card: the assistant wants to run an action and the
|
|
@@ -43,6 +49,8 @@
|
|
|
43
49
|
cancelTestId,
|
|
44
50
|
completionTestId,
|
|
45
51
|
completionTextTestId,
|
|
52
|
+
actions,
|
|
53
|
+
children,
|
|
46
54
|
classes
|
|
47
55
|
}: HITLProperties = $props();
|
|
48
56
|
|
|
@@ -180,6 +188,20 @@
|
|
|
180
188
|
await decide(action);
|
|
181
189
|
};
|
|
182
190
|
|
|
191
|
+
// An extra action (e.g. "Deny with instructions") is a side path, not a
|
|
192
|
+
// decision — it never settles the card, so `onconfirm` never fires for it.
|
|
193
|
+
// It still counts as interacting with the card: pause this card's own
|
|
194
|
+
// countdown and every sibling's, exactly like clicking confirm or cancel.
|
|
195
|
+
const selectExtraAction = (action: HITLExtraAction): void => {
|
|
196
|
+
if (decisionPending || isProcessing || isCompleted) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
pauseAllConfirmationTimers.set(true);
|
|
200
|
+
stopCountdown();
|
|
201
|
+
clearAutoCancel();
|
|
202
|
+
action.onSelect();
|
|
203
|
+
};
|
|
204
|
+
|
|
183
205
|
onMount(() => {
|
|
184
206
|
if (isHistoryMode) {
|
|
185
207
|
return;
|
|
@@ -375,6 +397,11 @@
|
|
|
375
397
|
</span>
|
|
376
398
|
</div>
|
|
377
399
|
{:else}
|
|
400
|
+
{#if children}
|
|
401
|
+
<div class="extra-content">
|
|
402
|
+
{@render children()}
|
|
403
|
+
</div>
|
|
404
|
+
{/if}
|
|
378
405
|
<div class="action-buttons">
|
|
379
406
|
<div class="cancel-button">
|
|
380
407
|
<Button
|
|
@@ -385,6 +412,19 @@
|
|
|
385
412
|
onclick={() => interact('rejected')}
|
|
386
413
|
/>
|
|
387
414
|
</div>
|
|
415
|
+
{#each actions ?? [] as action, index (action.testId ?? `${index}-${action.label}`)}
|
|
416
|
+
<div class="extra-action-button">
|
|
417
|
+
<Button
|
|
418
|
+
variant="secondary"
|
|
419
|
+
text={action.label}
|
|
420
|
+
enable={!isProcessing}
|
|
421
|
+
testId={action.testId ?? (testId && `${testId}-action-${index}`)}
|
|
422
|
+
classes={action.classes}
|
|
423
|
+
ariaLabel={action.ariaLabel}
|
|
424
|
+
onclick={() => selectExtraAction(action)}
|
|
425
|
+
/>
|
|
426
|
+
</div>
|
|
427
|
+
{/each}
|
|
388
428
|
<div class="confirm-button">
|
|
389
429
|
{#if countdownActive}
|
|
390
430
|
<div class="progress-anchor">
|
|
@@ -480,6 +520,13 @@
|
|
|
480
520
|
text-transform: capitalize;
|
|
481
521
|
}
|
|
482
522
|
|
|
523
|
+
/* Rendered only when `children` is supplied; the flex gap on
|
|
524
|
+
.confirmation-body already spaces it from the params above and the
|
|
525
|
+
action-buttons row below, so no default-behavior change when it's absent. */
|
|
526
|
+
.extra-content {
|
|
527
|
+
width: 100%;
|
|
528
|
+
}
|
|
529
|
+
|
|
483
530
|
.action-buttons {
|
|
484
531
|
display: flex;
|
|
485
532
|
gap: var(--hitl-buttons-gap, 0.75rem);
|
|
@@ -487,7 +534,8 @@
|
|
|
487
534
|
}
|
|
488
535
|
|
|
489
536
|
.cancel-button,
|
|
490
|
-
.confirm-button
|
|
537
|
+
.confirm-button,
|
|
538
|
+
.extra-action-button {
|
|
491
539
|
flex: 1;
|
|
492
540
|
position: relative;
|
|
493
541
|
--button-width: 100%;
|
|
@@ -15,6 +15,23 @@ export type HITLInitialState = {
|
|
|
15
15
|
/** `'EXPIRED'` renders the timed-out completion state. */
|
|
16
16
|
status?: string;
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* A side action rendered beside confirm/cancel — e.g. "Deny with instructions"
|
|
20
|
+
* opening a compose panel, or a third disposition a plain approve/reject can't
|
|
21
|
+
* express. Selecting one does NOT settle the card: no completion state, no
|
|
22
|
+
* `onconfirm`. It only pauses the countdown (own and siblings', like any other
|
|
23
|
+
* interaction) and calls `onSelect` — settling, if any, is the caller's job.
|
|
24
|
+
*/
|
|
25
|
+
export type HITLExtraAction = {
|
|
26
|
+
label: string;
|
|
27
|
+
onSelect: () => void;
|
|
28
|
+
/** `data-pw` for this action's button (default: `<testId>-action-<index>`). */
|
|
29
|
+
testId?: string;
|
|
30
|
+
/** Class string on this action's Button, e.g. to pick a variant. */
|
|
31
|
+
classes?: string;
|
|
32
|
+
/** Accessible name for this action's Button, when `label` alone isn't descriptive enough. */
|
|
33
|
+
ariaLabel?: string;
|
|
34
|
+
};
|
|
18
35
|
export type HITLProperties = OptionalHITLProperties & MandatoryHITLProperties;
|
|
19
36
|
export type MandatoryHITLProperties = {
|
|
20
37
|
confirmationId: string;
|
|
@@ -67,5 +84,16 @@ export type OptionalHITLProperties = {
|
|
|
67
84
|
completionTestId?: string;
|
|
68
85
|
/** Override the completion text's test id (default: `<testId>-completion-text`). */
|
|
69
86
|
completionTextTestId?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Extra side actions rendered between cancel and confirm — e.g. "Deny with
|
|
89
|
+
* instructions". None of these settle the card; see `HITLExtraAction`.
|
|
90
|
+
*/
|
|
91
|
+
actions?: HITLExtraAction[];
|
|
92
|
+
/**
|
|
93
|
+
* Arbitrary extra controls — free-text input, multi-select chips — rendered
|
|
94
|
+
* in the body above the action row while the card is pending. Never shown
|
|
95
|
+
* once the card is completed or in history mode.
|
|
96
|
+
*/
|
|
97
|
+
children?: Snippet;
|
|
70
98
|
classes?: string;
|
|
71
99
|
};
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { KeyboardInputProperties } from './properties';
|
|
3
3
|
|
|
4
|
-
let {
|
|
4
|
+
let {
|
|
5
|
+
keys,
|
|
6
|
+
separator = '+',
|
|
7
|
+
testId,
|
|
8
|
+
onclick,
|
|
9
|
+
classes,
|
|
10
|
+
literal = false
|
|
11
|
+
}: KeyboardInputProperties = $props();
|
|
5
12
|
|
|
6
13
|
const KEY_SYMBOLS: Record<string, string> = {
|
|
7
14
|
cmd: '\u2318',
|
|
@@ -28,6 +35,9 @@
|
|
|
28
35
|
let interactive = $derived(typeof onclick === 'function');
|
|
29
36
|
|
|
30
37
|
function getSymbol(key: string): string {
|
|
38
|
+
if (literal) {
|
|
39
|
+
return key;
|
|
40
|
+
}
|
|
31
41
|
return KEY_SYMBOLS[key.toLowerCase()] ?? key;
|
|
32
42
|
}
|
|
33
43
|
|
|
@@ -6,6 +6,15 @@ export type OptionalKeyboardInputProperties = {
|
|
|
6
6
|
separator?: string;
|
|
7
7
|
testId?: string;
|
|
8
8
|
classes?: string;
|
|
9
|
+
/**
|
|
10
|
+
* When true, every key renders exactly as given — the built-in KEY_SYMBOLS
|
|
11
|
+
* table (`space` → ␣, `tab` → ⇥, `cmd` → ⌘, …) is bypassed entirely.
|
|
12
|
+
* Defaults to false, so existing consumers keep today's glyph substitution
|
|
13
|
+
* unchanged. Use this when the word itself is the label that must appear
|
|
14
|
+
* (e.g. a "Hold SPACE" caption or a physical-key caption reading "Tab"),
|
|
15
|
+
* not the typographic symbol.
|
|
16
|
+
*/
|
|
17
|
+
literal?: boolean;
|
|
9
18
|
};
|
|
10
19
|
export type KeyboardInputEventProperties = {
|
|
11
20
|
onclick?: (event: MouseEvent) => void;
|