@sparkvault/sdk 1.1.5 → 1.1.6

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.
@@ -12,10 +12,6 @@ export declare function createCheckmarkIcon(): SVGSVGElement;
12
12
  * Back arrow (chevron left)
13
13
  */
14
14
  export declare function createBackArrowIcon(): SVGSVGElement;
15
- /**
16
- * Resend/refresh icon - circular arrow
17
- */
18
- export declare function createResendIcon(): SVGSVGElement;
19
15
  /**
20
16
  * Close (X) icon
21
17
  */
@@ -19,7 +19,6 @@ export declare class TotpVerifyView implements View {
19
19
  private inputElements;
20
20
  private submitButton;
21
21
  private resendButton;
22
- private timerDisplay;
23
22
  private backLink;
24
23
  private errorContainer;
25
24
  private resendTimer;
@@ -34,6 +33,7 @@ export declare class TotpVerifyView implements View {
34
33
  private readonly inputHandlers;
35
34
  constructor(props: TotpVerifyViewProps);
36
35
  render(): HTMLElement;
36
+ private createBackLink;
37
37
  private createInputGroup;
38
38
  private handleInput;
39
39
  private handleKeyDown;
@@ -2305,71 +2305,6 @@ function getStyles(options) {
2305
2305
  TOTP VIEW
2306
2306
  ======================================== */
2307
2307
 
2308
- .sv-resend-row {
2309
- display: flex;
2310
- align-items: center;
2311
- justify-content: space-between;
2312
- margin-top: 16px;
2313
- }
2314
-
2315
- .sv-resend-btn {
2316
- display: inline-flex;
2317
- align-items: center;
2318
- gap: 6px;
2319
- color: ${tokens.textSecondary};
2320
- font-size: 13px;
2321
- font-weight: 500;
2322
- text-decoration: none;
2323
- cursor: pointer;
2324
- background: none;
2325
- border: none;
2326
- padding: 0;
2327
- transition: color 0.15s ease;
2328
- }
2329
-
2330
- .sv-resend-btn:hover:not(:disabled) {
2331
- color: ${tokens.primary};
2332
- }
2333
-
2334
- .sv-resend-btn:disabled {
2335
- opacity: 0.5;
2336
- cursor: not-allowed;
2337
- }
2338
-
2339
- .sv-resend-btn svg {
2340
- width: 14px;
2341
- height: 14px;
2342
- }
2343
-
2344
- .sv-resend-timer {
2345
- font-size: 13px;
2346
- font-weight: 500;
2347
- color: ${tokens.textMuted};
2348
- min-width: 24px;
2349
- text-align: right;
2350
- }
2351
-
2352
- .sv-alt-method-link {
2353
- display: block;
2354
- width: 100%;
2355
- text-align: center;
2356
- color: ${tokens.textSecondary};
2357
- font-size: 13px;
2358
- font-weight: 400;
2359
- text-decoration: none;
2360
- cursor: pointer;
2361
- background: none;
2362
- border: none;
2363
- padding: 16px 0 0 0;
2364
- margin-top: 8px;
2365
- transition: color 0.15s ease;
2366
- }
2367
-
2368
- .sv-alt-method-link:hover {
2369
- color: ${tokens.primary};
2370
- text-decoration: underline;
2371
- }
2372
-
2373
2308
  .sv-resend-container {
2374
2309
  text-align: center;
2375
2310
  margin-top: 16px;
@@ -2761,27 +2696,6 @@ function createBackArrowIcon() {
2761
2696
  }));
2762
2697
  return svg;
2763
2698
  }
2764
- /**
2765
- * Resend/refresh icon - circular arrow
2766
- */
2767
- function createResendIcon() {
2768
- const svg = createSvgElement('0 0 16 16');
2769
- svg.appendChild(createPath('M13.5 8a5.5 5.5 0 11-1.21-3.45', {
2770
- stroke: 'currentColor',
2771
- 'stroke-width': '1.5',
2772
- 'stroke-linecap': 'round',
2773
- 'stroke-linejoin': 'round',
2774
- fill: 'none',
2775
- }));
2776
- svg.appendChild(createPath('M13.5 2.5v2.5H11', {
2777
- stroke: 'currentColor',
2778
- 'stroke-width': '1.5',
2779
- 'stroke-linecap': 'round',
2780
- 'stroke-linejoin': 'round',
2781
- fill: 'none',
2782
- }));
2783
- return svg;
2784
- }
2785
2699
  /**
2786
2700
  * Close (X) icon
2787
2701
  */
@@ -3704,7 +3618,6 @@ class TotpVerifyView {
3704
3618
  this.inputElements = [];
3705
3619
  this.submitButton = null;
3706
3620
  this.resendButton = null;
3707
- this.timerDisplay = null;
3708
3621
  this.backLink = null;
3709
3622
  this.errorContainer = null;
3710
3623
  this.resendTimer = null;
@@ -3722,12 +3635,14 @@ class TotpVerifyView {
3722
3635
  }
3723
3636
  render() {
3724
3637
  const container = div();
3638
+ this.backLink = this.createBackLink();
3725
3639
  const title = document.createElement('h3');
3726
3640
  title.className = 'sv-title';
3727
3641
  title.textContent = 'Enter verification code';
3642
+ const methodText = this.props.method === 'email' ? 'email' : 'phone';
3728
3643
  const subtitle = document.createElement('p');
3729
3644
  subtitle.className = 'sv-subtitle';
3730
- subtitle.innerHTML = `Enter the 6 digit code that has been sent to <strong>${escapeHtml(this.props.email)}</strong> to log in.`;
3645
+ subtitle.innerHTML = `We sent a 6-digit code to your ${methodText}<br><strong>${escapeHtml(this.props.email)}</strong>`;
3731
3646
  this.errorContainer = div();
3732
3647
  if (this.props.error) {
3733
3648
  this.errorContainer.appendChild(errorMessage(this.props.error));
@@ -3745,32 +3660,35 @@ class TotpVerifyView {
3745
3660
  this.startBackoff(this.props.backoffExpires);
3746
3661
  }
3747
3662
  }
3748
- // Resend row: icon + text on left, timer on right
3749
- const resendContainer = div('sv-resend-row');
3663
+ const resendContainer = div('sv-resend-container');
3750
3664
  this.resendButton = document.createElement('button');
3751
- this.resendButton.className = 'sv-resend-btn';
3752
- this.resendButton.appendChild(createResendIcon());
3753
- this.resendButton.appendChild(document.createTextNode('Resend code'));
3665
+ this.resendButton.className = 'sv-back-link';
3666
+ this.resendButton.textContent = 'Resend code';
3754
3667
  this.resendButton.addEventListener('click', this.boundHandleResend);
3755
- this.timerDisplay = document.createElement('span');
3756
- this.timerDisplay.className = 'sv-resend-timer';
3757
3668
  resendContainer.appendChild(this.resendButton);
3758
- resendContainer.appendChild(this.timerDisplay);
3759
- // "Log in another way" link at bottom
3760
- this.backLink = document.createElement('button');
3761
- this.backLink.className = 'sv-alt-method-link';
3762
- this.backLink.textContent = 'Log in another way';
3763
- this.backLink.addEventListener('click', this.boundHandleBack);
3669
+ // Use flex column layout so we can use CSS order for tab order control
3670
+ container.style.display = 'flex';
3671
+ container.style.flexDirection = 'column';
3672
+ // Append in TAB ORDER (not visual order) - back link last for tab navigation
3764
3673
  container.appendChild(title);
3765
3674
  container.appendChild(subtitle);
3766
3675
  container.appendChild(this.errorContainer);
3767
3676
  container.appendChild(inputGroup);
3768
3677
  container.appendChild(this.submitButton);
3769
3678
  container.appendChild(resendContainer);
3770
- container.appendChild(this.backLink);
3679
+ container.appendChild(this.backLink); // Last in DOM = last in tab order
3771
3680
  this.focusTimeoutId = setTimeout(() => this.inputElements[0]?.focus(), 50);
3772
3681
  return container;
3773
3682
  }
3683
+ createBackLink() {
3684
+ const link = document.createElement('button');
3685
+ link.className = 'sv-back-link';
3686
+ link.style.order = '-1'; // Visually keep at top with flexbox (DOM order controls tab order)
3687
+ link.appendChild(createBackArrowIcon());
3688
+ link.appendChild(document.createTextNode(' Choose another method'));
3689
+ link.addEventListener('click', this.boundHandleBack);
3690
+ return link;
3691
+ }
3774
3692
  createInputGroup() {
3775
3693
  const group = div('sv-totp-input-group');
3776
3694
  for (let i = 0; i < CODE_LENGTH; i++) {
@@ -3945,15 +3863,15 @@ class TotpVerifyView {
3945
3863
  this.resendTimer = new CooldownTimer({
3946
3864
  duration: 30,
3947
3865
  onTick: (secondsRemaining) => {
3948
- if (!this.resendButton || !this.timerDisplay)
3866
+ if (!this.resendButton)
3949
3867
  return;
3950
- this.timerDisplay.textContent = `${secondsRemaining}s`;
3868
+ this.resendButton.textContent = `Resend code (${secondsRemaining}s)`;
3951
3869
  this.resendButton.disabled = true;
3952
3870
  },
3953
3871
  onComplete: () => {
3954
- if (!this.resendButton || !this.timerDisplay)
3872
+ if (!this.resendButton)
3955
3873
  return;
3956
- this.timerDisplay.textContent = '';
3874
+ this.resendButton.textContent = 'Resend code';
3957
3875
  this.resendButton.disabled = false;
3958
3876
  },
3959
3877
  });