@meindesk/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,429 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, CSSProperties, ButtonHTMLAttributes, HTMLAttributes } from 'react';
3
+ import * as _meindesk_sdk from '@meindesk/sdk';
4
+ import { User, Session, AuthConfig, MeindeskClient, SignInData, SignInResult, SignUpData, AuthResult, FormField } from '@meindesk/sdk';
5
+ import { AuthExperienceConfig, ExperienceId, ProviderId, ProviderConfig, AppearanceConfig, ProfileFieldConfig } from '@meindesk/auth-config';
6
+
7
+ interface AuthContextValue {
8
+ isLoaded: boolean;
9
+ isSignedIn: boolean;
10
+ user: User | null;
11
+ session: Session | null;
12
+ sessionToken: string | null;
13
+ config: AuthConfig | null;
14
+ client: MeindeskClient;
15
+ /** Set when OAuth code exchange fails during bootstrap. */
16
+ oauthError: string | null;
17
+ signIn: (data: SignInData) => Promise<SignInResult>;
18
+ signUp: (data: SignUpData) => Promise<AuthResult>;
19
+ signOut: () => Promise<void>;
20
+ verifyMfa: (data: {
21
+ mfaToken: string;
22
+ code: string;
23
+ }) => Promise<AuthResult>;
24
+ startOAuth: (provider: string, options?: {
25
+ redirectUrl?: string;
26
+ purpose?: "sign_in" | "link";
27
+ sessionToken?: string;
28
+ }) => void;
29
+ exchangeOAuthCode: (code: string) => Promise<AuthResult>;
30
+ setActive: (result: AuthResult) => void;
31
+ refreshUser: () => Promise<User | null>;
32
+ /** Refetch application auth config (experience, providers, settings). */
33
+ reloadConfig: () => Promise<void>;
34
+ }
35
+ interface AuthProviderProps {
36
+ /** Defaults to `NEXT_PUBLIC_MEINDESK_PUBLISHABLE_KEY`. */
37
+ publishableKey?: string;
38
+ /** Defaults to `NEXT_PUBLIC_API_URL` or http://localhost:4000. */
39
+ apiUrl?: string;
40
+ children: ReactNode;
41
+ }
42
+ declare function AuthProvider({ publishableKey: publishableKeyProp, apiUrl: apiUrlProp, children, }: AuthProviderProps): react.FunctionComponentElement<{
43
+ children: ReactNode;
44
+ }>;
45
+ declare function useAuthContext(): AuthContextValue;
46
+
47
+ declare function useAuth(): {
48
+ isLoaded: boolean;
49
+ isSignedIn: boolean;
50
+ user: _meindesk_sdk.User | null;
51
+ session: _meindesk_sdk.Session | null;
52
+ sessionToken: string | null;
53
+ signIn: (data: _meindesk_sdk.SignInData) => Promise<_meindesk_sdk.SignInResult>;
54
+ signUp: (data: _meindesk_sdk.SignUpData) => Promise<_meindesk_sdk.AuthResult>;
55
+ signOut: () => Promise<void>;
56
+ };
57
+ declare function useUser(): {
58
+ isLoaded: boolean;
59
+ isSignedIn: boolean;
60
+ user: _meindesk_sdk.User | null;
61
+ };
62
+ declare function useSession(): {
63
+ isLoaded: boolean;
64
+ session: _meindesk_sdk.Session | null;
65
+ sessionToken: string | null;
66
+ };
67
+
68
+ interface ConditionalProps {
69
+ children: ReactNode;
70
+ fallback?: ReactNode;
71
+ }
72
+ declare function SignedIn({ children, fallback }: ConditionalProps): ReactNode;
73
+ declare function SignedOut({ children, fallback }: ConditionalProps): ReactNode;
74
+ interface ProtectProps extends ConditionalProps {
75
+ /** When false, render fallback even if signed in. */
76
+ condition?: boolean;
77
+ }
78
+ declare function Protect({ children, fallback, condition, }: ProtectProps): ReactNode;
79
+
80
+ interface SignInProps {
81
+ onSuccess?: (result: AuthResult) => void;
82
+ onError?: (error: Error) => void;
83
+ redirectUrl?: string;
84
+ className?: string;
85
+ style?: CSSProperties;
86
+ title?: string;
87
+ subtitle?: string;
88
+ }
89
+ declare function SignIn({ onSuccess, onError, redirectUrl, className, style, }: SignInProps): react.JSX.Element;
90
+
91
+ interface SignUpProps {
92
+ onSuccess?: (result: AuthResult) => void;
93
+ onError?: (error: Error) => void;
94
+ redirectUrl?: string;
95
+ className?: string;
96
+ style?: CSSProperties;
97
+ title?: string;
98
+ subtitle?: string;
99
+ }
100
+ declare function SignUp({ onSuccess, onError, redirectUrl, className, style, }: SignUpProps): react.JSX.Element;
101
+
102
+ interface SsoCallbackProps {
103
+ /** Where to send the user after a successful exchange. Defaults to `redirect_url` query or `/`. */
104
+ fallbackRedirectUrl?: string;
105
+ /** Shown while exchanging. */
106
+ loading?: ReactNode;
107
+ /** Custom error renderer. */
108
+ renderError?: (error: string) => ReactNode;
109
+ }
110
+ /**
111
+ * Optional dedicated OAuth landing page.
112
+ * Most apps do not need this — AuthProvider exchanges on any page and
113
+ * authMiddleware lets `?code=&provider=` through. Use when you want a
114
+ * dedicated sign-in progress screen.
115
+ */
116
+ declare function SsoCallback({ fallbackRedirectUrl, loading, renderError, }: SsoCallbackProps): react.JSX.Element;
117
+
118
+ interface ForgotPasswordProps {
119
+ onSuccess?: () => void;
120
+ onError?: (error: Error) => void;
121
+ redirectUrl?: string;
122
+ className?: string;
123
+ style?: CSSProperties;
124
+ title?: string;
125
+ subtitle?: string;
126
+ }
127
+ declare function ForgotPassword({ onSuccess, onError, className, style, }: ForgotPasswordProps): react.JSX.Element;
128
+
129
+ interface ResetPasswordProps {
130
+ onSuccess?: () => void;
131
+ onError?: (error: Error) => void;
132
+ redirectUrl?: string;
133
+ className?: string;
134
+ style?: CSSProperties;
135
+ title?: string;
136
+ subtitle?: string;
137
+ token?: string;
138
+ }
139
+ declare function ResetPassword({ onSuccess, onError, redirectUrl, className, style, token: tokenProp, }: ResetPasswordProps): react.JSX.Element;
140
+
141
+ interface MagicLinkSignInProps {
142
+ onSuccess?: (result: AuthResult) => void;
143
+ onError?: (error: Error) => void;
144
+ redirectUrl?: string;
145
+ className?: string;
146
+ style?: CSSProperties;
147
+ title?: string;
148
+ subtitle?: string;
149
+ token?: string;
150
+ }
151
+ declare function MagicLinkSignIn({ onSuccess, onError, redirectUrl, className, style, token: tokenProp, }: MagicLinkSignInProps): react.JSX.Element;
152
+
153
+ interface VerifyEmailProps {
154
+ onSuccess?: () => void;
155
+ onError?: (error: Error) => void;
156
+ redirectUrl?: string;
157
+ className?: string;
158
+ style?: CSSProperties;
159
+ title?: string;
160
+ subtitle?: string;
161
+ token?: string;
162
+ }
163
+ declare function VerifyEmail({ onSuccess, onError, redirectUrl, className, style, token: tokenProp, }: VerifyEmailProps): react.JSX.Element;
164
+
165
+ type UserProfileTab = "profile" | "security" | "preferences" | "email";
166
+ interface UserProfileProps {
167
+ open?: boolean;
168
+ onOpenChange?: (open: boolean) => void;
169
+ defaultTab?: UserProfileTab;
170
+ /** When opening via email shortcut, expand the email editor. */
171
+ expandEmailOnOpen?: boolean;
172
+ className?: string;
173
+ style?: CSSProperties;
174
+ }
175
+ declare function UserProfile({ open: controlledOpen, onOpenChange, defaultTab, expandEmailOnOpen, className, style, }: UserProfileProps): react.JSX.Element | null;
176
+ declare function UserProfileButton({ className, style, label, defaultTab, }: {
177
+ className?: string;
178
+ style?: CSSProperties;
179
+ label?: string;
180
+ defaultTab?: UserProfileTab;
181
+ }): react.JSX.Element | null;
182
+
183
+ interface UserButtonProps {
184
+ className?: string;
185
+ style?: CSSProperties;
186
+ afterSignOutUrl?: string;
187
+ showName?: boolean;
188
+ userProfileDefaultTab?: UserProfileTab;
189
+ }
190
+ declare function UserButton({ className, style, afterSignOutUrl, showName, userProfileDefaultTab, }: UserButtonProps): react.JSX.Element | null;
191
+
192
+ interface RenderFormFieldProps {
193
+ field: FormField;
194
+ value: string;
195
+ disabled?: boolean;
196
+ onChange: (name: string, value: string) => void;
197
+ autoComplete?: string;
198
+ }
199
+ declare function FormFieldControl({ field, value, disabled, onChange, autoComplete, }: RenderFormFieldProps): react.JSX.Element;
200
+ declare function autoCompleteForField(fieldName: string, mode?: "sign-in" | "sign-up"): string | undefined;
201
+
202
+ declare const authStyles: string;
203
+ declare function ensureAuthStyles(): void;
204
+
205
+ type AuthMode = "live" | "preview";
206
+ interface ExperienceScreenProps {
207
+ config: AuthExperienceConfig;
208
+ mode: AuthMode;
209
+ theme?: "light" | "dark";
210
+ className?: string;
211
+ onNavigate?: (experience: ExperienceId) => void;
212
+ onProviderClick?: (id: ProviderId) => void;
213
+ onSubmit?: (values: Record<string, string>) => void | Promise<void>;
214
+ }
215
+ declare function SignInScreen(props: ExperienceScreenProps): react.JSX.Element;
216
+ declare function SignUpScreen(props: ExperienceScreenProps): react.JSX.Element;
217
+ declare function ForgotPasswordScreen(props: ExperienceScreenProps): react.JSX.Element;
218
+ declare function ResetPasswordScreen(props: ExperienceScreenProps): react.JSX.Element;
219
+ declare function MagicLinkScreen(props: ExperienceScreenProps): react.JSX.Element;
220
+ declare function EmailVerificationScreen(props: ExperienceScreenProps): react.JSX.Element;
221
+ declare function MfaScreen(props: ExperienceScreenProps): react.JSX.Element;
222
+ declare function OrganizationSelectionScreen(props: ExperienceScreenProps): react.JSX.Element;
223
+ declare function OrganizationCreationScreen(props: ExperienceScreenProps): react.JSX.Element;
224
+
225
+ interface AuthExperienceProps {
226
+ experience: ExperienceId;
227
+ /** Full experience config. When omitted in live mode, derived from AuthProvider config. */
228
+ config?: AuthExperienceConfig;
229
+ /** Raw SDK AuthConfig used to assemble experience when `config` is omitted. */
230
+ authConfig?: AuthConfig | null;
231
+ mode?: AuthMode;
232
+ theme?: "light" | "dark";
233
+ className?: string;
234
+ style?: CSSProperties;
235
+ onExperienceChange?: (experience: ExperienceId) => void;
236
+ onProviderClick?: (id: ProviderId) => void;
237
+ onSubmit?: (values: Record<string, string>) => void | Promise<void>;
238
+ }
239
+ declare function authConfigToExperience(authConfig?: AuthConfig | null): AuthExperienceConfig;
240
+ /** Minimal placeholder while AuthProvider finishes loading config. */
241
+ declare function AuthExperienceLoading({ className, style, }: {
242
+ className?: string;
243
+ style?: CSSProperties;
244
+ }): react.JSX.Element;
245
+ declare function AuthExperience({ experience: experienceProp, config: configProp, authConfig, mode, theme, className, style, onExperienceChange, onProviderClick, onSubmit, }: AuthExperienceProps): react.JSX.Element;
246
+
247
+ declare function ProviderButtons({ providers, position, onProviderClick, disabled, }: {
248
+ providers: ProviderConfig[];
249
+ position: "before" | "after";
250
+ onProviderClick?: (id: ProviderId) => void;
251
+ disabled?: boolean;
252
+ }): react.JSX.Element | null;
253
+
254
+ declare function AuthShell({ config, theme, className, style, children, }: {
255
+ config: AuthExperienceConfig;
256
+ theme?: "light" | "dark";
257
+ className?: string;
258
+ style?: CSSProperties;
259
+ children: ReactNode;
260
+ }): react.JSX.Element;
261
+
262
+ declare function appearanceToCssVars(appearance: AppearanceConfig, theme?: "light" | "dark"): CSSProperties;
263
+
264
+ /** Centralized motion timings (ms). Keep auth UI fast — utility, not marketing. */
265
+ declare const MOTION_DURATION: {
266
+ readonly instant: 120;
267
+ readonly fast: 160;
268
+ readonly normal: 220;
269
+ readonly slow: 320;
270
+ };
271
+ type MotionDuration = keyof typeof MOTION_DURATION;
272
+ /** Controlled easings — no overshoot / bounce. */
273
+ declare const MOTION_EASING: {
274
+ readonly standard: "cubic-bezier(0.2, 0, 0, 1)";
275
+ readonly enter: "cubic-bezier(0.16, 1, 0.3, 1)";
276
+ readonly exit: "cubic-bezier(0.4, 0, 1, 1)";
277
+ readonly emphasis: "cubic-bezier(0.2, 0, 0, 1)";
278
+ };
279
+ type MotionEasing = keyof typeof MOTION_EASING;
280
+ declare const MOTION_DISTANCE: {
281
+ /** Max Y shift for form / dropdown enter (px). */
282
+ readonly subtle: 6;
283
+ };
284
+
285
+ declare function getPrefersReducedMotion(): boolean;
286
+ /** Subscribe to prefers-reduced-motion. Prefer opacity-only / instant swaps when true. */
287
+ declare function useReducedMotion(): boolean;
288
+
289
+ interface FadePresenceProps {
290
+ /** When this changes, content crossfades. */
291
+ contentKey: string;
292
+ children: ReactNode;
293
+ className?: string;
294
+ style?: CSSProperties;
295
+ /** Skip Y translate (opacity only). */
296
+ opacityOnly?: boolean;
297
+ }
298
+ /**
299
+ * Keyed crossfade. Latest key wins immediately (interruptible — no queue).
300
+ */
301
+ declare function FadePresence({ contentKey, children, className, style, opacityOnly, }: FadePresenceProps): react.JSX.Element;
302
+
303
+ interface FormTransitionProps {
304
+ contentKey: string;
305
+ children: ReactNode;
306
+ className?: string;
307
+ style?: CSSProperties;
308
+ }
309
+ /**
310
+ * Stable auth form shell: crossfade content and tween height so the card
311
+ * does not collapse then expand between steps.
312
+ */
313
+ declare function FormTransition({ contentKey, children, className, style, }: FormTransitionProps): react.JSX.Element;
314
+
315
+ interface CollapseTransitionProps {
316
+ open: boolean;
317
+ children: ReactNode;
318
+ className?: string;
319
+ style?: CSSProperties;
320
+ }
321
+ /** Reveal / hide inline messages without a harsh layout jump. */
322
+ declare function CollapseTransition({ open, children, className, style, }: CollapseTransitionProps): react.JSX.Element | null;
323
+
324
+ interface LoadingButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
325
+ loading?: boolean;
326
+ loadingLabel?: string;
327
+ /** Keep visible label while spinning (default true). */
328
+ showLabelWhileLoading?: boolean;
329
+ variant?: "primary" | "secondary" | "ghost" | "danger";
330
+ /** Skip default `.meindesk-button` styles (host supplies className). */
331
+ bare?: boolean;
332
+ className?: string;
333
+ style?: CSSProperties;
334
+ children: ReactNode;
335
+ }
336
+ declare const LoadingButton: react.ForwardRefExoticComponent<LoadingButtonProps & react.RefAttributes<HTMLButtonElement>>;
337
+
338
+ type AuthLoaderVariant = "inline" | "button" | "content" | "page" | "modal";
339
+ interface AuthLoaderProps extends HTMLAttributes<HTMLDivElement> {
340
+ variant?: AuthLoaderVariant;
341
+ label?: string;
342
+ className?: string;
343
+ style?: CSSProperties;
344
+ }
345
+ /** Shared thin-ring spinner for auth hydration, buttons, and modals. */
346
+ declare function AuthLoader({ variant, label, className, style, ...rest }: AuthLoaderProps): react.JSX.Element;
347
+
348
+ type SkeletonShape = "circle" | "line" | "rect" | "avatar";
349
+ interface SkeletonProps extends HTMLAttributes<HTMLDivElement> {
350
+ shape?: SkeletonShape;
351
+ width?: number | string;
352
+ height?: number | string;
353
+ className?: string;
354
+ style?: CSSProperties;
355
+ }
356
+ /** Soft pulse placeholder — match final layout, avoid aggressive shimmer. */
357
+ declare function Skeleton({ shape, width, height, className, style, ...rest }: SkeletonProps): react.JSX.Element;
358
+ declare function UserButtonSkeleton({ className }: {
359
+ className?: string;
360
+ }): react.JSX.Element;
361
+
362
+ interface FieldErrorProps {
363
+ message?: string | null;
364
+ children?: ReactNode;
365
+ className?: string;
366
+ style?: CSSProperties;
367
+ id?: string;
368
+ /** `form` = banner under the form; `field` = compact message under an input. */
369
+ variant?: "form" | "field";
370
+ }
371
+ declare function FieldError({ message, children, className, style, id, variant, }: FieldErrorProps): react.JSX.Element;
372
+
373
+ interface SuccessIndicatorProps {
374
+ message?: string | null;
375
+ children?: ReactNode;
376
+ show?: boolean;
377
+ className?: string;
378
+ style?: CSSProperties;
379
+ }
380
+ declare function SuccessIndicator({ message, children, show, className, style, }: SuccessIndicatorProps): react.JSX.Element;
381
+
382
+ type AuthToastTone = "success" | "error" | "info";
383
+ interface AuthToastItem {
384
+ id: string;
385
+ message: string;
386
+ tone: AuthToastTone;
387
+ }
388
+ interface AuthToastContextValue {
389
+ toasts: AuthToastItem[];
390
+ push: (message: string, tone?: AuthToastTone) => void;
391
+ dismiss: (id: string) => void;
392
+ }
393
+ declare function AuthToastProvider({ children }: {
394
+ children: ReactNode;
395
+ }): react.JSX.Element;
396
+ declare function useAuthToast(): AuthToastContextValue;
397
+
398
+ type AuthFormFieldErrors = Record<string, string>;
399
+ interface AuthFormErrorResult {
400
+ /** Banner / form-level message. */
401
+ formError: string | null;
402
+ /** Per-field messages keyed by field id (email, password, code, …). */
403
+ fieldErrors: AuthFormFieldErrors;
404
+ }
405
+ /** Prefer API message; fall back to a readable default for common codes. */
406
+ declare function formatAuthError(err: unknown, fallback?: string): string;
407
+ /**
408
+ * Map an API/client error into form + field errors.
409
+ * Credential failures stay form-level (no email/password leak via field highlights).
410
+ */
411
+ declare function mapAuthErrorToForm(err: unknown): AuthFormErrorResult;
412
+
413
+ interface ValidateAuthFieldsOptions {
414
+ /** Extra fields not in ProfileFieldConfig (e.g. MFA `code`). */
415
+ extras?: Array<{
416
+ id: string;
417
+ label?: string;
418
+ required?: boolean;
419
+ minLength?: number;
420
+ kind?: "email" | "password" | "code" | "text";
421
+ }>;
422
+ passwordMinLength?: number;
423
+ }
424
+ /** Client-side validation before submit. Returns field errors (empty = valid). */
425
+ declare function validateAuthFields(fields: ProfileFieldConfig[] | undefined, values: Record<string, string>, options?: ValidateAuthFieldsOptions): AuthFormFieldErrors;
426
+ declare function hasFieldErrors(errors: AuthFormFieldErrors): boolean;
427
+ declare function firstFieldErrorId(errors: AuthFormFieldErrors, order: string[]): string | null;
428
+
429
+ export { type AuthContextValue, AuthExperience, AuthExperienceLoading, type AuthExperienceProps, type AuthFormErrorResult, type AuthFormFieldErrors, AuthLoader, type AuthLoaderProps, type AuthLoaderVariant, type AuthMode, AuthProvider, type AuthProviderProps, AuthShell, type AuthToastItem, AuthToastProvider, type AuthToastTone, CollapseTransition, type CollapseTransitionProps, type ConditionalProps, EmailVerificationScreen, type ExperienceScreenProps, FadePresence, type FadePresenceProps, FieldError, type FieldErrorProps, ForgotPassword, type ForgotPasswordProps, ForgotPasswordScreen, FormFieldControl, FormTransition, type FormTransitionProps, LoadingButton, type LoadingButtonProps, MOTION_DISTANCE, MOTION_DURATION, MOTION_EASING, MagicLinkScreen, MagicLinkSignIn, type MagicLinkSignInProps, MfaScreen, type MotionDuration, type MotionEasing, OrganizationCreationScreen, OrganizationSelectionScreen, Protect, type ProtectProps, ProviderButtons, type RenderFormFieldProps, ResetPassword, type ResetPasswordProps, ResetPasswordScreen, SignIn, type SignInProps, SignInScreen, SignUp, type SignUpProps, SignUpScreen, SignedIn, SignedOut, Skeleton, type SkeletonProps, type SkeletonShape, SsoCallback, type SsoCallbackProps, SuccessIndicator, type SuccessIndicatorProps, UserButton, type UserButtonProps, UserButtonSkeleton, UserProfile, UserProfileButton, type UserProfileProps, type UserProfileTab, type ValidateAuthFieldsOptions, VerifyEmail, type VerifyEmailProps, appearanceToCssVars, authConfigToExperience, authStyles, autoCompleteForField, ensureAuthStyles, firstFieldErrorId, formatAuthError, getPrefersReducedMotion, hasFieldErrors, mapAuthErrorToForm, useAuth, useAuthContext, useAuthToast, useReducedMotion, useSession, useUser, validateAuthFields };