@hex-core/components 1.8.1 → 1.9.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/_tsup-dts-rollup.d.ts +280 -0
- package/dist/auth-forgot-password.d.ts +2 -0
- package/dist/auth-forgot-password.js +400 -0
- package/dist/auth-forgot-password.js.map +1 -0
- package/dist/auth-reset-password.d.ts +2 -0
- package/dist/auth-reset-password.js +323 -0
- package/dist/auth-reset-password.js.map +1 -0
- package/dist/auth-sign-in-split.d.ts +3 -0
- package/dist/auth-sign-in-split.js +443 -0
- package/dist/auth-sign-in-split.js.map +1 -0
- package/dist/auth-sign-up-card.d.ts +3 -0
- package/dist/auth-sign-up-card.js +590 -0
- package/dist/auth-sign-up-card.js.map +1 -0
- package/dist/auth-verify-email.d.ts +2 -0
- package/dist/auth-verify-email.js +339 -0
- package/dist/auth-verify-email.js.map +1 -0
- package/dist/auth-verify-otp.d.ts +2 -0
- package/dist/auth-verify-otp.js +349 -0
- package/dist/auth-verify-otp.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +1029 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -401,6 +401,275 @@ export { AudioWaveformProps as AudioWaveformProps_alias_1 }
|
|
|
401
401
|
|
|
402
402
|
export declare const audioWaveformSchema: ComponentSchemaDefinition;
|
|
403
403
|
|
|
404
|
+
declare interface AuthAdapter {
|
|
405
|
+
signInWithPassword?(p: {
|
|
406
|
+
email: string;
|
|
407
|
+
password: string;
|
|
408
|
+
remember: boolean;
|
|
409
|
+
}): Promise<AuthAdapterResult>;
|
|
410
|
+
signUpWithPassword?(p: {
|
|
411
|
+
email: string;
|
|
412
|
+
password: string;
|
|
413
|
+
name?: string;
|
|
414
|
+
}): Promise<AuthAdapterResult>;
|
|
415
|
+
signInWithSocial?(p: {
|
|
416
|
+
provider: AuthSocialProvider;
|
|
417
|
+
}): Promise<AuthAdapterResult>;
|
|
418
|
+
sendMagicLink?(p: {
|
|
419
|
+
email: string;
|
|
420
|
+
}): Promise<AuthAdapterResult>;
|
|
421
|
+
verifyOtp?(p: {
|
|
422
|
+
code: string;
|
|
423
|
+
intent: AuthOtpIntent;
|
|
424
|
+
}): Promise<AuthAdapterResult>;
|
|
425
|
+
requestPasswordReset?(p: {
|
|
426
|
+
email: string;
|
|
427
|
+
}): Promise<AuthAdapterResult>;
|
|
428
|
+
resetPassword?(p: {
|
|
429
|
+
token: string;
|
|
430
|
+
password: string;
|
|
431
|
+
}): Promise<AuthAdapterResult>;
|
|
432
|
+
registerPasskey?(): Promise<AuthAdapterResult>;
|
|
433
|
+
signInWithPasskey?(): Promise<AuthAdapterResult>;
|
|
434
|
+
/**
|
|
435
|
+
* Re-send a magic link to the same address. Distinct from {@link sendMagicLink}
|
|
436
|
+
* so consumers can throttle resends and surface different analytics / error
|
|
437
|
+
* copy for the second-and-onward attempt. Used by the verify-email block.
|
|
438
|
+
*/
|
|
439
|
+
resendMagicLink?(p: {
|
|
440
|
+
email: string;
|
|
441
|
+
}): Promise<AuthAdapterResult>;
|
|
442
|
+
/**
|
|
443
|
+
* Re-send a one-time code for the given intent. Distinct from the initial
|
|
444
|
+
* code dispatch so consumers can throttle and log resends separately. Used
|
|
445
|
+
* by the verify-otp block.
|
|
446
|
+
*/
|
|
447
|
+
resendOtp?(p: {
|
|
448
|
+
intent: AuthOtpIntent;
|
|
449
|
+
}): Promise<AuthAdapterResult>;
|
|
450
|
+
}
|
|
451
|
+
export { AuthAdapter }
|
|
452
|
+
export { AuthAdapter as AuthAdapter_alias_1 }
|
|
453
|
+
export { AuthAdapter as AuthAdapter_alias_2 }
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* The contract every Hex Core auth block consumes via its `adapter` prop.
|
|
457
|
+
*
|
|
458
|
+
* Hex Core does not ship session management — auth blocks are presentation-
|
|
459
|
+
* only and delegate every credential, OTP, and OAuth handoff to whatever
|
|
460
|
+
* the consumer wires up (better-auth, Clerk, NextAuth, Supabase Auth, a
|
|
461
|
+
* custom server, …). The adapter is the single seam.
|
|
462
|
+
*
|
|
463
|
+
* Every method is **optional**. A block that needs `signInWithPassword` but
|
|
464
|
+
* not passkeys passes an adapter implementing only the methods it needs;
|
|
465
|
+
* the block surfaces a runtime error if the user hits a code path the
|
|
466
|
+
* adapter doesn't implement, rather than failing to render. This lets a
|
|
467
|
+
* consumer ship password-only on day one and add passkeys later without
|
|
468
|
+
* forking the block source.
|
|
469
|
+
*
|
|
470
|
+
* A reference {@link mockAuthAdapter} lives below — used by the docs
|
|
471
|
+
* showcase routes and unit tests; never ship it in production.
|
|
472
|
+
*/
|
|
473
|
+
declare interface AuthAdapterResult {
|
|
474
|
+
ok: boolean;
|
|
475
|
+
error?: {
|
|
476
|
+
code: string;
|
|
477
|
+
message: string;
|
|
478
|
+
};
|
|
479
|
+
redirect?: string;
|
|
480
|
+
}
|
|
481
|
+
export { AuthAdapterResult }
|
|
482
|
+
export { AuthAdapterResult as AuthAdapterResult_alias_1 }
|
|
483
|
+
export { AuthAdapterResult as AuthAdapterResult_alias_2 }
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* "Forgot password" page. Single email field; on success swaps to a
|
|
487
|
+
* confirmation state composed from `Empty` ("we sent you a link") plus a
|
|
488
|
+
* "back to sign in" affordance. Routes the dispatch through
|
|
489
|
+
* `adapter.requestPasswordReset`.
|
|
490
|
+
*/
|
|
491
|
+
declare function AuthForgotPassword({ adapter, signInHref, className, onSuccess, }: AuthForgotPasswordProps): JSX.Element;
|
|
492
|
+
export { AuthForgotPassword }
|
|
493
|
+
export { AuthForgotPassword as AuthForgotPassword_alias_1 }
|
|
494
|
+
export { AuthForgotPassword as AuthForgotPassword_alias_2 }
|
|
495
|
+
|
|
496
|
+
declare interface AuthForgotPasswordProps {
|
|
497
|
+
adapter: AuthAdapter;
|
|
498
|
+
signInHref?: string;
|
|
499
|
+
className?: string;
|
|
500
|
+
onSuccess?: () => void;
|
|
501
|
+
}
|
|
502
|
+
export { AuthForgotPasswordProps }
|
|
503
|
+
export { AuthForgotPasswordProps as AuthForgotPasswordProps_alias_1 }
|
|
504
|
+
export { AuthForgotPasswordProps as AuthForgotPasswordProps_alias_2 }
|
|
505
|
+
|
|
506
|
+
export declare const authForgotPasswordSchema: ComponentSchemaDefinition;
|
|
507
|
+
|
|
508
|
+
declare type AuthOtpIntent = "sign-in" | "verify-email" | "mfa";
|
|
509
|
+
export { AuthOtpIntent }
|
|
510
|
+
export { AuthOtpIntent as AuthOtpIntent_alias_1 }
|
|
511
|
+
export { AuthOtpIntent as AuthOtpIntent_alias_2 }
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* "Reset password" page. Two fields (new password + confirm) with manual
|
|
515
|
+
* confirm-match and minLength validation. The opaque `token` is forwarded
|
|
516
|
+
* verbatim to `adapter.resetPassword`. Routes the consumer-supplied adapter
|
|
517
|
+
* is responsible for binding the token to a user account on the backend.
|
|
518
|
+
*/
|
|
519
|
+
declare function AuthResetPassword({ adapter, token, signInHref, passwordMinLength, className, onSuccess, }: AuthResetPasswordProps): JSX.Element;
|
|
520
|
+
export { AuthResetPassword }
|
|
521
|
+
export { AuthResetPassword as AuthResetPassword_alias_1 }
|
|
522
|
+
export { AuthResetPassword as AuthResetPassword_alias_2 }
|
|
523
|
+
|
|
524
|
+
declare interface AuthResetPasswordProps {
|
|
525
|
+
adapter: AuthAdapter;
|
|
526
|
+
/** Reset token, typically read from `?token=…` by the showcase / consumer route. */
|
|
527
|
+
token: string;
|
|
528
|
+
signInHref?: string;
|
|
529
|
+
passwordMinLength?: number;
|
|
530
|
+
className?: string;
|
|
531
|
+
onSuccess?: (redirect: string | undefined) => void;
|
|
532
|
+
}
|
|
533
|
+
export { AuthResetPasswordProps }
|
|
534
|
+
export { AuthResetPasswordProps as AuthResetPasswordProps_alias_1 }
|
|
535
|
+
export { AuthResetPasswordProps as AuthResetPasswordProps_alias_2 }
|
|
536
|
+
|
|
537
|
+
export declare const authResetPasswordSchema: ComponentSchemaDefinition;
|
|
538
|
+
|
|
539
|
+
declare interface AuthSignInSocialProvider {
|
|
540
|
+
provider: AuthSocialProvider;
|
|
541
|
+
label: string;
|
|
542
|
+
icon?: React_2.ReactNode;
|
|
543
|
+
}
|
|
544
|
+
export { AuthSignInSocialProvider }
|
|
545
|
+
export { AuthSignInSocialProvider as AuthSignInSocialProvider_alias_1 }
|
|
546
|
+
export { AuthSignInSocialProvider as AuthSignInSocialProvider_alias_2 }
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Split-screen sign-in page. Marketing panel on the left (≥lg), credential
|
|
550
|
+
* form on the right. All submit paths route through the supplied
|
|
551
|
+
* `AuthAdapter` — Hex Core never touches credentials directly.
|
|
552
|
+
*/
|
|
553
|
+
declare function AuthSignInSplit({ adapter, socialProviders, brand, marketing, signUpHref, forgotPasswordHref, className, onSuccess, }: AuthSignInSplitProps): JSX.Element;
|
|
554
|
+
export { AuthSignInSplit }
|
|
555
|
+
export { AuthSignInSplit as AuthSignInSplit_alias_1 }
|
|
556
|
+
export { AuthSignInSplit as AuthSignInSplit_alias_2 }
|
|
557
|
+
|
|
558
|
+
declare interface AuthSignInSplitProps {
|
|
559
|
+
/** Wires every credential / OAuth call to the consumer's auth library. */
|
|
560
|
+
adapter: AuthAdapter;
|
|
561
|
+
/** Optional list of social-login buttons rendered above the email field. */
|
|
562
|
+
socialProviders?: ReadonlyArray<AuthSignInSocialProvider>;
|
|
563
|
+
/** Brand block (logo + product name) shown at the top of the marketing panel. */
|
|
564
|
+
brand?: React_2.ReactNode;
|
|
565
|
+
/** Marketing copy / quote / illustration shown below the brand block. */
|
|
566
|
+
marketing?: React_2.ReactNode;
|
|
567
|
+
/** Href for the "Sign up" link rendered below the form. */
|
|
568
|
+
signUpHref?: string;
|
|
569
|
+
/** Href for the "Forgot?" link inline with the password label. */
|
|
570
|
+
forgotPasswordHref?: string;
|
|
571
|
+
/** Additional classes applied to the root grid wrapper. */
|
|
572
|
+
className?: string;
|
|
573
|
+
/** Called after a successful sign-in (any flow) with the adapter's redirect target. */
|
|
574
|
+
onSuccess?: (redirect: string | undefined) => void;
|
|
575
|
+
}
|
|
576
|
+
export { AuthSignInSplitProps }
|
|
577
|
+
export { AuthSignInSplitProps as AuthSignInSplitProps_alias_1 }
|
|
578
|
+
export { AuthSignInSplitProps as AuthSignInSplitProps_alias_2 }
|
|
579
|
+
|
|
580
|
+
export declare const authSignInSplitSchema: ComponentSchemaDefinition;
|
|
581
|
+
|
|
582
|
+
/** Centered-card sign-up page. Composes Card + form fields + optional social. */
|
|
583
|
+
declare function AuthSignUpCard({ adapter, socialProviders, signInHref, termsHref, privacyHref, passwordMinLength, className, onSuccess, }: AuthSignUpCardProps): JSX.Element;
|
|
584
|
+
export { AuthSignUpCard }
|
|
585
|
+
export { AuthSignUpCard as AuthSignUpCard_alias_1 }
|
|
586
|
+
export { AuthSignUpCard as AuthSignUpCard_alias_2 }
|
|
587
|
+
|
|
588
|
+
declare interface AuthSignUpCardProps {
|
|
589
|
+
adapter: AuthAdapter;
|
|
590
|
+
socialProviders?: ReadonlyArray<AuthSignUpCardSocialProvider>;
|
|
591
|
+
signInHref?: string;
|
|
592
|
+
termsHref?: string;
|
|
593
|
+
privacyHref?: string;
|
|
594
|
+
passwordMinLength?: number;
|
|
595
|
+
className?: string;
|
|
596
|
+
onSuccess?: (redirect: string | undefined) => void;
|
|
597
|
+
}
|
|
598
|
+
export { AuthSignUpCardProps }
|
|
599
|
+
export { AuthSignUpCardProps as AuthSignUpCardProps_alias_1 }
|
|
600
|
+
export { AuthSignUpCardProps as AuthSignUpCardProps_alias_2 }
|
|
601
|
+
|
|
602
|
+
export declare const authSignUpCardSchema: ComponentSchemaDefinition;
|
|
603
|
+
|
|
604
|
+
declare interface AuthSignUpCardSocialProvider {
|
|
605
|
+
provider: AuthSocialProvider;
|
|
606
|
+
label: string;
|
|
607
|
+
icon?: React_2.ReactNode;
|
|
608
|
+
}
|
|
609
|
+
export { AuthSignUpCardSocialProvider }
|
|
610
|
+
export { AuthSignUpCardSocialProvider as AuthSignUpCardSocialProvider_alias_1 }
|
|
611
|
+
export { AuthSignUpCardSocialProvider as AuthSignUpCardSocialProvider_alias_2 }
|
|
612
|
+
|
|
613
|
+
declare type AuthSocialProvider = "github" | "google" | "microsoft" | (string & {});
|
|
614
|
+
export { AuthSocialProvider }
|
|
615
|
+
export { AuthSocialProvider as AuthSocialProvider_alias_1 }
|
|
616
|
+
export { AuthSocialProvider as AuthSocialProvider_alias_2 }
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Transactional "verify your email" page. Mostly visual — composes the
|
|
620
|
+
* `Empty` primitive with a mail icon plus an optional resend button. The
|
|
621
|
+
* resend button is hidden when `adapter.resendMagicLink` is absent. Rate-
|
|
622
|
+
* limit pressure handled client-side via a cooldown timer.
|
|
623
|
+
*/
|
|
624
|
+
declare function AuthVerifyEmail({ adapter, email, resendCooldownSeconds, signInHref, className, }: AuthVerifyEmailProps): JSX.Element;
|
|
625
|
+
export { AuthVerifyEmail }
|
|
626
|
+
export { AuthVerifyEmail as AuthVerifyEmail_alias_1 }
|
|
627
|
+
export { AuthVerifyEmail as AuthVerifyEmail_alias_2 }
|
|
628
|
+
|
|
629
|
+
declare interface AuthVerifyEmailProps {
|
|
630
|
+
adapter: AuthAdapter;
|
|
631
|
+
/** Optional address shown in the description ("we sent a link to <email>"). */
|
|
632
|
+
email?: string;
|
|
633
|
+
/** Seconds to disable the resend button after each successful resend. */
|
|
634
|
+
resendCooldownSeconds?: number;
|
|
635
|
+
/** Href for the "Back to sign in" affordance. */
|
|
636
|
+
signInHref?: string;
|
|
637
|
+
className?: string;
|
|
638
|
+
}
|
|
639
|
+
export { AuthVerifyEmailProps }
|
|
640
|
+
export { AuthVerifyEmailProps as AuthVerifyEmailProps_alias_1 }
|
|
641
|
+
export { AuthVerifyEmailProps as AuthVerifyEmailProps_alias_2 }
|
|
642
|
+
|
|
643
|
+
export declare const authVerifyEmailSchema: ComponentSchemaDefinition;
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* One-time-code verification page. Renders an `InputOTP` of `length` slots
|
|
647
|
+
* and submits automatically when the code is full. Routes verification
|
|
648
|
+
* through `adapter.verifyOtp({ code, intent })`. Optional resend button
|
|
649
|
+
* calls `adapter.resendOtp({ intent })` when implemented.
|
|
650
|
+
*/
|
|
651
|
+
declare function AuthVerifyOtp({ adapter, intent, length, resendCooldownSeconds, className, onSuccess, }: AuthVerifyOtpProps): JSX.Element;
|
|
652
|
+
export { AuthVerifyOtp }
|
|
653
|
+
export { AuthVerifyOtp as AuthVerifyOtp_alias_1 }
|
|
654
|
+
export { AuthVerifyOtp as AuthVerifyOtp_alias_2 }
|
|
655
|
+
|
|
656
|
+
declare interface AuthVerifyOtpProps {
|
|
657
|
+
adapter: AuthAdapter;
|
|
658
|
+
/** Forwarded verbatim to adapter.verifyOtp({ code, intent }). */
|
|
659
|
+
intent: AuthOtpIntent;
|
|
660
|
+
/** Total number of digits in the code. Defaults to 6. */
|
|
661
|
+
length?: number;
|
|
662
|
+
/** Seconds the resend button stays disabled after each successful resend. */
|
|
663
|
+
resendCooldownSeconds?: number;
|
|
664
|
+
className?: string;
|
|
665
|
+
onSuccess?: (redirect: string | undefined) => void;
|
|
666
|
+
}
|
|
667
|
+
export { AuthVerifyOtpProps }
|
|
668
|
+
export { AuthVerifyOtpProps as AuthVerifyOtpProps_alias_1 }
|
|
669
|
+
export { AuthVerifyOtpProps as AuthVerifyOtpProps_alias_2 }
|
|
670
|
+
|
|
671
|
+
export declare const authVerifyOtpSchema: ComponentSchemaDefinition;
|
|
672
|
+
|
|
404
673
|
/** Root container for an avatar (image + fallback). */
|
|
405
674
|
declare const Avatar: React_2.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarProps & React_2.RefAttributes<HTMLSpanElement>, "ref"> & React_2.RefAttributes<HTMLSpanElement>>;
|
|
406
675
|
export { Avatar }
|
|
@@ -3059,6 +3328,17 @@ declare const mindMapSchema: ComponentSchemaDefinition;
|
|
|
3059
3328
|
export { mindMapSchema }
|
|
3060
3329
|
export { mindMapSchema as mindMapSchema_alias_1 }
|
|
3061
3330
|
|
|
3331
|
+
/**
|
|
3332
|
+
* In-memory mock adapter for docs showcase + tests. Every method delays
|
|
3333
|
+
* 400ms to simulate a network round-trip and resolves `{ ok: true }`. Do
|
|
3334
|
+
* not use in production — there is no validation, no persistence, and no
|
|
3335
|
+
* security.
|
|
3336
|
+
*/
|
|
3337
|
+
declare const mockAuthAdapter: Required<AuthAdapter>;
|
|
3338
|
+
export { mockAuthAdapter }
|
|
3339
|
+
export { mockAuthAdapter as mockAuthAdapter_alias_1 }
|
|
3340
|
+
export { mockAuthAdapter as mockAuthAdapter_alias_2 }
|
|
3341
|
+
|
|
3062
3342
|
/**
|
|
3063
3343
|
* Searchable multi-select input built on Command + Popover.
|
|
3064
3344
|
*
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React6 from 'react';
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
8
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
9
|
+
|
|
10
|
+
function cn(...inputs) {
|
|
11
|
+
return twMerge(clsx(inputs));
|
|
12
|
+
}
|
|
13
|
+
var alertVariants = cva(
|
|
14
|
+
[
|
|
15
|
+
"relative w-full rounded-lg border px-[var(--space-4,1rem)] py-[var(--space-3,0.75rem)] text-sm",
|
|
16
|
+
"transition-all duration-[var(--duration-normal,200ms)] ease-out",
|
|
17
|
+
"[&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:text-foreground",
|
|
18
|
+
"[&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px]"
|
|
19
|
+
].join(" "),
|
|
20
|
+
{
|
|
21
|
+
variants: {
|
|
22
|
+
variant: {
|
|
23
|
+
default: "border-foreground/[0.08] bg-background text-foreground",
|
|
24
|
+
destructive: "border-destructive/50 text-destructive [&>svg]:text-destructive bg-destructive/5"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
defaultVariants: { variant: "default" }
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
var Alert = React6.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
31
|
+
"div",
|
|
32
|
+
{
|
|
33
|
+
ref,
|
|
34
|
+
role: "alert",
|
|
35
|
+
className: cn(alertVariants({ variant }), className),
|
|
36
|
+
...props
|
|
37
|
+
}
|
|
38
|
+
));
|
|
39
|
+
Alert.displayName = "Alert";
|
|
40
|
+
var AlertTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
41
|
+
"h5",
|
|
42
|
+
{
|
|
43
|
+
ref,
|
|
44
|
+
className: cn("mb-[var(--space-1,0.25rem)] font-medium leading-none tracking-tight", className),
|
|
45
|
+
...props
|
|
46
|
+
}
|
|
47
|
+
));
|
|
48
|
+
AlertTitle.displayName = "AlertTitle";
|
|
49
|
+
var AlertDescription = React6.forwardRef(
|
|
50
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("text-sm [&_p]:leading-relaxed", className), ...props })
|
|
51
|
+
);
|
|
52
|
+
AlertDescription.displayName = "AlertDescription";
|
|
53
|
+
var emptyVariants = cva(
|
|
54
|
+
[
|
|
55
|
+
"flex flex-col items-center justify-center text-center",
|
|
56
|
+
"rounded-md border border-dashed border-border bg-muted/30"
|
|
57
|
+
].join(" "),
|
|
58
|
+
{
|
|
59
|
+
variants: {
|
|
60
|
+
size: {
|
|
61
|
+
sm: "gap-[var(--space-2,0.5rem)] px-[var(--space-4,1rem)] py-[var(--space-6,1.5rem)] text-sm",
|
|
62
|
+
default: "gap-[var(--space-3,0.75rem)] px-[var(--space-6,1.5rem)] py-[var(--space-8,2rem)]",
|
|
63
|
+
lg: "gap-[var(--space-4,1rem)] px-[var(--space-8,2rem)] py-[var(--space-12,3rem)]"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
defaultVariants: { size: "default" }
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
var emptyIconWrapperVariants = cva(
|
|
70
|
+
"flex shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground [&_svg]:size-5",
|
|
71
|
+
{
|
|
72
|
+
variants: {
|
|
73
|
+
size: {
|
|
74
|
+
sm: "h-9 w-9",
|
|
75
|
+
default: "h-12 w-12 [&_svg]:size-6",
|
|
76
|
+
lg: "h-16 w-16 [&_svg]:size-7"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
defaultVariants: { size: "default" }
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
var emptyTitleVariants = cva("font-semibold text-foreground", {
|
|
83
|
+
variants: {
|
|
84
|
+
size: {
|
|
85
|
+
sm: "text-sm",
|
|
86
|
+
default: "text-base",
|
|
87
|
+
lg: "text-lg"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
defaultVariants: { size: "default" }
|
|
91
|
+
});
|
|
92
|
+
var emptyDescriptionVariants = cva("max-w-md text-muted-foreground", {
|
|
93
|
+
variants: {
|
|
94
|
+
size: {
|
|
95
|
+
sm: "text-xs",
|
|
96
|
+
default: "text-sm",
|
|
97
|
+
lg: "text-base"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
defaultVariants: { size: "default" }
|
|
101
|
+
});
|
|
102
|
+
function Empty({
|
|
103
|
+
className,
|
|
104
|
+
size,
|
|
105
|
+
icon,
|
|
106
|
+
title,
|
|
107
|
+
description,
|
|
108
|
+
action,
|
|
109
|
+
titleAs = "h3",
|
|
110
|
+
ref,
|
|
111
|
+
...props
|
|
112
|
+
}) {
|
|
113
|
+
const titleId = React6.useId();
|
|
114
|
+
const TitleComp = titleAs;
|
|
115
|
+
return /* @__PURE__ */ jsxs(
|
|
116
|
+
"div",
|
|
117
|
+
{
|
|
118
|
+
ref,
|
|
119
|
+
role: "region",
|
|
120
|
+
"aria-labelledby": titleId,
|
|
121
|
+
className: cn(emptyVariants({ size }), className),
|
|
122
|
+
...props,
|
|
123
|
+
children: [
|
|
124
|
+
icon ? /* @__PURE__ */ jsx("div", { className: emptyIconWrapperVariants({ size }), "aria-hidden": "true", children: icon }) : null,
|
|
125
|
+
/* @__PURE__ */ jsx(TitleComp, { id: titleId, className: emptyTitleVariants({ size }), children: title }),
|
|
126
|
+
description ? /* @__PURE__ */ jsx("div", { className: emptyDescriptionVariants({ size }), children: description }) : null,
|
|
127
|
+
action ? /* @__PURE__ */ jsx("div", { className: "mt-[var(--space-2,0.5rem)]", children: action }) : null
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
var buttonVariants = cva(
|
|
133
|
+
[
|
|
134
|
+
"inline-flex items-center justify-center gap-[var(--gap-sm,0.5rem)] whitespace-nowrap rounded-md text-sm font-medium",
|
|
135
|
+
"transition-all duration-[var(--duration-normal,200ms)] ease-out",
|
|
136
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
137
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
138
|
+
"active:scale-[0.98]",
|
|
139
|
+
"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0"
|
|
140
|
+
].join(" "),
|
|
141
|
+
{
|
|
142
|
+
variants: {
|
|
143
|
+
variant: {
|
|
144
|
+
default: [
|
|
145
|
+
"bg-primary text-primary-foreground",
|
|
146
|
+
"shadow-sm shadow-primary/20",
|
|
147
|
+
"hover:bg-primary/90 hover:shadow-md hover:shadow-primary/25"
|
|
148
|
+
].join(" "),
|
|
149
|
+
destructive: [
|
|
150
|
+
"bg-destructive text-destructive-foreground",
|
|
151
|
+
"shadow-sm shadow-destructive/20",
|
|
152
|
+
"hover:bg-destructive/90 hover:shadow-md hover:shadow-destructive/25"
|
|
153
|
+
].join(" "),
|
|
154
|
+
outline: [
|
|
155
|
+
"border border-input bg-background",
|
|
156
|
+
"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]",
|
|
157
|
+
"hover:bg-accent hover:text-accent-foreground hover:shadow-md hover:inset-ring-foreground/12"
|
|
158
|
+
].join(" "),
|
|
159
|
+
secondary: [
|
|
160
|
+
"bg-secondary text-secondary-foreground",
|
|
161
|
+
"shadow-sm inset-ring-1 inset-ring-foreground/[0.08]",
|
|
162
|
+
"hover:bg-secondary/80 hover:shadow-md hover:inset-ring-foreground/15"
|
|
163
|
+
].join(" "),
|
|
164
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
165
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
166
|
+
},
|
|
167
|
+
size: {
|
|
168
|
+
default: "h-[var(--control-height-md,2.5rem)] px-[var(--space-4,1rem)] py-[var(--space-2,0.5rem)]",
|
|
169
|
+
sm: "h-[var(--control-height-sm,2.25rem)] rounded-md px-[var(--space-3,0.75rem)]",
|
|
170
|
+
lg: "h-[var(--control-height-lg,2.75rem)] rounded-md px-[var(--space-8,2rem)] text-base",
|
|
171
|
+
icon: "h-[var(--control-height-md,2.5rem)] w-[var(--control-height-md,2.5rem)]"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
defaultVariants: {
|
|
175
|
+
variant: "default",
|
|
176
|
+
size: "default"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
var Button = React6.forwardRef(
|
|
181
|
+
({ className, variant, size, asChild = false, loading = false, children, disabled, ...props }, ref) => {
|
|
182
|
+
const Comp = asChild ? Slot : "button";
|
|
183
|
+
return /* @__PURE__ */ jsx(
|
|
184
|
+
Comp,
|
|
185
|
+
{
|
|
186
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
187
|
+
ref,
|
|
188
|
+
disabled: disabled || loading,
|
|
189
|
+
"aria-busy": loading || void 0,
|
|
190
|
+
...props,
|
|
191
|
+
children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
192
|
+
/* @__PURE__ */ jsxs(
|
|
193
|
+
"svg",
|
|
194
|
+
{
|
|
195
|
+
className: "animate-spin h-4 w-4",
|
|
196
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
197
|
+
fill: "none",
|
|
198
|
+
viewBox: "0 0 24 24",
|
|
199
|
+
"aria-hidden": "true",
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ jsx(
|
|
202
|
+
"circle",
|
|
203
|
+
{
|
|
204
|
+
className: "opacity-25",
|
|
205
|
+
cx: "12",
|
|
206
|
+
cy: "12",
|
|
207
|
+
r: "10",
|
|
208
|
+
stroke: "currentColor",
|
|
209
|
+
strokeWidth: "4"
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
/* @__PURE__ */ jsx(
|
|
213
|
+
"path",
|
|
214
|
+
{
|
|
215
|
+
className: "opacity-75",
|
|
216
|
+
fill: "currentColor",
|
|
217
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
),
|
|
223
|
+
children
|
|
224
|
+
] }) : children
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
Button.displayName = "Button";
|
|
230
|
+
var Input = React6.forwardRef(
|
|
231
|
+
({ className, type, ...props }, ref) => {
|
|
232
|
+
return /* @__PURE__ */ jsx(
|
|
233
|
+
"input",
|
|
234
|
+
{
|
|
235
|
+
type,
|
|
236
|
+
className: cn(
|
|
237
|
+
"flex h-[var(--control-height-md,2.5rem)] w-full rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm",
|
|
238
|
+
"transition-all duration-[var(--duration-normal,200ms)] ease-out",
|
|
239
|
+
// inset-ring gives a self-borne edge so the input field is visible on flat
|
|
240
|
+
// surfaces (token border alone is too low-contrast on bg-background=white).
|
|
241
|
+
"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]",
|
|
242
|
+
"file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground",
|
|
243
|
+
"placeholder:text-muted-foreground",
|
|
244
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
245
|
+
"focus-visible:shadow-md focus-visible:border-ring/50",
|
|
246
|
+
"hover:border-ring/30 hover:shadow-md",
|
|
247
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
248
|
+
className
|
|
249
|
+
),
|
|
250
|
+
ref,
|
|
251
|
+
...props
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
Input.displayName = "Input";
|
|
257
|
+
var labelVariants = cva(
|
|
258
|
+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
259
|
+
);
|
|
260
|
+
var Label = React6.forwardRef(
|
|
261
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props })
|
|
262
|
+
);
|
|
263
|
+
Label.displayName = "Label";
|
|
264
|
+
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
265
|
+
var MailIcon = () => /* @__PURE__ */ jsxs(
|
|
266
|
+
"svg",
|
|
267
|
+
{
|
|
268
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
269
|
+
viewBox: "0 0 24 24",
|
|
270
|
+
fill: "none",
|
|
271
|
+
stroke: "currentColor",
|
|
272
|
+
strokeWidth: 2,
|
|
273
|
+
strokeLinecap: "round",
|
|
274
|
+
strokeLinejoin: "round",
|
|
275
|
+
"aria-hidden": "true",
|
|
276
|
+
children: [
|
|
277
|
+
/* @__PURE__ */ jsx("rect", { width: 20, height: 16, x: 2, y: 4, rx: 2 }),
|
|
278
|
+
/* @__PURE__ */ jsx("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
function AuthForgotPassword({
|
|
283
|
+
adapter,
|
|
284
|
+
signInHref = "/sign-in",
|
|
285
|
+
className,
|
|
286
|
+
onSuccess
|
|
287
|
+
}) {
|
|
288
|
+
const [email, setEmail] = React6.useState("");
|
|
289
|
+
const [submitting, setSubmitting] = React6.useState(false);
|
|
290
|
+
const [error, setError] = React6.useState(null);
|
|
291
|
+
const [submittedEmail, setSubmittedEmail] = React6.useState(null);
|
|
292
|
+
async function handleSubmit(e) {
|
|
293
|
+
e.preventDefault();
|
|
294
|
+
if (!EMAIL_REGEX.test(email)) {
|
|
295
|
+
setError({ code: "invalid_email", message: "Enter a valid email address." });
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (!adapter.requestPasswordReset) {
|
|
299
|
+
console.warn(
|
|
300
|
+
"[AuthForgotPassword] adapter.requestPasswordReset is not implemented \u2014 wire it up before exposing the form."
|
|
301
|
+
);
|
|
302
|
+
setError({
|
|
303
|
+
code: "unimplemented",
|
|
304
|
+
message: "Password reset is currently unavailable. Please try again later."
|
|
305
|
+
});
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
setError(null);
|
|
309
|
+
setSubmitting(true);
|
|
310
|
+
try {
|
|
311
|
+
const result = await adapter.requestPasswordReset({ email });
|
|
312
|
+
if (!result.ok) {
|
|
313
|
+
setError(result.error ?? { code: "unknown", message: "Couldn't send reset link." });
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
setSubmittedEmail(email);
|
|
317
|
+
onSuccess?.();
|
|
318
|
+
} finally {
|
|
319
|
+
setSubmitting(false);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (submittedEmail) {
|
|
323
|
+
return /* @__PURE__ */ jsx(
|
|
324
|
+
"div",
|
|
325
|
+
{
|
|
326
|
+
className: cn(
|
|
327
|
+
"flex min-h-svh items-center justify-center p-6 sm:p-10",
|
|
328
|
+
className
|
|
329
|
+
),
|
|
330
|
+
children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-sm", children: /* @__PURE__ */ jsx(
|
|
331
|
+
Empty,
|
|
332
|
+
{
|
|
333
|
+
icon: /* @__PURE__ */ jsx(MailIcon, {}),
|
|
334
|
+
title: "Check your inbox",
|
|
335
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
336
|
+
"We sent a password-reset link to",
|
|
337
|
+
" ",
|
|
338
|
+
/* @__PURE__ */ jsx("strong", { className: "text-foreground", children: submittedEmail }),
|
|
339
|
+
". The link expires in 60 minutes."
|
|
340
|
+
] }),
|
|
341
|
+
action: /* @__PURE__ */ jsx(Button, { variant: "outline", asChild: true, children: /* @__PURE__ */ jsx("a", { href: signInHref, children: "Back to sign in" }) })
|
|
342
|
+
}
|
|
343
|
+
) })
|
|
344
|
+
}
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex min-h-svh items-center justify-center p-6 sm:p-10", className), children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm space-y-6", children: [
|
|
348
|
+
/* @__PURE__ */ jsxs("header", { className: "space-y-2 text-center", children: [
|
|
349
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: "Reset your password" }),
|
|
350
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Enter your email and we\u2019ll send you a link to set a new password." })
|
|
351
|
+
] }),
|
|
352
|
+
error ? /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
|
|
353
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: "Couldn\u2019t send reset link" }),
|
|
354
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: error.message })
|
|
355
|
+
] }) : null,
|
|
356
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", noValidate: true, children: [
|
|
357
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
358
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "auth-forgot-email", children: "Email" }),
|
|
359
|
+
/* @__PURE__ */ jsx(
|
|
360
|
+
Input,
|
|
361
|
+
{
|
|
362
|
+
id: "auth-forgot-email",
|
|
363
|
+
type: "email",
|
|
364
|
+
autoComplete: "email",
|
|
365
|
+
required: true,
|
|
366
|
+
value: email,
|
|
367
|
+
onChange: (e) => setEmail(e.target.value),
|
|
368
|
+
disabled: submitting
|
|
369
|
+
}
|
|
370
|
+
)
|
|
371
|
+
] }),
|
|
372
|
+
/* @__PURE__ */ jsx(
|
|
373
|
+
Button,
|
|
374
|
+
{
|
|
375
|
+
type: "submit",
|
|
376
|
+
className: "w-full",
|
|
377
|
+
disabled: submitting,
|
|
378
|
+
loading: submitting,
|
|
379
|
+
children: submitting ? "Sending link" : "Send reset link"
|
|
380
|
+
}
|
|
381
|
+
)
|
|
382
|
+
] }),
|
|
383
|
+
/* @__PURE__ */ jsxs("p", { className: "text-center text-sm text-muted-foreground", children: [
|
|
384
|
+
"Remembered your password?",
|
|
385
|
+
" ",
|
|
386
|
+
/* @__PURE__ */ jsx(
|
|
387
|
+
"a",
|
|
388
|
+
{
|
|
389
|
+
href: signInHref,
|
|
390
|
+
className: "font-medium text-foreground underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded",
|
|
391
|
+
children: "Sign in"
|
|
392
|
+
}
|
|
393
|
+
)
|
|
394
|
+
] })
|
|
395
|
+
] }) });
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export { AuthForgotPassword };
|
|
399
|
+
//# sourceMappingURL=auth-forgot-password.js.map
|
|
400
|
+
//# sourceMappingURL=auth-forgot-password.js.map
|