@juspay/svelte-ui-components 4.6.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.
@@ -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 { HITLAction, HITLProperties, HITLResponse, HITLSection } from './properties';
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
  };