doct-ui-auth-kit 1.0.13 → 1.0.15
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/adapters/http-auth-adapter.d.ts +13 -0
- package/dist/adapters/index.d.ts +1 -0
- package/dist/auth/index.d.ts +28 -0
- package/dist/auth-methods/apple.d.ts +19 -0
- package/dist/auth-methods/google.d.ts +5 -0
- package/dist/auth-methods/index.d.ts +2 -0
- package/dist/auth-methods/use-google-auth.d.ts +69 -0
- package/dist/components/common/back-button.d.ts +13 -0
- package/dist/components/common/default-footer.d.ts +5 -0
- package/dist/components/form/rhf-doct-phone-input.d.ts +2 -0
- package/dist/components/form/rhf-input-field.d.ts +2 -0
- package/dist/components/form/rhf-otp-input-field.d.ts +3 -0
- package/dist/components/layout/auth-layout-preset.d.ts +30 -0
- package/dist/components/layout/auth-layout-public.d.ts +17 -0
- package/dist/components/layout/auth-layout-wrapper.d.ts +42 -0
- package/dist/components/layout/auth-layout.d.ts +89 -0
- package/dist/components/layout/image-slider.d.ts +28 -0
- package/dist/components/layout/index.d.ts +8 -0
- package/dist/components/layout/main-layout.d.ts +30 -0
- package/dist/constants/brand.d.ts +9 -0
- package/dist/constants/demo-slider.d.ts +14 -0
- package/dist/constants/index.d.ts +4 -0
- package/dist/constants/layout-classes.d.ts +10 -0
- package/dist/constants/layout-presets.d.ts +10 -0
- package/dist/core/auth-api-adapter.d.ts +6 -0
- package/dist/core/auth-context.d.ts +21 -0
- package/dist/core/auth-flow.d.ts +1 -1
- package/dist/core/auth-provider.d.ts +8 -0
- package/dist/core/auth-types.d.ts +5 -0
- package/dist/core/device-detection.d.ts +19 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/core/sso-session.d.ts +35 -0
- package/dist/core/use-auth-flow-router-sync.d.ts +1 -1
- package/dist/core/use-auth-flow.d.ts +9 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/use-login-entry-form.d.ts +12 -0
- package/dist/hooks/use-main-auth-page-handlers.d.ts +9 -0
- package/dist/hooks/use-otp-verification.d.ts +3 -3
- package/dist/hooks/use-repeat-login.d.ts +9 -0
- package/dist/hooks/use-signup-form.d.ts +12 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +321 -313
- package/dist/pages/index.d.ts +8 -0
- package/dist/pages/login-entry/index.d.ts +3 -0
- package/dist/pages/login-entry/login-entry-page.d.ts +21 -0
- package/dist/pages/login-entry/login-entry.d.ts +21 -0
- package/dist/pages/main-login/index.d.ts +3 -0
- package/dist/pages/main-login/main-login-page.d.ts +16 -0
- package/dist/pages/main-login/main-login.d.ts +25 -0
- package/dist/pages/otp-verification/index.d.ts +3 -0
- package/dist/pages/otp-verification/otp-verification-page.d.ts +23 -0
- package/dist/pages/otp-verification/otp-verification.d.ts +22 -0
- package/dist/pages/repeat-login/index.d.ts +3 -0
- package/dist/pages/repeat-login/repeat-login-page.d.ts +24 -0
- package/dist/pages/repeat-login/repeat-login.d.ts +25 -0
- package/dist/pages/signup/index.d.ts +3 -0
- package/dist/pages/signup/signup-page.d.ts +6 -0
- package/dist/pages/signup/signup.d.ts +7 -0
- package/dist/pages.js +1 -1
- package/dist/{signup-page-ChXnxtSS.js → signup-page-LsYojX4-.js} +43 -38
- package/dist/types/auth/auth-api-adapter.d.ts +57 -0
- package/dist/types/auth/auth-provider.d.ts +40 -0
- package/dist/types/auth/auth-types.d.ts +70 -0
- package/dist/types/auth/device-detection.d.ts +13 -0
- package/dist/types/auth/flow.d.ts +133 -0
- package/dist/types/auth/index.d.ts +10 -0
- package/dist/types/auth/router.d.ts +60 -0
- package/dist/types/auth/sso-session.d.ts +33 -0
- package/dist/types/components/auth-layout-types.d.ts +92 -0
- package/dist/types/components/forms.d.ts +77 -0
- package/dist/types/components/index.d.ts +7 -0
- package/dist/types/components/layout-presets.d.ts +29 -0
- package/dist/types/components/layout.d.ts +57 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/pages/index.d.ts +9 -0
- package/dist/types/pages/login-form.d.ts +57 -0
- package/dist/types/pages/otp-verification.d.ts +1 -1
- package/dist/types/pages/repeat-login.d.ts +29 -0
- package/dist/types/pages/signup-form.d.ts +49 -0
- package/dist/utils/build-phone-recipient.d.ts +12 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/set-form-errors-from-zod.d.ts +11 -0
- package/dist/validations/index.d.ts +6 -0
- package/dist/validations/schemas.d.ts +87 -0
- package/package.json +110 -109
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth flow state machine types: state, actions, and context.
|
|
3
|
+
*/
|
|
4
|
+
import type { AuthStep, SSOSession, UserType } from './auth-types';
|
|
5
|
+
/** Identifier type for OTP / profile steps. */
|
|
6
|
+
export type IdentifierType = 'phone' | 'email';
|
|
7
|
+
/** Full state for the auth flow. */
|
|
8
|
+
export interface AuthFlowState {
|
|
9
|
+
step: AuthStep;
|
|
10
|
+
/** Previous step for goBack. */
|
|
11
|
+
lastStep: AuthStep;
|
|
12
|
+
/** Indian (+91) vs Foreign (non +91); drives layout and OTP routing. */
|
|
13
|
+
userType: UserType;
|
|
14
|
+
/** Current identifier value (phone or email) when in OTP or signup. */
|
|
15
|
+
identifierValue: string;
|
|
16
|
+
/** Type of identifier (phone vs email). */
|
|
17
|
+
identifierType: IdentifierType;
|
|
18
|
+
/** Masked value for display (e.g. "+91 9825910X0X"). */
|
|
19
|
+
maskedRecipient: string;
|
|
20
|
+
/** For SIGNUP_DETAILS (Indian): which field to collect (phone or email). */
|
|
21
|
+
signupCollectField: IdentifierType;
|
|
22
|
+
/** For REPEAT_LOGIN: last used method label. */
|
|
23
|
+
lastMethod: string;
|
|
24
|
+
/** Set when step is AUTHENTICATED. */
|
|
25
|
+
session: SSOSession | null;
|
|
26
|
+
/** Foreign flow: phone value when user entered phone before signup details. */
|
|
27
|
+
pendingPhone: string;
|
|
28
|
+
/** Foreign flow: signup form data for completeProfile after OTP verify. */
|
|
29
|
+
pendingFullName: string;
|
|
30
|
+
pendingEmail: string;
|
|
31
|
+
}
|
|
32
|
+
/** Pure reducer actions. */
|
|
33
|
+
export type AuthFlowAction = {
|
|
34
|
+
type: 'SET_SESSION';
|
|
35
|
+
session: SSOSession;
|
|
36
|
+
} | {
|
|
37
|
+
type: 'SET_STEP_REPEAT_LOGIN';
|
|
38
|
+
lastMethod: string;
|
|
39
|
+
maskedIdentifier: string;
|
|
40
|
+
} | {
|
|
41
|
+
type: 'SET_STEP_METHOD_SELECT';
|
|
42
|
+
} | {
|
|
43
|
+
type: 'SET_STEP_PHONE_ENTRY';
|
|
44
|
+
} | {
|
|
45
|
+
type: 'SET_STEP_EMAIL_ENTRY';
|
|
46
|
+
} | {
|
|
47
|
+
type: 'SET_STEP_OTP_VERIFICATION';
|
|
48
|
+
userType: UserType;
|
|
49
|
+
identifierType: IdentifierType;
|
|
50
|
+
value: string;
|
|
51
|
+
maskedValue: string;
|
|
52
|
+
/** Foreign flow: for completeProfile after OTP. */
|
|
53
|
+
pendingFullName?: string;
|
|
54
|
+
pendingEmail?: string;
|
|
55
|
+
pendingPhone?: string;
|
|
56
|
+
} | {
|
|
57
|
+
type: 'SET_STEP_SIGNUP_DETAILS';
|
|
58
|
+
userType: UserType;
|
|
59
|
+
/** Indian: which field to collect (phone or email). Foreign: ignored. */
|
|
60
|
+
signupCollectField: IdentifierType;
|
|
61
|
+
/** Foreign only: phone value when user entered phone before signup. */
|
|
62
|
+
pendingPhone?: string;
|
|
63
|
+
/** When coming from identifier entry (foreign): preserve for later OTP. */
|
|
64
|
+
identifierType?: IdentifierType;
|
|
65
|
+
identifierValue?: string;
|
|
66
|
+
maskedRecipient?: string;
|
|
67
|
+
} | {
|
|
68
|
+
type: 'SET_STEP_PROVIDER_PENDING';
|
|
69
|
+
} | {
|
|
70
|
+
type: 'SET_STEP_AUTHENTICATED';
|
|
71
|
+
session: SSOSession;
|
|
72
|
+
} | {
|
|
73
|
+
type: 'GO_BACK';
|
|
74
|
+
} | {
|
|
75
|
+
type: 'RESET';
|
|
76
|
+
} | {
|
|
77
|
+
type: 'SIGN_OUT';
|
|
78
|
+
};
|
|
79
|
+
/** Provider config slice exposed to flow for Google/Apple wiring. */
|
|
80
|
+
export interface AuthFlowProviderConfig {
|
|
81
|
+
google?: {
|
|
82
|
+
clientId: string;
|
|
83
|
+
enableOneTap?: boolean;
|
|
84
|
+
};
|
|
85
|
+
apple?: {
|
|
86
|
+
clientId: string;
|
|
87
|
+
redirectUri: string;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** Async actions that perform I/O and dispatch to the flow reducer. */
|
|
91
|
+
export interface AuthFlowActions {
|
|
92
|
+
selectMethod: (method: 'phone' | 'email' | 'google' | 'apple') => void;
|
|
93
|
+
/** From REPEAT_LOGIN: continue with last used method. */
|
|
94
|
+
continueWithLastMethod: () => void;
|
|
95
|
+
submitIdentifier: (data: {
|
|
96
|
+
phone?: string;
|
|
97
|
+
email?: string;
|
|
98
|
+
countryCode?: string;
|
|
99
|
+
}) => void;
|
|
100
|
+
/** SIGNUP_DETAILS step: submit name + phone/email, then OTP (foreign) or complete (Indian). */
|
|
101
|
+
submitSignupDetails: (data: {
|
|
102
|
+
fullName: string;
|
|
103
|
+
phone?: string;
|
|
104
|
+
email?: string;
|
|
105
|
+
countryCode?: string;
|
|
106
|
+
}) => void;
|
|
107
|
+
/**
|
|
108
|
+
* Verifies the OTP against the auth API. Resolves on success (after the
|
|
109
|
+
* reducer has been advanced) and rejects with an `AuthError` whose
|
|
110
|
+
* `message` carries the API's failure reason — callers can surface it
|
|
111
|
+
* as a field-level error.
|
|
112
|
+
*/
|
|
113
|
+
verifyOtp: (otp: string) => Promise<void>;
|
|
114
|
+
resendOtp: () => void;
|
|
115
|
+
providerCallback: (params: {
|
|
116
|
+
provider: 'google' | 'apple';
|
|
117
|
+
credential: string;
|
|
118
|
+
}) => void;
|
|
119
|
+
goBack: () => void;
|
|
120
|
+
reset: () => void;
|
|
121
|
+
signOut: () => void;
|
|
122
|
+
}
|
|
123
|
+
/** Auth flow context value provided by SSOAuthProvider. */
|
|
124
|
+
export interface AuthFlowContextValue {
|
|
125
|
+
state: AuthFlowState;
|
|
126
|
+
actions: AuthFlowActions;
|
|
127
|
+
/** Session when step is AUTHENTICATED. */
|
|
128
|
+
session: SSOSession | null;
|
|
129
|
+
/** True while step is CHECKING_SESSION. */
|
|
130
|
+
isLoading: boolean;
|
|
131
|
+
/** Provider config for Google/Apple (One Tap, Sign-In button). */
|
|
132
|
+
providerConfig: AuthFlowProviderConfig | undefined;
|
|
133
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth domain types: session, adapter, provider, flow state, errors, device detection.
|
|
3
|
+
*/
|
|
4
|
+
export * from './auth-api-adapter';
|
|
5
|
+
export * from './auth-provider';
|
|
6
|
+
export * from './auth-types';
|
|
7
|
+
export * from './device-detection';
|
|
8
|
+
export * from './flow';
|
|
9
|
+
export * from './router';
|
|
10
|
+
export * from './sso-session';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional URL routing integration for `<AuthFlow/>`.
|
|
3
|
+
*
|
|
4
|
+
* The SDK stays router-agnostic: consumers construct an `AuthFlowRouter`
|
|
5
|
+
* adapter from their app's router (Next.js, React Router, TanStack, etc.)
|
|
6
|
+
* and a `routes` map of which auth step maps to which URL path.
|
|
7
|
+
*
|
|
8
|
+
* Steps omitted from the map render in place without changing the URL
|
|
9
|
+
* (e.g. `CHECKING_SESSION`, `PROVIDER_PENDING`, `AUTHENTICATED`).
|
|
10
|
+
*/
|
|
11
|
+
import type { AuthStep } from './auth-types';
|
|
12
|
+
/**
|
|
13
|
+
* URL path for a given auth step. Consumers control the path strings;
|
|
14
|
+
* the SDK only matches via string equality (returned by `getPath`).
|
|
15
|
+
*/
|
|
16
|
+
export type AuthFlowRoutes = Partial<Record<AuthStep, string>>;
|
|
17
|
+
/**
|
|
18
|
+
* Router adapter the SDK uses to read and update the URL. Built by the
|
|
19
|
+
* consumer from their framework's primitives.
|
|
20
|
+
*
|
|
21
|
+
* @example Next.js (App Router)
|
|
22
|
+
* ```tsx
|
|
23
|
+
* import { usePathname, useRouter } from 'next/navigation';
|
|
24
|
+
*
|
|
25
|
+
* function useAuthRouter(): AuthFlowRouter {
|
|
26
|
+
* const router = useRouter();
|
|
27
|
+
* const pathname = usePathname();
|
|
28
|
+
* const pathRef = useRef(pathname);
|
|
29
|
+
* pathRef.current = pathname;
|
|
30
|
+
* const listenersRef = useRef(new Set<(p: string) => void>());
|
|
31
|
+
*
|
|
32
|
+
* useEffect(() => {
|
|
33
|
+
* for (const cb of listenersRef.current) cb(pathname);
|
|
34
|
+
* }, [pathname]);
|
|
35
|
+
*
|
|
36
|
+
* return {
|
|
37
|
+
* push: (p) => router.push(p),
|
|
38
|
+
* replace: (p) => router.replace(p),
|
|
39
|
+
* getPath: () => pathRef.current,
|
|
40
|
+
* subscribe: (cb) => {
|
|
41
|
+
* listenersRef.current.add(cb);
|
|
42
|
+
* return () => listenersRef.current.delete(cb);
|
|
43
|
+
* },
|
|
44
|
+
* };
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export interface AuthFlowRouter {
|
|
49
|
+
/** Navigate to `path`, adding a history entry. */
|
|
50
|
+
push: (path: string) => void;
|
|
51
|
+
/** Navigate to `path`, replacing the current history entry. */
|
|
52
|
+
replace: (path: string) => void;
|
|
53
|
+
/** Return the current URL path (pathname only — no query / hash). */
|
|
54
|
+
getPath: () => string;
|
|
55
|
+
/**
|
|
56
|
+
* Subscribe to path changes (back/forward, programmatic push/replace).
|
|
57
|
+
* Returns an unsubscribe function.
|
|
58
|
+
*/
|
|
59
|
+
subscribe: (callback: (path: string) => void) => () => void;
|
|
60
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSO session and token storage types.
|
|
3
|
+
*/
|
|
4
|
+
/** How/where the SSO token is stored for cross-app access. */
|
|
5
|
+
export interface TokenStorageStrategy {
|
|
6
|
+
get(): string | null;
|
|
7
|
+
set(token: string, expiresAt: number): void;
|
|
8
|
+
remove(): void;
|
|
9
|
+
}
|
|
10
|
+
/** Minimal request config type for the interceptor (no axios import). */
|
|
11
|
+
export interface AxiosRequestConfig {
|
|
12
|
+
headers?: Record<string, string> | {
|
|
13
|
+
[key: string]: string;
|
|
14
|
+
};
|
|
15
|
+
withCredentials?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Axios instance shape needed to attach auth interceptors (avoids hard axios dependency).
|
|
19
|
+
* Use createAxiosAuthInterceptors with your axios instance.
|
|
20
|
+
*/
|
|
21
|
+
export interface AxiosAuthInterceptorInstance {
|
|
22
|
+
interceptors: {
|
|
23
|
+
request: {
|
|
24
|
+
use(onFulfilled?: (config: AxiosRequestConfig) => AxiosRequestConfig | Promise<AxiosRequestConfig>, onRejected?: (err: unknown) => unknown): number;
|
|
25
|
+
};
|
|
26
|
+
response: {
|
|
27
|
+
use(onFulfilled?: (res: unknown) => unknown, onRejected?: (err: unknown) => unknown): number;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
defaults: {
|
|
31
|
+
withCredentials?: boolean;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Layout configuration types
|
|
4
|
+
*/
|
|
5
|
+
export type AuthLayoutVariant = 'mobile' | 'desktop';
|
|
6
|
+
export type AuthLayoutMaxWidth = 'sm' | 'md' | 'lg';
|
|
7
|
+
/** Text/alignment variant for Logo, Title, Description slots */
|
|
8
|
+
export type AuthLayoutAlign = 'left' | 'center' | 'right';
|
|
9
|
+
/**
|
|
10
|
+
* Props for AuthLayout.Root component
|
|
11
|
+
*/
|
|
12
|
+
export interface AuthLayoutRootProps {
|
|
13
|
+
/** Main content (compound components) */
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
/** Layout variation for spacing and alignment */
|
|
16
|
+
variant?: AuthLayoutVariant;
|
|
17
|
+
/** Maximum width constraint for the content area */
|
|
18
|
+
maxWidth?: AuthLayoutMaxWidth;
|
|
19
|
+
/** Additional className for the root container */
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Props for AuthLayout.Header component
|
|
24
|
+
*/
|
|
25
|
+
export interface AuthLayoutHeaderProps {
|
|
26
|
+
/** Header content */
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
/** Additional className */
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Props for AuthLayout.Logo component
|
|
33
|
+
*/
|
|
34
|
+
export interface AuthLayoutLogoProps {
|
|
35
|
+
/** Logo content */
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
/** Alignment: left, center (default), or right */
|
|
38
|
+
align?: AuthLayoutAlign;
|
|
39
|
+
/** Additional className */
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Props for AuthLayout.Title component
|
|
44
|
+
*/
|
|
45
|
+
export interface AuthLayoutTitleProps {
|
|
46
|
+
/** Title content */
|
|
47
|
+
children: ReactNode;
|
|
48
|
+
/** Alignment: left, center (default), or right */
|
|
49
|
+
align?: AuthLayoutAlign;
|
|
50
|
+
/** Additional className */
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Props for AuthLayout.Description component
|
|
55
|
+
*/
|
|
56
|
+
export interface AuthLayoutDescriptionProps {
|
|
57
|
+
/** Description content */
|
|
58
|
+
children: ReactNode;
|
|
59
|
+
/** Alignment: left, center (default), or right */
|
|
60
|
+
align?: AuthLayoutAlign;
|
|
61
|
+
/** Additional className */
|
|
62
|
+
className?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Props for AuthLayout.Body component
|
|
66
|
+
*/
|
|
67
|
+
export interface AuthLayoutBodyProps {
|
|
68
|
+
/** Body content (forms, buttons, etc.) */
|
|
69
|
+
children: ReactNode;
|
|
70
|
+
/** Additional className */
|
|
71
|
+
className?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Props for AuthLayout.Main component
|
|
75
|
+
*/
|
|
76
|
+
export interface AuthLayoutMainProps {
|
|
77
|
+
/** Main content (Logo, Title, Description, Body slots) */
|
|
78
|
+
children: ReactNode;
|
|
79
|
+
/** When true, constrains main content width to 320px (max-w-[320px]) */
|
|
80
|
+
sm?: boolean;
|
|
81
|
+
/** Additional className */
|
|
82
|
+
className?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Props for AuthLayout.Footer component
|
|
86
|
+
*/
|
|
87
|
+
export interface AuthLayoutFooterProps {
|
|
88
|
+
/** Footer content */
|
|
89
|
+
children: ReactNode;
|
|
90
|
+
/** Additional className */
|
|
91
|
+
className?: string;
|
|
92
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** Form types used by auth SDK form components. */
|
|
2
|
+
import type { ComponentProps, KeyboardEvent } from 'react';
|
|
3
|
+
import { DoctPhoneInput } from 'docthub-core-components';
|
|
4
|
+
import type { Control, FieldValues } from 'react-hook-form';
|
|
5
|
+
/** Base props shared by RHF form field components. */
|
|
6
|
+
export interface BaseFormFieldProps {
|
|
7
|
+
/** Field name used by react-hook-form for registration and validation. */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Visible label rendered above or beside the input. */
|
|
10
|
+
label?: string;
|
|
11
|
+
/** Placeholder text shown when the input is empty. */
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
/** Whether the field is required for form submission. */
|
|
14
|
+
required?: boolean;
|
|
15
|
+
/** Whether the field is disabled (non-interactive). */
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
/** Additional CSS class name(s) applied to the field wrapper. */
|
|
18
|
+
className?: string;
|
|
19
|
+
/** Validation error message to display below the input. */
|
|
20
|
+
error?: string;
|
|
21
|
+
/** Supplementary helper text shown below the input when there is no error. */
|
|
22
|
+
helperText?: string;
|
|
23
|
+
/** Focus this field when form/screen opens (PRODUCT_PROTOCOLS #26). */
|
|
24
|
+
autoFocus?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Props for the text/email/number input field component. */
|
|
27
|
+
export interface RHFInputFieldProps extends BaseFormFieldProps {
|
|
28
|
+
/** HTML input type. Allowed: `'text'`, `'email'`, `'password'`, `'number'`, `'tel'`, `'url'`, `'search'`. */
|
|
29
|
+
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search';
|
|
30
|
+
/** HTML `autocomplete` attribute value (e.g. `'email'`, `'tel'`). */
|
|
31
|
+
autoComplete?: string;
|
|
32
|
+
/** Maximum character length enforced on the input. */
|
|
33
|
+
maxLength?: number;
|
|
34
|
+
/** Minimum character length enforced on the input. */
|
|
35
|
+
minLength?: number;
|
|
36
|
+
/** Regex pattern string for native HTML validation. */
|
|
37
|
+
pattern?: string;
|
|
38
|
+
/** react-hook-form `Control` instance. When omitted, the field uses the nearest `FormProvider`. */
|
|
39
|
+
control?: Control<FieldValues>;
|
|
40
|
+
/** Called when a key is pressed while the input is focused. */
|
|
41
|
+
onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
|
|
42
|
+
/** When true, restricts input to numeric characters only. */
|
|
43
|
+
numericOnly?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** Props for RHF wrapper around DoctPhoneInput (docthub-core-components). */
|
|
46
|
+
type DoctPhoneInputProps = ComponentProps<typeof DoctPhoneInput>;
|
|
47
|
+
/** Props for RHF wrapper around DoctPhoneInput (docthub-core-components). */
|
|
48
|
+
export interface RHFDoctPhoneInputFieldProps extends BaseFormFieldProps, Omit<DoctPhoneInputProps, 'id' | 'name' | 'value' | 'error' | 'helperText' | 'onBlur' | 'onPhoneChange'> {
|
|
49
|
+
/** Country code used when no `countryCodeName` field is configured (e.g. `'91'`). */
|
|
50
|
+
countryCode?: string;
|
|
51
|
+
/** Optional RHF field that stores country code independently. */
|
|
52
|
+
countryCodeName?: string;
|
|
53
|
+
/** Optional RHF field that stores the `DoctPhoneInput` values object. */
|
|
54
|
+
phoneArrayName?: string;
|
|
55
|
+
/** Optional RHF field that stores selected country metadata. */
|
|
56
|
+
selectedCountryName?: string;
|
|
57
|
+
/** react-hook-form `Control` instance. When omitted, the field uses the nearest `FormProvider`. */
|
|
58
|
+
control?: Control<FieldValues>;
|
|
59
|
+
}
|
|
60
|
+
/** Props for the OTP input field component. */
|
|
61
|
+
export interface RHFOtpInputFieldProps extends BaseFormFieldProps {
|
|
62
|
+
/** Number of OTP digit boxes to render. @default 6 */
|
|
63
|
+
length?: number;
|
|
64
|
+
/** Input type for each OTP box: `'text'`, `'number'`, or `'password'` (masked). */
|
|
65
|
+
type?: 'text' | 'number' | 'password';
|
|
66
|
+
/** Focus the first OTP box on mount. */
|
|
67
|
+
autoFocus?: boolean;
|
|
68
|
+
/** Automatically trigger submission when all boxes are filled. */
|
|
69
|
+
autoSubmit?: boolean;
|
|
70
|
+
/** Called with the complete OTP string once all boxes are filled. */
|
|
71
|
+
onComplete?: (otp: string) => void;
|
|
72
|
+
/** CSS class name(s) applied to each individual OTP input box. */
|
|
73
|
+
inputClassName?: string;
|
|
74
|
+
/** react-hook-form `Control` instance. When omitted, the field uses the nearest `FormProvider`. */
|
|
75
|
+
control?: Control<FieldValues>;
|
|
76
|
+
}
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout preset types for the Auth SDK.
|
|
3
|
+
* Presets control structure only: width, alignment, slider vs standalone.
|
|
4
|
+
* They do NOT control auth methods, MFA, or flow behavior.
|
|
5
|
+
*/
|
|
6
|
+
import type { AuthLayoutAlign, AuthLayoutMaxWidth, AuthLayoutVariant } from './auth-layout-types';
|
|
7
|
+
/** Layout type: two-panel with slider vs single centered column. */
|
|
8
|
+
export type LayoutType = 'withSlider' | 'standalone';
|
|
9
|
+
/**
|
|
10
|
+
* Named presets for auth screens. Kept minimal to avoid preset explosion.
|
|
11
|
+
* Add new presets only for distinct layout structures, not for auth methods.
|
|
12
|
+
*/
|
|
13
|
+
export type LayoutPresetName = 'login' | 'signup' | 'verification' | '';
|
|
14
|
+
/**
|
|
15
|
+
* Structure-only config derived from a preset.
|
|
16
|
+
* Used by AuthLayout to render the correct shell (slider, width, alignment).
|
|
17
|
+
*/
|
|
18
|
+
export interface LayoutPresetConfig {
|
|
19
|
+
/** Whether to show the two-panel slider (e.g. login) or standalone column. */
|
|
20
|
+
layoutType: LayoutType;
|
|
21
|
+
/** Mobile vs desktop spacing/breakpoints. */
|
|
22
|
+
variant: AuthLayoutVariant;
|
|
23
|
+
/** Max width of the content area. */
|
|
24
|
+
maxWidth: AuthLayoutMaxWidth;
|
|
25
|
+
/** Constrain main content to 320px when 'sm'. */
|
|
26
|
+
contentWidth: 'sm' | 'default';
|
|
27
|
+
/** Title/description alignment. */
|
|
28
|
+
align: AuthLayoutAlign;
|
|
29
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** Props for the ImageSlider component. */
|
|
3
|
+
export interface ImageSliderProps {
|
|
4
|
+
/** Array of image URLs to display */
|
|
5
|
+
images: string[];
|
|
6
|
+
/** Auto-play interval in milliseconds (0 to disable) */
|
|
7
|
+
autoPlayInterval?: number;
|
|
8
|
+
/** Additional className for the root container */
|
|
9
|
+
className?: string;
|
|
10
|
+
/** Whether to hide the built-in slider indicators */
|
|
11
|
+
hideIndicators?: boolean;
|
|
12
|
+
/** Optional callback fired whenever the active slide changes */
|
|
13
|
+
onSlideChange?: (index: number) => void;
|
|
14
|
+
/** Controlled active index (makes component controlled) */
|
|
15
|
+
activeIndex?: number;
|
|
16
|
+
/** Callback for manual slide navigation in controlled mode */
|
|
17
|
+
onNavigate?: (index: number) => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Props for the MainLayout component.
|
|
21
|
+
* Two-panel auth page: left panel (marketing/slider), right panel (auth content).
|
|
22
|
+
*/
|
|
23
|
+
export interface MainLayoutProps {
|
|
24
|
+
/** Array of image URLs for the slider */
|
|
25
|
+
sliderImages?: string[];
|
|
26
|
+
/** Auto-play interval for slider in milliseconds (0 to disable) */
|
|
27
|
+
sliderAutoPlayInterval?: number;
|
|
28
|
+
/** Call-to-action text displayed above the image card. Set to null to hide */
|
|
29
|
+
ctaText?: ReactNode | null;
|
|
30
|
+
/** Per-slide title/CTA (overrides ctaText when provided; uses active slide index) */
|
|
31
|
+
sliderTitles?: (ReactNode | string)[] | undefined;
|
|
32
|
+
/** Additional className for the root container */
|
|
33
|
+
className?: string;
|
|
34
|
+
/** Additional className for the marketing panel (left side) */
|
|
35
|
+
marketingClassName?: string;
|
|
36
|
+
/** Additional className for the content panel (right side) */
|
|
37
|
+
contentClassName?: string;
|
|
38
|
+
/** Main authentication content (typically AuthLayout.Root with slots) */
|
|
39
|
+
children: ReactNode;
|
|
40
|
+
}
|
|
41
|
+
/** Props for the MarketingPanel component (left side). */
|
|
42
|
+
export interface MarketingPanelProps {
|
|
43
|
+
/** Array of image URLs for the slider */
|
|
44
|
+
sliderImages: string[];
|
|
45
|
+
/** Auto-play interval for slider in milliseconds */
|
|
46
|
+
sliderAutoPlayInterval: number;
|
|
47
|
+
/** Active slide index (controlled) */
|
|
48
|
+
activeSlideIndex: number;
|
|
49
|
+
/** Callback when slide changes */
|
|
50
|
+
onSlideChange: (index: number) => void;
|
|
51
|
+
/** Call-to-action text */
|
|
52
|
+
ctaText?: ReactNode | null;
|
|
53
|
+
/** Per-slide title/CTA (overrides ctaText when provided) */
|
|
54
|
+
sliderTitles?: (ReactNode | string)[] | undefined;
|
|
55
|
+
/** Additional className */
|
|
56
|
+
className?: string;
|
|
57
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page-specific types: props, form values, hook options/return types.
|
|
3
|
+
*/
|
|
4
|
+
export * from './login-form';
|
|
5
|
+
export * from './main-login';
|
|
6
|
+
export * from './otp-verification';
|
|
7
|
+
export * from './pages';
|
|
8
|
+
export * from './repeat-login';
|
|
9
|
+
export * from './signup-form';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { UseFormReturn } from 'react-hook-form';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { loginEmailFormSchema, loginPhoneFormSchema } from '../../validations';
|
|
4
|
+
/** Login mode: phone number or email */
|
|
5
|
+
export type LoginEntryMode = 'phone' | 'email';
|
|
6
|
+
/** Form values for phone-based login, inferred from the Zod schema. */
|
|
7
|
+
export type PhoneFormValues = z.infer<typeof loginPhoneFormSchema>;
|
|
8
|
+
/** Form values for email-based login, inferred from the Zod schema. */
|
|
9
|
+
export type EmailFormValues = z.infer<typeof loginEmailFormSchema>;
|
|
10
|
+
/** Discriminated union of phone or email login form values. */
|
|
11
|
+
export type LoginEntryFormValues = PhoneFormValues | EmailFormValues;
|
|
12
|
+
/** Payload when login entry form is valid (phone or email). */
|
|
13
|
+
export type LoginEntrySubmitData = {
|
|
14
|
+
phone?: string;
|
|
15
|
+
email?: string;
|
|
16
|
+
countryCode?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Params passed to onSuccess after submitApi resolves.
|
|
20
|
+
* Lets the consumer redirect to OTP with mode and recipient (for recipientDisplay) without storing them in refs.
|
|
21
|
+
*/
|
|
22
|
+
export interface LoginEntrySuccessParams {
|
|
23
|
+
/** Current login entry mode (phone or email). */
|
|
24
|
+
mode: LoginEntryMode;
|
|
25
|
+
/** Submitted phone or email string; use for OTP page recipientDisplay or verify API. */
|
|
26
|
+
recipient: string;
|
|
27
|
+
}
|
|
28
|
+
export interface UseLoginEntryFormOptions {
|
|
29
|
+
mode: LoginEntryMode;
|
|
30
|
+
/**
|
|
31
|
+
* Sync callback with valid form data. Used when parent owns API (e.g. AuthFlow passes actions.submitIdentifier).
|
|
32
|
+
* Ignored when submitApi is provided.
|
|
33
|
+
*/
|
|
34
|
+
onSubmit?: ((data: LoginEntrySubmitData) => void) | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* When provided, hook runs business logic: validate → call submitApi(data) → onSuccess(params).
|
|
37
|
+
* Use from consumer (e.g. Next.js): submitApi = sendOtp, onSuccess = (params) => router.push(`/otp?mode=${params.mode}&recipient=${encodeURIComponent(params.recipient)}`).
|
|
38
|
+
*/
|
|
39
|
+
submitApi?: ((data: LoginEntrySubmitData) => Promise<void>) | undefined;
|
|
40
|
+
/** Called after submitApi resolves successfully; receives mode and recipient for OTP redirect/display. */
|
|
41
|
+
onSuccess?: ((params: LoginEntrySuccessParams) => void) | undefined;
|
|
42
|
+
/** Called when submitApi rejects or throws. */
|
|
43
|
+
onError?: ((error: unknown) => void) | undefined;
|
|
44
|
+
}
|
|
45
|
+
/** Return value of the `useLoginEntryForm` hook, providing form state and mode info. */
|
|
46
|
+
export interface UseLoginEntryFormReturn {
|
|
47
|
+
/** react-hook-form methods bound to the current login mode's schema. */
|
|
48
|
+
methods: UseFormReturn<LoginEntryFormValues>;
|
|
49
|
+
/** Submit handler to pass to the form's `onSubmit`. Validates and dispatches the login data. */
|
|
50
|
+
handleSubmit: (data: LoginEntryFormValues) => void;
|
|
51
|
+
/** True when the current mode is `'phone'`; use for conditional field rendering. */
|
|
52
|
+
isPhone: boolean;
|
|
53
|
+
/** True when current form values pass validation (for disabling Continue until valid – edge cases 3, 4). */
|
|
54
|
+
isFormValid: (data: LoginEntryFormValues) => boolean;
|
|
55
|
+
/** True while submitApi is in flight. Use to disable Continue button and show loading. */
|
|
56
|
+
isSubmitting: boolean;
|
|
57
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { UseFormReturn } from 'react-hook-form';
|
|
2
2
|
import type { z } from 'zod';
|
|
3
|
-
import type { OtpVerificationMode, otpFormSchema } from '
|
|
3
|
+
import type { OtpVerificationMode, otpFormSchema } from '../../validations';
|
|
4
4
|
export type { OtpVerificationMode };
|
|
5
5
|
/** Form values for the OTP verification form, inferred from the Zod schema. */
|
|
6
6
|
export type OtpFormValues = z.infer<typeof otpFormSchema>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook options and return type for repeat login (continue with last method).
|
|
3
|
+
*/
|
|
4
|
+
export interface UseRepeatLoginOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Last used authentication method shown in the primary button label.
|
|
7
|
+
* @default "Mobile"
|
|
8
|
+
*/
|
|
9
|
+
lastUsedMethod?: string | undefined;
|
|
10
|
+
/** Sync handler for primary action. Use when caller owns API (e.g. AuthFlow). Ignored when continueApi is provided. */
|
|
11
|
+
onContinueWithLastMethod?: (() => void) | undefined;
|
|
12
|
+
/** Handler for the secondary action (choose another method). */
|
|
13
|
+
onUseAnotherMethod?: (() => void) | undefined;
|
|
14
|
+
/** Async API for continue (e.g. validate session). When provided, hook runs: continueApi() → onSuccess(). */
|
|
15
|
+
continueApi?: (() => Promise<void>) | undefined;
|
|
16
|
+
/** Called after continueApi succeeds (e.g. router.push('/dashboard')). */
|
|
17
|
+
onSuccess?: (() => void) | undefined;
|
|
18
|
+
/** Called when continueApi fails. */
|
|
19
|
+
onError?: ((error: unknown) => void) | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** Return value of the `useRepeatLogin` hook, providing continue handler and display state. */
|
|
22
|
+
export interface UseRepeatLoginReturn {
|
|
23
|
+
/** Call this when the user clicks "Continue with {lastUsedMethod}". */
|
|
24
|
+
handleContinue: () => void;
|
|
25
|
+
/** True while continueApi is in flight. */
|
|
26
|
+
isSubmitting: boolean;
|
|
27
|
+
/** Resolved lastUsedMethod for display (default "Mobile"). */
|
|
28
|
+
lastUsedMethod: string;
|
|
29
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { UseFormReturn } from 'react-hook-form';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { signupEmailFormSchema, signupForeignFormSchema, signupPhoneFormSchema } from '../../validations';
|
|
4
|
+
/** Signup mode: phone, email as second field, or foreign (full name + email + phone). */
|
|
5
|
+
export type SignupEntryMode = 'phone' | 'email' | 'foreign';
|
|
6
|
+
/** Form values for phone-based signup, inferred from the Zod schema. */
|
|
7
|
+
export type SignupPhoneFormValues = z.infer<typeof signupPhoneFormSchema>;
|
|
8
|
+
/** Form values for email-based signup, inferred from the Zod schema. */
|
|
9
|
+
export type SignupEmailFormValues = z.infer<typeof signupEmailFormSchema>;
|
|
10
|
+
/** Form values for foreign signup (full name + email + phone), inferred from the Zod schema. */
|
|
11
|
+
export type SignupForeignFormValues = z.infer<typeof signupForeignFormSchema>;
|
|
12
|
+
/** Discriminated union of all signup form value shapes. */
|
|
13
|
+
export type SignupFormValues = SignupPhoneFormValues | SignupEmailFormValues | SignupForeignFormValues;
|
|
14
|
+
/** Payload when signup form is valid. */
|
|
15
|
+
export type SignupSubmitData = {
|
|
16
|
+
fullName: string;
|
|
17
|
+
phone?: string;
|
|
18
|
+
email?: string;
|
|
19
|
+
countryCode?: string;
|
|
20
|
+
};
|
|
21
|
+
export interface UseSignupFormOptions {
|
|
22
|
+
/** Mode: phone, email as second field, or foreign (name + email + phone) */
|
|
23
|
+
mode: SignupEntryMode;
|
|
24
|
+
/** For foreign mode: pre-fill phone when user already entered it. */
|
|
25
|
+
defaultPhone?: string | undefined;
|
|
26
|
+
/** Sync callback with valid data. Use when parent owns API (e.g. AuthFlow). Ignored when submitApi is provided. */
|
|
27
|
+
onSubmit?: ((data: SignupSubmitData) => void) | undefined;
|
|
28
|
+
/** When provided, hook runs: validate → submitApi(data) → onSuccess(). Consumer passes redirect in onSuccess. */
|
|
29
|
+
submitApi?: ((data: SignupSubmitData) => Promise<void>) | undefined;
|
|
30
|
+
/** Called after submitApi succeeds (e.g. router.push('/otp') or next step). */
|
|
31
|
+
onSuccess?: (() => void) | undefined;
|
|
32
|
+
/** Called when submitApi rejects or throws. */
|
|
33
|
+
onError?: ((error: unknown) => void) | undefined;
|
|
34
|
+
}
|
|
35
|
+
/** Return value of the `useSignupForm` hook, providing form state and mode flags. */
|
|
36
|
+
export interface UseSignupFormReturn {
|
|
37
|
+
/** react-hook-form methods bound to the current signup mode's schema. */
|
|
38
|
+
methods: UseFormReturn<SignupFormValues>;
|
|
39
|
+
/** Submit handler to pass to the form's `onSubmit`. Validates and dispatches signup data. */
|
|
40
|
+
handleSubmit: (data: SignupFormValues) => void;
|
|
41
|
+
/** True when mode is 'phone', false when mode is 'email'. For 'foreign' same as (mode === 'phone') for layout. */
|
|
42
|
+
isPhone: boolean;
|
|
43
|
+
/** True when mode is 'foreign' (full name + email + phone). */
|
|
44
|
+
isForeign: boolean;
|
|
45
|
+
/** True when current form values pass validation (for disabling Continue – edge cases 9, 16, 19). */
|
|
46
|
+
isFormValid: (data: SignupFormValues) => boolean;
|
|
47
|
+
/** True while submitApi is in flight. */
|
|
48
|
+
isSubmitting: boolean;
|
|
49
|
+
}
|