@rpcbase/auth 0.53.0 → 0.54.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.
@@ -0,0 +1,14 @@
1
+ export declare const useResendCountdown: (seconds?: number) => {
2
+ remaining: number;
3
+ formatted: string;
4
+ isCountingDown: boolean;
5
+ canResend: boolean;
6
+ restart: (nextSeconds?: number) => void;
7
+ };
8
+ export declare const ResendCodeButton: ({ seconds, onResend, className, disabled, }: {
9
+ seconds?: number;
10
+ onResend?: () => Promise<void> | void;
11
+ className?: string;
12
+ disabled?: boolean;
13
+ }) => import("react/jsx-runtime").JSX.Element;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ResendCodeButton/index.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,GAAI,gBAAY;;;;;4BAoBF,MAAM;CAelD,CAAA;AAGD,eAAO,MAAM,gBAAgB,GAAI,6CAK9B;IACD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,4CA8CA,CAAA"}
@@ -5,4 +5,5 @@ export * from './SignInForm';
5
5
  export * from './SignUpForm';
6
6
  export * from './RememberMeCheckbox';
7
7
  export * from './PasswordInput';
8
+ export * from './ResendCodeButton';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA"}
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { useLocation, Link, useNavigate } from "@rpcbase/router";
3
3
  import clsx from "clsx";
4
4
  import { useFormContext, useForm, zodResolver, FormProvider } from "@rpcbase/form";
5
5
  import * as React from "react";
6
- import { useEffect, useState } from "react";
6
+ import { useEffect, useState, useCallback, useMemo } from "react";
7
7
  import { r as requestSchema } from "./index-Bdcryyvv.js";
8
8
  import { r as requestSchema$1 } from "./index-DwX0Y2YV.js";
9
9
  import { b, a, r } from "./middleware-BiMXO6Dq.js";
@@ -317,15 +317,98 @@ const PasswordInput = ({
317
317
  errorMessage ? /* @__PURE__ */ jsx("p", { className: "mt-1 -mb-2 text-sm/6 text-red-500", children: errorMessage }) : null
318
318
  ] });
319
319
  };
320
+ const useResendCountdown = (seconds = 60) => {
321
+ const [remaining, setRemaining] = useState(seconds);
322
+ const [isCountingDown, setIsCountingDown] = useState(true);
323
+ useEffect(() => {
324
+ if (!isCountingDown) return;
325
+ const timer = setInterval(() => {
326
+ setRemaining((prev) => {
327
+ if (prev <= 1) {
328
+ setIsCountingDown(false);
329
+ return 0;
330
+ }
331
+ return prev - 1;
332
+ });
333
+ }, 1e3);
334
+ return () => clearInterval(timer);
335
+ }, [isCountingDown]);
336
+ const restart = useCallback((nextSeconds) => {
337
+ const value = typeof nextSeconds === "number" ? nextSeconds : seconds;
338
+ setRemaining(value);
339
+ setIsCountingDown(true);
340
+ }, [seconds]);
341
+ const formatted = useMemo(() => {
342
+ const minutes = Math.floor(remaining / 60);
343
+ const secs = remaining % 60;
344
+ return `${minutes}:${secs.toString().padStart(2, "0")}`;
345
+ }, [remaining]);
346
+ const canResend = !isCountingDown && remaining === 0;
347
+ return { remaining, formatted, isCountingDown, canResend, restart };
348
+ };
349
+ const ResendCodeButton = ({
350
+ seconds = 60,
351
+ onResend,
352
+ className,
353
+ disabled
354
+ }) => {
355
+ const [isSending, setIsSending] = useState(false);
356
+ const { formatted, isCountingDown, restart, canResend } = useResendCountdown(seconds);
357
+ const handleClick = async () => {
358
+ if (!canResend || isSending || disabled) return;
359
+ try {
360
+ setIsSending(true);
361
+ if (onResend) {
362
+ await onResend();
363
+ }
364
+ } finally {
365
+ restart();
366
+ setIsSending(false);
367
+ }
368
+ };
369
+ const isDisabled = disabled || isCountingDown || isSending;
370
+ const showCountdown = isDisabled && (isCountingDown || isSending);
371
+ return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
372
+ /* @__PURE__ */ jsx(
373
+ "button",
374
+ {
375
+ type: "button",
376
+ onClick: handleClick,
377
+ disabled: isDisabled,
378
+ "aria-label": "Resend code",
379
+ className: clsx(
380
+ "text-sm font-semibold text-sky-600 hover:underline disabled:cursor-not-allowed disabled:text-gray-400",
381
+ className
382
+ ),
383
+ children: "Resend code"
384
+ }
385
+ ),
386
+ showCountdown ? /* @__PURE__ */ jsxs(
387
+ "span",
388
+ {
389
+ "data-testid": "resend-countdown",
390
+ className: "text-sm text-gray-500",
391
+ "aria-live": "polite",
392
+ children: [
393
+ "(",
394
+ formatted,
395
+ ")"
396
+ ]
397
+ }
398
+ ) : null
399
+ ] });
400
+ };
320
401
  export {
321
402
  AppleSignInButton,
322
403
  AuthLayout,
323
404
  EmailInput,
324
405
  PasswordInput,
325
406
  RememberMeCheckbox,
407
+ ResendCodeButton,
326
408
  SignInForm,
327
409
  SignUpForm,
328
410
  b as redirectAuthMiddleware,
329
411
  a as requireSession,
330
- r as restrictSessionMiddleware
412
+ r as restrictSessionMiddleware,
413
+ useResendCountdown
331
414
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/auth",
3
- "version": "0.53.0",
3
+ "version": "0.54.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"