@llmnative/react 2.1.0 → 2.2.1

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.
Files changed (39) hide show
  1. package/dist/index.css +1 -1
  2. package/dist/index.js +21 -21
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +10322 -8474
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/types/src/App.d.ts +10 -1
  7. package/dist/types/src/I18n.d.ts +93 -0
  8. package/dist/types/src/components/auth/AuthGate.d.ts +26 -0
  9. package/dist/types/src/components/auth/AuthLayout.d.ts +38 -0
  10. package/dist/types/src/components/auth/ForgotPassword.d.ts +19 -0
  11. package/dist/types/src/components/auth/OneTimeCodeInput.d.ts +27 -0
  12. package/dist/types/src/components/auth/ResetPassword.d.ts +31 -0
  13. package/dist/types/src/components/auth/SignIn.d.ts +42 -0
  14. package/dist/types/src/components/auth/SignUp.d.ts +43 -0
  15. package/dist/types/src/components/auth/VerifyCode.d.ts +32 -0
  16. package/dist/types/src/components/auth/VerifyEmail.d.ts +31 -0
  17. package/dist/types/src/components/auth/index.d.ts +12 -0
  18. package/dist/types/src/components/auth/providers.d.ts +22 -0
  19. package/dist/types/src/components/auth/shared.d.ts +124 -0
  20. package/dist/types/src/components/auth/useAuthFlows.d.ts +46 -0
  21. package/dist/types/src/index.d.ts +5 -1
  22. package/dist/types/src/providers/auth/AuthProvider.d.ts +51 -0
  23. package/dist/types/src/providers/auth/firebase/FirebaseAuthProvider.d.ts +8 -1
  24. package/dist/types/src/providers/auth/github/GitHubAuthProvider.d.ts +2 -0
  25. package/dist/types/src/providers/auth/mock/MockAuthProvider.d.ts +55 -0
  26. package/dist/types/src/providers/auth/supabase/SupabaseAuthProvider.d.ts +16 -1
  27. package/dist/types/src/providers/manifest.d.ts +4 -1
  28. package/llms-full.txt +66 -2
  29. package/package.json +1 -1
  30. package/scripts/cli/setup-project.js +678 -667
  31. package/templates/_shared/conf/access.tsx +23 -0
  32. package/templates/_shared/pages/access/ForgotPasswordPage.tsx +13 -0
  33. package/templates/_shared/pages/access/ResetPasswordPage.tsx +19 -0
  34. package/templates/_shared/pages/access/SignInPage.tsx +21 -0
  35. package/templates/_shared/pages/access/SignUpPage.tsx +23 -0
  36. package/templates/_shared/pages/access/VerifyEmailPage.tsx +20 -0
  37. package/templates/_shared/pages/access/paths.ts +12 -0
  38. package/templates/_shared/sections/Footer.tsx +9 -9
  39. package/templates/_shared/sections/Header.tsx +26 -24
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { type AuthGateProps } from "./components/auth/AuthGate";
2
3
  import { AppThemeProviderConfig } from "./Theme";
3
4
  import { AIConfig, DropboxConfig, ProxyConfig, FirebaseConfig, ScrapeConfig } from "./Config";
4
5
  import type { AIProviderAdapter } from "./providers/ai";
@@ -18,6 +19,8 @@ interface MenuItem {
18
19
  icon?: string;
19
20
  /** A route only, never an entry of a menu, title or not (CR-126): a page reached by a link. */
20
21
  hidden?: boolean;
22
+ /** Open without a session even when `<App authGate>` is set (CR-127): sign up, the links of an email. */
23
+ public?: boolean;
21
24
  children?: MenuItem[];
22
25
  page?: React.ComponentType;
23
26
  layout?: React.ComponentType;
@@ -107,6 +110,12 @@ export type AppProps = AppProviderProps & {
107
110
  }>;
108
111
  LayoutDefault?: React.ComponentType;
109
112
  menuConfig: MenuConfig;
113
+ /**
114
+ * Puts every route behind an `AuthGate` (CR-127): without a session the sign-in shows in place of the
115
+ * page, layout included, and the address does not change. `true` for the default sign-in, or the props
116
+ * of the gate (`fallback`, `allow`, `denied`, …). A route with `public: true` stays open.
117
+ */
118
+ authGate?: boolean | Omit<AuthGateProps, 'children'>;
110
119
  };
111
120
  export declare const setStaticMenu: (config: MenuConfig) => void;
112
121
  export declare const getStaticMenu: (type: string) => MenuItem[];
@@ -126,7 +135,7 @@ export declare const getContextMenu: () => string[];
126
135
  * you need the provider stack without the routing layer (e.g. tests, Storybook).
