@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.
@@ -2301,71 +2301,6 @@ function getStyles(options) {
2301
2301
  TOTP VIEW
2302
2302
  ======================================== */
2303
2303
 
2304
- .sv-resend-row {
2305
- display: flex;
2306
- align-items: center;
2307
- justify-content: space-between;
2308
- margin-top: 16px;
2309
- }
2310
-
2311
- .sv-resend-btn {
2312
- display: inline-flex;
2313
- align-items: center;
2314
- gap: 6px;
2315
- color: ${tokens.textSecondary};
2316
- font-size: 13px;
2317
- font-weight: 500;
2318
- text-decoration: none;
2319
- cursor: pointer;
2320
- background: none;
2321
- border: none;
2322
- padding: 0;
2323
- transition: color 0.15s ease;
2324
- }
2325
-
2326
- .sv-resend-btn:hover:not(:disabled) {
2327
- color: ${tokens.primary};
2328
- }
2329
-
2330
- .sv-resend-btn:disabled {
2331
- opacity: 0.5;
2332
- cursor: not-allowed;
2333
- }
2334
-
2335
- .sv-resend-btn svg {
2336
- width: 14px;
2337
- height: 14px;
2338
- }
2339
-
2340
- .sv-resend-timer {
2341
- font-size: 13px;
2342
- font-weight: 500;
2343
- color: ${tokens.textMuted};
2344
- min-width: 24px;
2345
- text-align: right;
2346
- }
2347
-
2348
- .sv-alt-method-link {
2349
- display: block;
2350
- width: 100%;
2351
- text-align: center;
2352
- color: ${tokens.textSecondary};
2353
- font-size: 13px;
2354
- font-weight: 400;
2355
- text-decoration: none;
2356
- cursor: pointer;
2357
- background: none;
2358
- border: none;
2359
- padding: 16px 0 0 0;
2360
- margin-top: 8px;
2361
- transition: color 0.15s ease;
2362
- }
2363
-
2364
- .sv-alt-method-link:hover {
2365
- color: ${tokens.primary};
2366
- text-decoration: underline;
2367
- }
2368
-
2369
2304
  .sv-resend-container {
2370
2305
  text-align: center;
2371
2306
  margin-top: 16px;
@@ -2757,27 +2692,6 @@ function createBackArrowIcon() {
2757
2692
  }));
2758
2693
  return svg;
2759
2694
  }
2760
- /**
2761
- * Resend/refresh icon - circular arrow
2762
- */
2763
- function createResendIcon() {
2764
- const svg = createSvgElement('0 0 16 16');
2765
- svg.appendChild(createPath('M13.5 8a5.5 5.5 0 11-1.21-3.45', {
2766
- stroke: 'currentColor',
2767
- 'stroke-width': '1.5',
2768
- 'stroke-linecap': 'round',
2769
- 'stroke-linejoin': 'round',
2770
- fill: 'none',
2771
- }));
2772
- svg.appendChild(createPath('M13.5 2.5v2.5H11', {
2773
- stroke: 'currentColor',
2774
- 'stroke-width': '1.5',
2775
- 'stroke-linecap': 'round',
2776
- 'stroke-linejoin': 'round',
2777
- fill: 'none',
2778
- }));
2779
- return svg;
2780
- }
2781
2695
  /**
2782
2696
  * Close (X) icon
2783
2697
  */