127
136
  */
128
137
  export declare function AppProvider({ contextProviders, providers, appName, scrapeConfig, iconProvider, googleMaps, themeProvider, i18n, children, errorReportUrl, debug, basename, }: AppProviderProps): React.JSX.Element;
129
- declare function App({ importPage, LayoutDefault, menuConfig, children, ...providerProps }: AppProps): React.JSX.Element;
138
+ declare function App({ importPage, LayoutDefault, menuConfig, authGate, children, ...providerProps }: AppProps): React.JSX.Element;
130
139
  /**
131
140
  * Whether a route of `menuConfig` is a page to navigate to: it has a title, it is not `hidden`, and its path has
132
141
  * no parameter (`/invite/:token`) and no wildcard (`*`). The others are routes only, never entries of a menu
@@ -14,6 +14,8 @@ export interface I18nDict {
14
14
  next: string;
15
15
  notFoundMessage: string;
16
16
  goHome: string;
17
+ /** The button that opens the menu on a small screen (the header of the scaffold). */
18
+ openNavigation: string;
17
19
  };
18
20
  auth: {
19
21
  signIn: string;
@@ -24,6 +26,97 @@ export interface I18nDict {
24
26
  notConfigured: string;
25
27
  notImplemented: string;
26
28
  };
29
+ /** CR-127 — the access screens. */
30
+ access: {
31
+ email: string;
32
+ emailPlaceholder: string;
33
+ password: string;
34
+ newPassword: string;
35
+ name: string;
36
+ showPassword: string;
37
+ hidePassword: string;
38
+ or: string;
39
+ continue: string;
40
+ backToSignIn: string;
41
+ emailRequired: string;
42
+ emailInvalid: string;
43
+ passwordRequired: string;
44
+ nameRequired: string;
45
+ signInTitle: string;
46
+ signInTitleApp: string;
47
+ signInDescription: string;
48
+ signInSubmit: string;
49
+ forgotPassword: string;
50
+ noAccount: string;
51
+ signUpLink: string;
52
+ continueWith: string;
53
+ codeRequest: string;
54
+ usePassword: string;
55
+ useCode: string;
56
+ signUpTitle: string;
57
+ signUpDescription: string;
58
+ signUpSubmit: string;
59
+ haveAccount: string;
60
+ signInLink: string;
61
+ terms: string;
62
+ termsRequired: string;
63
+ passwordRules: string;
64
+ ruleLength: string;
65
+ ruleNumber: string;
66
+ ruleCase: string;
67
+ ruleSymbol: string;
68
+ ruleMet: string;
69
+ ruleNotMet: string;
70
+ checkEmailTitle: string;
71
+ checkEmailSignUp: string;
72
+ checkEmailHint: string;
73
+ resend: string;
74
+ resendIn: string;
75
+ resent: string;
76
+ useOtherEmail: string;
77
+ forgotTitle: string;
78
+ forgotDescription: string;
79
+ forgotSubmit: string;
80
+ forgotSent: string;
81
+ resetTitle: string;
82
+ resetDescription: string;
83
+ resetDescriptionFor: string;
84
+ resetSubmit: string;
85
+ resetDoneTitle: string;
86
+ resetDone: string;
87
+ linkExpiredTitle: string;
88
+ linkExpired: string;
89
+ requestNewLink: string;
90
+ verifyTitle: string;
91
+ verifyPending: string;
92
+ verifyPendingNoEmail: string;
93
+ verifyChecking: string;
94
+ verifyDoneTitle: string;
95
+ verifyDone: string;
96
+ verifiedContinue: string;
97
+ notVerifiedYet: string;
98
+ codeTitle: string;
99
+ codeDescription: string;
100
+ codeLabel: string;
101
+ codeDigit: string;
102
+ codeSubmit: string;
103
+ codeNotReceived: string;
104
+ deniedTitle: string;
105
+ denied: string;
106
+ signInOther: string;
107
+ errorGeneric: string;
108
+ errorCredentials: string;
109
+ errorEmailInUse: string;
110
+ errorWeakPassword: string;
111
+ errorInvalidEmail: string;
112
+ errorTooManyRequests: string;
113
+ errorNetwork: string;
114
+ errorInvalidCode: string;
115
+ errorExpiredLink: string;
116
+ errorDisabled: string;
117
+ errorCancelled: string;
118
+ errorNotSupported: string;
119
+ };
27
120
  form: {
28
121
  headerAdd: string;
29
122
  headerEdit: string;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import type { UserProfile } from '../../providers/auth/AuthProvider';
3
+ export interface AuthGateProps {
4
+ /** The page, shown only to a signed-in (and allowed) user. */
5
+ children?: React.ReactNode;
6
+ /**
7
+ * What shows instead of the page without a session: your `<SignIn …/>`. Default: a `SignIn` bound to
8
+ * the auth provider (`useAuthFlows`). The address does not change: once signed in, the page appears.
9
+ */
10
+ fallback?: React.ReactNode;
11
+ /** The auth provider of the app to ask. Default: the default one. */
12
+ provider?: string;
13
+ /** While the session of the last visit is restored. Default: a spinner in the middle of the page. */
14
+ loading?: React.ReactNode;
15
+ /** Whether a signed-in user may see the pages (a role, an invitation). Default: everyone signed in. */
16
+ allow?: (user: UserProfile) => boolean | Promise<boolean>;
17
+ /** For a signed-in user who is not allowed. Default: "No access" with "Sign in with another account". */
18
+ denied?: React.ReactNode;
19
+ }
20
+ /**
21
+ * Shows its page only to a signed-in user (CR-127); without a session it shows the sign-in in its place,
22
+ * without a redirect, so the address stays the one that was opened and the page appears once signed in.
23
+ * `<App authGate={…}>` puts every route behind one, except those marked `public`.
24
+ */
25
+ export declare function AuthGate({ children, fallback, provider, loading, allow, denied }: AuthGateProps): React.JSX.Element;
26
+ export default AuthGate;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ export type AuthLayoutTone = 'neutral' | 'success' | 'warning' | 'danger';
3
+ export interface AuthLayoutProps {
4
+ /** The heading of the screen (one `h1`). */
5
+ title: React.ReactNode;
6
+ /** One or two sentences under the title. */
7
+ description?: React.ReactNode;
8
+ /** An icon above the title, for a state (an email sent, a link expired). */
9
+ icon?: string;
10
+ /** The color of that icon. Default `neutral`. */
11
+ tone?: AuthLayoutTone;
12
+ /** The mark above the card: a `<Brand>`, a logo. */
13
+ brand?: React.ReactNode;
14
+ /** Top right of the page: a `ThemeSwitcher`, a `LocaleSwitcher`. */
15
+ toolbar?: React.ReactNode;
16
+ /** Under the card: another way in ("Don't have an account? Create one"). */
17
+ below?: React.ReactNode;
18
+ /** Bottom of the page: legal links, the copyright. */
19
+ footer?: React.ReactNode;
20
+ /**
21
+ * When it changes, the focus moves to the title, so a screen reader announces the new step
22
+ * (an email sent, a code to type). Default: the title itself, when it is a string.
23
+ */
24
+ focusKey?: string | number;
25
+ children?: React.ReactNode;
26
+ className?: string;
27
+ }
28
+ /**
29
+ * The frame of an access screen (CR-127): the brand, a card in the middle of the page with the title,
30
+ * the description and the content, then another way in and the footer. In the colors of the theme,
31
+ * light and dark; on a phone the card becomes the page.
32
+ */
33
+ export declare function AuthLayout({ title, description, icon, tone, brand, toolbar, below, footer, focusKey, children, className, }: AuthLayoutProps): React.JSX.Element;
34
+ /** The content of a screen in its `AuthLayout`, or alone when `bare`. */
35
+ export declare function AuthFrame({ bare, ...props }: AuthLayoutProps & {
36
+ bare?: boolean;
37
+ }): React.JSX.Element;
38
+ export default AuthLayout;
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { type AuthLink, type AuthScreenProps } from './shared';
3
+ export interface ForgotPasswordProps extends AuthScreenProps {
4
+ /** Sends the link to choose a new password. */
5
+ onSendReset: (email: string) => Promise<unknown>;
6
+ /** "Back to sign in". */
7
+ signInLink?: AuthLink;
8
+ defaultEmail?: string;
9
+ /** Seconds before a new link can be asked. Default `30`. */
10
+ resendSeconds?: number;
11
+ title?: React.ReactNode;
12
+ description?: React.ReactNode;
13
+ }
14
+ /**
15
+ * The screen to recover a password (CR-127): the email, then the same answer whether the account
16
+ * exists or not (it never tells who has an account), a new send after a wait.
17
+ */
18
+ export declare function ForgotPassword({ onSendReset, signInLink, defaultEmail, resendSeconds, title, description, errorMessage, brand, toolbar, footer, bare, className, }: ForgotPasswordProps): React.JSX.Element;
19
+ export default ForgotPassword;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ export interface OneTimeCodeInputProps {
3
+ /** The code typed so far (digits or letters, without spaces). */
4
+ value: string;
5
+ onChange: (value: string) => void;
6
+ /** Called once every box is filled (typed, pasted or filled by the phone). */
7
+ onComplete?: (code: string) => void;
8
+ /** How many characters. Default `6`. */
9
+ length?: number;
10
+ /** `numeric` (default) shows the number keyboard on a phone; `alphanumeric` takes letters too. */
11
+ mode?: 'numeric' | 'alphanumeric';
12
+ disabled?: boolean;
13
+ /** The code was refused: the boxes say it. */
14
+ invalid?: boolean;
15
+ autoFocus?: boolean;
16
+ /** The name of the group for a screen reader. Default: "Sign-in code". */
17
+ label?: string;
18
+ /** The id of the text that describes the code (where it was sent), or of its error. */
19
+ describedBy?: string;
20
+ className?: string;
21
+ }
22
+ /**
23
+ * A one-time code in boxes (CR-127): typing moves to the next box, Backspace to the previous one, a
24
+ * pasted code (or the one the phone suggests from an SMS or email, `one-time-code`) fills them all.
25
+ */
26
+ export declare function OneTimeCodeInput({ value, onChange, onComplete, length, mode, disabled, invalid, autoFocus, label, describedBy, className, }: OneTimeCodeInputProps): React.JSX.Element;
27
+ export default OneTimeCodeInput;
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { type AuthLink, type AuthScreenProps, type PasswordRules } from './shared';
3
+ export interface ResetPasswordProps extends AuthScreenProps {
4
+ /** Saves the new password (with the code of the link, which your function knows). */
5
+ onResetPassword: (password: string) => Promise<unknown>;
6
+ /** The account, when the link says it. */
7
+ email?: string;
8
+ /** The link has no code, or it is known to be expired: the screen says so at once. */
9
+ invalidLink?: boolean;
10
+ /** What the password needs. Default: at least 8 characters. */
11
+ passwordRules?: PasswordRules;
12
+ /** "Back to sign in", and the button after the password is saved. */
13
+ signInLink?: AuthLink;
14
+ /** "Ask for a new link" when the link is expired (the screen of `ForgotPassword`). */
15
+ requestNewLink?: AuthLink;
16
+ title?: React.ReactNode;
17
+ description?: React.ReactNode;
18
+ /** Called after the password is saved. */
19
+ onDone?: () => void;
20
+ }
21
+ /**
22
+ * The screen of a new password (CR-127), opened by the link of the email: the password with its
23
+ * requirements, then "Password changed"; an expired link says so and offers a new one.
24
+ */
25
+ export declare function ResetPassword({ onResetPassword, email, invalidLink, passwordRules, signInLink, requestNewLink, title, description, onDone, errorMessage, brand, toolbar, footer, bare, className, }: ResetPasswordProps): React.JSX.Element;
26
+ /** The one action of a state (sign in, ask a new link), as a full-width button. */
27
+ export declare function PrimaryLink({ to, children }: {
28
+ to: AuthLink;
29
+ children: React.ReactNode;
30
+ }): React.JSX.Element;
31
+ export default ResetPassword;
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { type AuthProviderOption } from './providers';
3
+ import { type AuthLink, type AuthScreenProps } from './shared';
4
+ export interface SignInProps extends AuthScreenProps {
5
+ /** Signs in with email and password. Without it there is no password. */
6
+ onPasswordSignIn?: (credentials: {
7
+ email: string;
8
+ password: string;
9
+ }) => Promise<unknown>;
10
+ /** Sends a code by email. With `onVerifyCode`, the screen offers to sign in with a code. */
11
+ onRequestCode?: (email: string) => Promise<unknown>;
12
+ /** Signs in with the code received by email. */
13
+ onVerifyCode?: (email: string, code: string) => Promise<unknown>;
14
+ /** The ways in through other services, in this order: `['google', 'apple']`. */
15
+ providers?: AuthProviderOption[];
16
+ /** Signs in with a provider of `providers`. */
17
+ onProviderSignIn?: (id: string) => Promise<unknown>;
18
+ /** The first way offered when there are password and code. Default `password`. */
19
+ method?: 'password' | 'code';
20
+ /** Digits of the code. Default `6`. */
21
+ codeLength?: number;
22
+ /** Seconds before a new code can be asked. Default `30`. */
23
+ resendSeconds?: number;
24
+ /** "Forgot password?" next to the password. */
25
+ forgotPasswordLink?: AuthLink;
26
+ /** "Don't have an account? Create one" under the card. */
27
+ signUpLink?: AuthLink;
28
+ /** The email already typed (an invitation, the last visit). */
29
+ defaultEmail?: string;
30
+ /** The name of the app in the title: "Sign in to <appName>". */
31
+ appName?: string;
32
+ title?: React.ReactNode;
33
+ description?: React.ReactNode;
34
+ /** Called once signed in (the gate shows the page by itself). */
35
+ onSignedIn?: () => void;
36
+ }
37
+ /**
38
+ * The sign-in screen (CR-127): providers, then email and password or a code by email, in any
39
+ * combination. An error of a function appears in the screen, translated, and what was typed stays.
40
+ */
41
+ export declare function SignIn({ onPasswordSignIn, onRequestCode, onVerifyCode, providers, onProviderSignIn, method: initialMethod, codeLength, resendSeconds, forgotPasswordLink, signUpLink, defaultEmail, appName, title, description, onSignedIn, errorMessage, brand, toolbar, footer, bare, className, }: SignInProps): React.JSX.Element;
42
+ export default SignIn;
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import type { AuthSignUpResult } from '../../providers/auth/AuthProvider';
3
+ import { type AuthProviderOption } from './providers';
4
+ import { type AuthLink, type AuthScreenProps, type PasswordRules } from './shared';
5
+ export interface SignUpInput {
6
+ name?: string;
7
+ email: string;
8
+ password: string;
9
+ }
10
+ export interface SignUpProps extends AuthScreenProps {
11
+ /**
12
+ * Creates the account. Return `{ needsEmailVerification: true }` (what `signUp` of the adapter
13
+ * returns) to show "Check your email"; anything else calls `onSignedUp`.
14
+ */
15
+ onSignUp: (input: SignUpInput) => Promise<Partial<AuthSignUpResult> | void | unknown>;
16
+ /** Sends again the link that confirms the email. */
17
+ onResendVerification?: (email: string) => Promise<unknown>;
18
+ /** Asks the full name. Default `true`. */
19
+ askName?: boolean;
20
+ /**
21
+ * A box to tick before creating the account: `true` for the default sentence, or your own (with the
22
+ * links to your terms and privacy policy).
23
+ */
24
+ terms?: boolean | React.ReactNode;
25
+ /** What the password needs. Default: at least 8 characters. */
26
+ passwordRules?: PasswordRules;
27
+ providers?: AuthProviderOption[];
28
+ onProviderSignIn?: (id: string) => Promise<unknown>;
29
+ /** "Already have an account? Sign in" under the card. */
30
+ signInLink?: AuthLink;
31
+ /** Seconds before a new link can be asked. Default `30`. */
32
+ resendSeconds?: number;
33
+ title?: React.ReactNode;
34
+ description?: React.ReactNode;
35
+ /** Called when the account works at once (no email to confirm). */
36
+ onSignedUp?: () => void;
37
+ }
38
+ /**
39
+ * The screen that creates an account (CR-127): name, email, a password with its requirements shown
40
+ * while typing, the terms; then "Check your email" when the address must be confirmed.
41
+ */
42
+ export declare function SignUp({ onSignUp, onResendVerification, askName, terms, passwordRules, providers, onProviderSignIn, signInLink, resendSeconds, title, description, onSignedUp, errorMessage, brand, toolbar, footer, bare, className, }: SignUpProps): React.JSX.Element;
43
+ export default SignUp;
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { type AuthScreenProps } from './shared';
3
+ export interface VerifyCodeProps extends AuthScreenProps {
4
+ /** Where the code was sent: shown to the person. */
5
+ email?: string;
6
+ /** Checks the code; throw to refuse it (`AuthFlowError('invalidCode')`). */
7
+ onVerify: (code: string) => Promise<unknown>;
8
+ /** Sends a new code. Without it there is no "Send it again". */
9
+ onResend?: () => Promise<unknown>;
10
+ /** Goes back to type another email. */
11
+ onChangeEmail?: () => void;
12
+ /** Default `6`. */
13
+ length?: number;
14
+ mode?: 'numeric' | 'alphanumeric';
15
+ /** Seconds before a new code can be asked. Default `30`. */
16
+ resendSeconds?: number;
17
+ title?: React.ReactNode;
18
+ description?: React.ReactNode;
19
+ /** Called after the code was accepted. */
20
+ onVerified?: () => void;
21
+ }
22
+ /**
23
+ * The screen of a one-time code (CR-127): where it was sent, the boxes, sent as soon as it is complete,
24
+ * a new code after a wait, another email.
25
+ */
26
+ export declare function VerifyCode({ email, onVerify, onResend, onChangeEmail, length, mode, resendSeconds, title, description, onVerified, errorMessage, brand, toolbar, footer, bare, className, }: VerifyCodeProps): React.JSX.Element;
27
+ /** A sentence with the email in it, the email in bold. */
28
+ export declare function EmailIn({ text, email }: {
29
+ text: string;
30
+ email: string;
31
+ }): React.JSX.Element;
32
+ export default VerifyCode;
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { type AuthLink, type AuthScreenProps } from './shared';
3
+ export interface VerifyEmailProps extends AuthScreenProps {
4
+ /** The code of the link (`oobCode`, `token_hash`, …): with `onVerify` the screen confirms it at once. */
5
+ code?: string | null;
6
+ /** Confirms the email with the code of the link. */
7
+ onVerify?: (code: string) => Promise<unknown>;
8
+ /** The address waiting for its confirmation. */
9
+ email?: string;
10
+ /** Sends the link again. */
11
+ onResend?: () => Promise<unknown>;
12
+ /**
13
+ * "I've confirmed it": checks again (e.g. reloads the user). `false` means still not confirmed;
14
+ * anything else calls `onVerified`.
15
+ */
16
+ onContinue?: () => Promise<boolean | void>;
17
+ /** The button after the email is confirmed (the app, or the sign in). */
18
+ continueLink?: AuthLink;
19
+ signInLink?: AuthLink;
20
+ /** Seconds before a new link can be asked. Default `30`. */
21
+ resendSeconds?: number;
22
+ /** Called once the email is confirmed. */
23
+ onVerified?: () => void;
24
+ }
25
+ /**
26
+ * The activation of an account (CR-127): opened by the link of the email it confirms the code at once
27
+ * (confirming, done, link expired); otherwise it waits for the confirmation, with a new send after a
28
+ * wait and "I've confirmed it".
29
+ */
30
+ export declare function VerifyEmail({ code, onVerify, email, onResend, onContinue, continueLink, signInLink, resendSeconds, onVerified, errorMessage, brand, toolbar, footer, bare, className, }: VerifyEmailProps): React.JSX.Element;
31
+ export default VerifyEmail;
@@ -0,0 +1,12 @@
1
+ export { AuthLayout, type AuthLayoutProps, type AuthLayoutTone } from './AuthLayout';
2
+ export { SignIn, type SignInProps } from './SignIn';
3
+ export { SignUp, type SignUpProps, type SignUpInput } from './SignUp';
4
+ export { ForgotPassword, type ForgotPasswordProps } from './ForgotPassword';
5
+ export { ResetPassword, type ResetPasswordProps } from './ResetPassword';
6
+ export { VerifyEmail, type VerifyEmailProps } from './VerifyEmail';
7
+ export { VerifyCode, type VerifyCodeProps } from './VerifyCode';
8
+ export { OneTimeCodeInput, type OneTimeCodeInputProps } from './OneTimeCodeInput';
9
+ export { AuthGate, type AuthGateProps } from './AuthGate';
10
+ export { useAuthFlows, useAuthSession, linkCode, type AuthFlows, type AuthFlowsOptions, type AuthSession } from './useAuthFlows';
11
+ export { authErrorMessage, authErrorReason, type AuthLink, type AuthScreenProps, type PasswordRules } from './shared';
12
+ export { type AuthProviderOption } from './providers';
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ /** A way in through another service: its id (`google`, `apple`, `github`, `microsoft`, …), or the whole option. */
3
+ export type AuthProviderOption = string | {
4
+ id: string;
5
+ /** The name shown, "Continue with <label>". Default: the known name of the id. */
6
+ label?: string;
7
+ /** The mark of the service. Default: the one of a known id. */
8
+ icon?: React.ReactNode;
9
+ };
10
+ export declare function resolveProvider(option: AuthProviderOption): {
11
+ id: string;
12
+ label: string;
13
+ icon: string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null;
14
+ };
15
+ /** The buttons "Continue with …", one per provider, one under the other. */
16
+ export declare function ProviderButtons({ providers, onSelect, pending, disabled, }: {
17
+ providers: AuthProviderOption[];
18
+ onSelect: (id: string) => void;
19
+ /** The id of the provider being opened. */
20
+ pending?: string | null;
21
+ disabled?: boolean;
22
+ }): React.JSX.Element;
@@ -0,0 +1,124 @@
1
+ import React from 'react';
2
+ import { type I18nDict } from '../../I18n';
3
+ import { type AuthErrorReason } from '../../providers/auth/AuthProvider';
4
+ export type AccessDict = I18nDict['access'];
5
+ /** The texts of the access screens, in the language of the app. */
6
+ export declare const useAccessText: () => AccessDict;
7
+ /**
8
+ * A link to another screen: a path of the app (a `Link`, no reload) or a function (a button that
9
+ * looks like a link, e.g. to switch the screen in place).
10
+ */
11
+ export type AuthLink = string | (() => void);
12
+ /** What every access screen shares: its frame. */
13
+ export interface AuthScreenProps {
14
+ /** The mark above the title: a `<Brand>`, a logo. */
15
+ brand?: React.ReactNode;
16
+ /** Top right of the page: a `ThemeSwitcher`, a `LocaleSwitcher`. */
17
+ toolbar?: React.ReactNode;
18
+ /** Bottom of the page: legal links, the copyright. */
19
+ footer?: React.ReactNode;
20
+ /** Only the content, without `AuthLayout` (inside a modal or a page of your own). */
21
+ bare?: boolean;
22
+ className?: string;
23
+ /** The message shown for an error of a function; `undefined` falls back to the translated reason. */
24
+ errorMessage?: (error: unknown) => string | undefined;
25
+ }
26
+ /**
27
+ * Why an access flow failed: the reason of an `AuthFlowError`, of a known code of Firebase or Supabase,
28
+ * a refused connection, too many requests; `generic` otherwise. Never the raw text of the service.
29
+ */
30
+ export declare function authErrorReason(error: unknown): AuthErrorReason;
31
+ /** The message of an error of an access flow, translated (see `authErrorReason`). */
32
+ export declare function authErrorMessage(error: unknown, dict: AccessDict): string;
33
+ /** Runs a function of a screen: its pending state and its error, as a message for the person. */
34
+ export declare function useAuthAction(errorMessage?: AuthScreenProps['errorMessage']): {
35
+ pending: boolean;
36
+ error: string | null;
37
+ reason: AuthErrorReason | null;
38
+ run: <T>(action: () => Promise<T>) => Promise<{
39
+ ok: true;
40
+ value: T;
41
+ } | {
42
+ ok: false;
43
+ }>;
44
+ clear: () => void;
45
+ };
46
+ export declare function emailProblem(value: string, t: AccessDict): string | undefined;
47
+ /** What a new password needs. Length first (NIST 800-63B); the others only when you ask for them. */
48
+ export interface PasswordRules {
49
+ /** Default `8`. */
50
+ minLength?: number;
51
+ number?: boolean;
52
+ mixedCase?: boolean;
53
+ symbol?: boolean;
54
+ }
55
+ export declare function passwordChecks(value: string, rules: PasswordRules, t: AccessDict): {
56
+ id: string;
57
+ label: string;
58
+ met: boolean;
59
+ }[];
60
+ /** Moves the focus to the first field with an error, after the render that shows it. */
61
+ export declare function focusFirstInvalid(form: HTMLFormElement | null): void;
62
+ /** Seconds left before a new send; `start()` begins the wait. */
63
+ export declare function useCooldown(seconds: number): [number, () => void];
64
+ export declare const authControlClass: string;
65
+ interface AuthFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'> {
66
+ label: string;
67
+ value: string;
68
+ onChange: (value: string) => void;
69
+ error?: string;
70
+ hint?: React.ReactNode;
71
+ /** Right of the label (e.g. "Forgot password?"). */
72
+ labelAside?: React.ReactNode;
73
+ /** Inside the field, at its right (e.g. the button that shows the password). */
74
+ inset?: React.ReactNode;
75
+ }
76
+ /** A field of an access screen: its label, its error announced and tied to it, its hint. */
77
+ export declare const AuthField: React.ForwardRefExoticComponent<AuthFieldProps & React.RefAttributes<HTMLInputElement>>;
78
+ interface PasswordFieldProps extends Omit<AuthFieldProps, 'type' | 'inset' | 'hint'> {
79
+ /** The requirements shown while typing (a new password). */
80
+ rules?: PasswordRules;
81
+ }
82
+ /** A password with the button that shows it, and the requirements of a new one. */
83
+ export declare const PasswordField: React.ForwardRefExoticComponent<PasswordFieldProps & React.RefAttributes<HTMLInputElement>>;
84
+ /** The button that sends the form: full width, its spinner while it waits. */
85
+ export declare const SubmitButton: ({ pending, children, disabled }: {
86
+ pending: boolean;
87
+ children: React.ReactNode;
88
+ disabled?: boolean;
89
+ }) => React.JSX.Element;
90
+ export declare const Spinner: ({ className }: {
91
+ className?: string;
92
+ }) => React.JSX.Element;
93
+ /** The error of the last attempt, announced to a screen reader. */
94
+ export declare const FormError: ({ message }: {
95
+ message: string | null;
96
+ }) => React.JSX.Element;
97
+ /** A quiet message that something happened (a code sent again). */
98
+ export declare const FormNotice: ({ message }: {
99
+ message: string | null;
100
+ }) => React.JSX.Element;
101
+ /** A link of a screen: a path of the app, or a function. */
102
+ export declare const TextLink: ({ to, children, className }: {
103
+ to: AuthLink;
104
+ children: React.ReactNode;
105
+ className?: string;
106
+ }) => React.JSX.Element;
107
+ /** A button that looks like a link (a new send, another way in). */
108
+ export declare const LinkButton: ({ onClick, disabled, children, className }: {
109
+ onClick: () => void;
110
+ disabled?: boolean;
111
+ children: React.ReactNode;
112
+ className?: string;
113
+ }) => React.JSX.Element;
114
+ /** "or", between the providers and the form. */
115
+ export declare const Divider: ({ label }: {
116
+ label: string;
117
+ }) => React.JSX.Element;
118
+ /** "Don't have an account? Create one" under the card. */
119
+ export declare const AltLine: ({ text, link, label }: {
120
+ text: string;
121
+ link?: AuthLink;
122
+ label: string;
123
+ }) => React.JSX.Element | null;
124
+ export {};
@@ -0,0 +1,46 @@
1
+ import type { AuthProviderAdapter, UserProfile } from '../../providers/auth/AuthProvider';
2
+ import type { SignInProps } from './SignIn';
3
+ import type { SignUpProps } from './SignUp';
4
+ import type { ForgotPasswordProps } from './ForgotPassword';
5
+ import type { ResetPasswordProps } from './ResetPassword';
6
+ import type { VerifyEmailProps } from './VerifyEmail';
7
+ export interface AuthSession {
8
+ /** The signed-in user, `null` without a session. */
9
+ user: UserProfile | null;
10
+ /** `false` while the session of the last visit is being restored: show neither the page nor the sign-in. */
11
+ ready: boolean;
12
+ signOut: () => Promise<void>;
13
+ adapter: AuthProviderAdapter;
14
+ }
15
+ /** Who is signed in with an auth provider of the app, and whether it is known yet (CR-127). */
16
+ export declare function useAuthSession(provider?: string): AuthSession;
17
+ export interface AuthFlowsOptions {
18
+ /** The page the confirmation link of a new account opens (your `VerifyEmail`), e.g. `/verify-email`. */
19
+ verifyEmailPath?: string;
20
+ /** The page the link to choose a new password opens (your `ResetPassword`), e.g. `/reset-password`. */
21
+ resetPasswordPath?: string;
22
+ }
23
+ export interface AuthFlows {
24
+ adapter: AuthProviderAdapter;
25
+ /** For `<SignIn {...flows.signIn} />`: password, code by email, providers, as the adapter offers them. */
26
+ signIn: Pick<SignInProps, 'onPasswordSignIn' | 'onRequestCode' | 'onVerifyCode' | 'onProviderSignIn' | 'providers'>;
27
+ /** For `<SignUp {...flows.signUp} />`; `undefined` when the adapter cannot create accounts. */
28
+ signUp?: Pick<SignUpProps, 'onSignUp' | 'onResendVerification'>;
29
+ /** For `<ForgotPassword {...flows.forgotPassword} />`; `undefined` without password reset. */
30
+ forgotPassword?: Pick<ForgotPasswordProps, 'onSendReset'>;
31
+ /** For `<ResetPassword {...flows.resetPassword(code)} />`, with the code of the link. */
32
+ resetPassword: (code: string | null | undefined) => Pick<ResetPasswordProps, 'onResetPassword' | 'invalidLink'>;
33
+ /** For `<VerifyEmail {...flows.verifyEmail} code={…} />`. */
34
+ verifyEmail: Pick<VerifyEmailProps, 'onVerify' | 'onResend'>;
35
+ }
36
+ /**
37
+ * Binds the access screens to an auth provider of the app (CR-127): each screen gets the functions of
38
+ * the methods the adapter has. An adapter that can reset a password (Firebase, Supabase, mock) signs in
39
+ * with email and password; one that cannot (Google, GitHub, Dropbox) offers its own button.
40
+ */
41
+ export declare function useAuthFlows(provider?: string, options?: AuthFlowsOptions): AuthFlows;
42
+ /**
43
+ * The code of the link an email opened, whatever the service calls it: `oobCode` (Firebase),
44
+ * `token_hash` (Supabase), `code`.
45
+ */
46
+ export declare function linkCode(search?: string | URLSearchParams): string | null;