@@ -3700,7 +3614,6 @@ class TotpVerifyView {
3700
3614
  this.inputElements = [];
3701
3615
  this.submitButton = null;
3702
3616
  this.resendButton = null;
3703
- this.timerDisplay = null;
3704
3617
  this.backLink = null;
3705
3618
  this.errorContainer = null;
3706
3619
  this.resendTimer = null;
@@ -3718,12 +3631,14 @@ class TotpVerifyView {
3718
3631
  }
3719
3632
  render() {
3720
3633
  const container = div();
3634
+ this.backLink = this.createBackLink();
3721
3635
  const title = document.createElement('h3');
3722
3636
  title.className = 'sv-title';
3723
3637
  title.textContent = 'Enter verification code';
3638
+ const methodText = this.props.method === 'email' ? 'email' : 'phone';
3724
3639
  const subtitle = document.createElement('p');
3725
3640
  subtitle.className = 'sv-subtitle';
3726
- subtitle.innerHTML = `Enter the 6 digit code that has been sent to <strong>${escapeHtml(this.props.email)}</strong> to log in.`;
3641
+ subtitle.innerHTML = `We sent a 6-digit code to your ${methodText}<br><strong>${escapeHtml(this.props.email)}</strong>`;
3727
3642
  this.errorContainer = div();
3728
3643
  if (this.props.error) {
3729
3644
  this.errorContainer.appendChild(errorMessage(this.props.error));
@@ -3741,32 +3656,35 @@ class TotpVerifyView {
3741
3656
  this.startBackoff(this.props.backoffExpires);
3742
3657
  }
3743
3658
  }
3744
- // Resend row: icon + text on left, timer on right
3745
- const resendContainer = div('sv-resend-row');
3659
+ const resendContainer = div('sv-resend-container');
3746
3660
  this.resendButton = document.createElement('button');
3747
- this.resendButton.className = 'sv-resend-btn';
3748
- this.resendButton.appendChild(createResendIcon());
3749
- this.resendButton.appendChild(document.createTextNode('Resend code'));
3661
+ this.resendButton.className = 'sv-back-link';
3662
+ this.resendButton.textContent = 'Resend code';
3750
3663
  this.resendButton.addEventListener('click', this.boundHandleResend);
3751
- this.timerDisplay = document.createElement('span');
3752
- this.timerDisplay.className = 'sv-resend-timer';
3753
3664
  resendContainer.appendChild(this.resendButton);
3754
- resendContainer.appendChild(this.timerDisplay);
3755
- // "Log in another way" link at bottom
3756
- this.backLink = document.createElement('button');
3757
- this.backLink.className = 'sv-alt-method-link';
3758
- this.backLink.textContent = 'Log in another way';
3759
- this.backLink.addEventListener('click', this.boundHandleBack);
3665
+ // Use flex column layout so we can use CSS order for tab order control
3666
+ container.style.display = 'flex';
3667
+ container.style.flexDirection = 'column';
3668
+ // Append in TAB ORDER (not visual order) - back link last for tab navigation
3760
3669
  container.appendChild(title);
3761
3670
  container.appendChild(subtitle);
3762
3671
  container.appendChild(this.errorContainer);
3763
3672
  container.appendChild(inputGroup);
3764
3673
  container.appendChild(this.submitButton);
3765
3674
  container.appendChild(resendContainer);
3766
- container.appendChild(this.backLink);
3675
+ container.appendChild(this.backLink); // Last in DOM = last in tab order
3767
3676
  this.focusTimeoutId = setTimeout(() => this.inputElements[0]?.focus(), 50);
3768
3677
  return container;
3769
3678
  }
3679
+ createBackLink() {
3680
+ const link = document.createElement('button');
3681
+ link.className = 'sv-back-link';
3682
+ link.style.order = '-1'; // Visually keep at top with flexbox (DOM order controls tab order)
3683
+ link.appendChild(createBackArrowIcon());
3684
+ link.appendChild(document.createTextNode(' Choose another method'));
3685
+ link.addEventListener('click', this.boundHandleBack);
3686
+ return link;
3687
+ }
3770
3688
  createInputGroup() {
3771
3689
  const group = div('sv-totp-input-group');
3772
3690
  for (let i = 0; i < CODE_LENGTH; i++) {
@@ -3941,15 +3859,15 @@ class TotpVerifyView {
3941
3859
  this.resendTimer = new CooldownTimer({
3942
3860
  duration: 30,
3943
3861
  onTick: (secondsRemaining) => {
3944
- if (!this.resendButton || !this.timerDisplay)
3862
+ if (!this.resendButton)
3945
3863
  return;
3946
- this.timerDisplay.textContent = `${secondsRemaining}s`;
3864
+ this.resendButton.textContent = `Resend code (${secondsRemaining}s)`;
3947
3865
  this.resendButton.disabled = true;
3948
3866
  },
3949
3867
  onComplete: () => {
3950
- if (!this.resendButton || !this.timerDisplay)
3868
+ if (!this.resendButton)
3951
3869
  return;
3952
- this.timerDisplay.textContent = '';
3870
+ this.resendButton.textContent = 'Resend code';
3953
3871
  this.resendButton.disabled = false;
3954
3872
  },
3955
3873
  });