@nice2dev/auth 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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+
7
+ ## [0.1.0] — 2026-01-XX
8
+
9
+ ### Added
10
+ - `NiceLoginForm` — login form with validation and i18n
11
+ - `NiceRegistrationForm` — registration form with password strength
12
+ - `NiceTwoFaSetup` — TOTP 2FA configuration with QR code
13
+ - `NiceChangePassword` — change password form with strength indicator
14
+ - `NiceCaptcha` — captcha widget (multiple provider support)
15
+ - `NicePasswordStrength` — password strength indicator
16
+ - `NiceOAuthButtons` — OAuth login buttons (Discord, Google, MS, Spotify…)
17
+ - `useAuth` — auth state hook (JWT, roles, refresh token, logout)
18
+ - `NiceAuthGuard` — protected route wrapper
19
+ - `NiceTokenManagement` — API token management UI
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NiceToDev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @nice2dev/auth
2
+
3
+ Authentication & authorization UI components for React — login, registration, OAuth, 2FA, captcha, password management, and token handling.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@nice2dev/auth)](https://www.npmjs.com/package/@nice2dev/auth)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
8
+
9
+ ---
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install @nice2dev/auth
15
+ ```
16
+
17
+ **Peer dependencies:** `react >= 17.0.0`, `react-dom >= 17.0.0`
18
+
19
+ ## Components
20
+
21
+ | Component | Description |
22
+ |-----------|-------------|
23
+ | `NiceLoginForm` | Login form with email/password, validation, remember me |
24
+ | `NiceRegistrationForm` | Registration form with password strength |
25
+ | `NiceTwoFaSetup` | TOTP 2FA setup with QR code display |
26
+ | `NiceChangePassword` | Change/reset password with strength meter |
27
+ | `NiceCaptcha` | Captcha widget (pluggable providers) |
28
+ | `NicePasswordStrength` | Visual password strength indicator |
29
+ | `NiceOAuthButtons` | OAuth provider login buttons (Google, GitHub, Microsoft, etc.) |
30
+ | `NiceAuthGuard` | Protected route/section wrapper |
31
+ | `NiceTokenManagement` | API token CRUD management |
32
+
33
+ ## Hooks
34
+
35
+ | Hook | Description |
36
+ |------|-------------|
37
+ | `useAuth` | Auth state management (JWT, roles, refresh, logout) |
38
+
39
+ ## Usage
40
+
41
+ ```tsx
42
+ import { NiceLoginForm, useAuth } from '@nice2dev/auth';
43
+
44
+ function LoginPage() {
45
+ const { login, user } = useAuth({
46
+ loginFn: async (credentials) => {
47
+ const res = await fetch('/api/auth/login', {
48
+ method: 'POST',
49
+ body: JSON.stringify(credentials),
50
+ });
51
+ return res.json();
52
+ },
53
+ });
54
+
55
+ if (user) return <div>Welcome, {user.name}</div>;
56
+
57
+ return <NiceLoginForm onLogin={login} />;
58
+ }
59
+ ```
60
+
61
+ ## Types
62
+
63
+ Key TypeScript types exported: `AuthUser`, `AuthTokens`, `AuthState`, `AuthActions`, `UseAuthConfig`, `CaptchaProvider`, `OAuthProvider`, `PasswordStrengthLevel`.
64
+
65
+ ## License
66
+
67
+ MIT © NiceToDev
@@ -0,0 +1,32 @@
1
+ import { default as React } from 'react';
2
+ /** Captcha provider type. */
3
+ export type CaptchaProvider = 'custom' | 'recaptcha' | 'hcaptcha' | 'turnstile';
4
+ /** Props for the {@link NiceCaptcha} component. */
5
+ export interface NiceCaptchaProps {
6
+ /** Captcha provider. */
7
+ provider?: CaptchaProvider;
8
+ /** Site key for the captcha provider. */
9
+ siteKey?: string;
10
+ /** Fires when captcha is verified with a token. */
11
+ onVerify?: (token: string) => void;
12
+ /** Fires when captcha expires. */
13
+ onExpire?: () => void;
14
+ /** Fires on captcha error. */
15
+ onError?: (error: unknown) => void;
16
+ /** Theme. */
17
+ theme?: 'light' | 'dark';
18
+ /** Size. */
19
+ size?: 'normal' | 'compact' | 'invisible';
20
+ /** Custom render for provider='custom'. */
21
+ customRender?: React.ReactNode;
22
+ className?: string;
23
+ style?: React.CSSProperties;
24
+ }
25
+ /**
26
+ * {@link NiceCaptcha} — Pluggable captcha widget shell.
27
+ * For production use, inject the actual captcha SDK via `customRender` or
28
+ * integrate the provider script externally. This component provides a
29
+ * consistent wrapper API.
30
+ */
31
+ export declare const NiceCaptcha: React.ForwardRefExoticComponent<NiceCaptchaProps & React.RefAttributes<HTMLDivElement>>;
32
+ //# sourceMappingURL=NiceCaptcha.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NiceCaptcha.d.ts","sourceRoot":"","sources":["../src/NiceCaptcha.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,6BAA6B;AAC7B,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,CAAC;AAEhF,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,aAAa;IACb,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,YAAY;IACZ,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IAC1C,2CAA2C;IAC3C,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,yFA4BtB,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { default as React } from 'react';
2
+ /** Props for the {@link NiceChangePassword} component. */
3
+ export interface NiceChangePasswordProps {
4
+ /** Whether the user must provide current password. */
5
+ requireCurrentPassword?: boolean;
6
+ /** Fires on submit. */
7
+ onSubmit?: (data: {
8
+ currentPassword?: string;
9
+ newPassword: string;
10
+ }) => void;
11
+ /** Whether a request is in progress. */
12
+ loading?: boolean;
13
+ /** External error message. */
14
+ error?: string;
15
+ /** Success message after password change. */
16
+ success?: string;
17
+ /** Minimum password strength to allow submit (0-4). */
18
+ minPasswordStrength?: number;
19
+ /** Title. */
20
+ title?: string;
21
+ className?: string;
22
+ style?: React.CSSProperties;
23
+ }
24
+ /**
25
+ * {@link NiceChangePassword} — Change/reset password form with strength meter.
26
+ */
27
+ export declare const NiceChangePassword: React.ForwardRefExoticComponent<NiceChangePasswordProps & React.RefAttributes<HTMLFormElement>>;
28
+ //# sourceMappingURL=NiceChangePassword.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NiceChangePassword.d.ts","sourceRoot":"","sources":["../src/NiceChangePassword.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4C,MAAM,OAAO,CAAC;AAGjE,0DAA0D;AAC1D,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,uBAAuB;IACvB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7E,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,aAAa;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,iGAwF7B,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { default as React } from 'react';
2
+ /** Props for the {@link NiceLoginForm} component. */
3
+ export interface NiceLoginFormProps {
4
+ /** Fires on form submit. */
5
+ onSubmit?: (credentials: {
6
+ email: string;
7
+ password: string;
8
+ rememberMe: boolean;
9
+ }) => void;
10
+ /** Whether a login request is in progress. */
11
+ loading?: boolean;
12
+ /** External error message (e.g. "Invalid credentials"). */
13
+ error?: string;
14
+ /** Whether to show "Remember me" checkbox. */
15
+ showRememberMe?: boolean;
16
+ /** Whether to show "Forgot password" link. */
17
+ showForgotPassword?: boolean;
18
+ /** Fires when "Forgot password" is clicked. */
19
+ onForgotPassword?: () => void;
20
+ /** Whether to show "Register" link. */
21
+ showRegisterLink?: boolean;
22
+ /** Fires when "Register" is clicked. */
23
+ onRegisterClick?: () => void;
24
+ /** Title text. */
25
+ title?: string;
26
+ /** Submit button label. */
27
+ submitLabel?: string;
28
+ /** Logo element. */
29
+ logo?: React.ReactNode;
30
+ /** Additional content below the form (OAuth buttons, etc.). */
31
+ footer?: React.ReactNode;
32
+ className?: string;
33
+ style?: React.CSSProperties;
34
+ /** Email field label. */
35
+ emailLabel?: string;
36
+ /** Password field label. */
37
+ passwordLabel?: string;
38
+ }
39
+ /**
40
+ * {@link NiceLoginForm} — Login form with email, password, remember me,
41
+ * forgot password link, and optional OAuth footer.
42
+ */
43
+ export declare const NiceLoginForm: React.ForwardRefExoticComponent<NiceLoginFormProps & React.RefAttributes<HTMLFormElement>>;
44
+ //# sourceMappingURL=NiceLoginForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NiceLoginForm.d.ts","sourceRoot":"","sources":["../src/NiceLoginForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4C,MAAM,OAAO,CAAC;AAEjE,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3F,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wCAAwC;IACxC,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,yBAAyB;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,4FAqFxB,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { default as React } from 'react';
2
+ /** OAuth provider definition. */
3
+ export interface OAuthProvider {
4
+ /** Unique provider id. */
5
+ id: string;
6
+ /** Display label. */
7
+ label: string;
8
+ /** Icon (emoji, SVG element, or URL). */
9
+ icon?: React.ReactNode;
10
+ /** Brand color for the button. */
11
+ color?: string;
12
+ /** Text color. */
13
+ textColor?: string;
14
+ }
15
+ /** Props for the {@link NiceOAuthButtons} component. */
16
+ export interface NiceOAuthButtonsProps {
17
+ /** Providers to display. */
18
+ providers?: OAuthProvider[];
19
+ /** Fires when a provider button is clicked. */
20
+ onProviderClick?: (providerId: string) => void;
21
+ /** Whether buttons are disabled. */
22
+ disabled?: boolean;
23
+ /** Loading provider id (shows spinner on that button). */
24
+ loadingProvider?: string;
25
+ /** Layout direction. */
26
+ direction?: 'horizontal' | 'vertical';
27
+ /** Separator text (e.g. "or continue with"). */
28
+ separatorText?: string;
29
+ /** Whether to show separator above buttons. */
30
+ showSeparator?: boolean;
31
+ className?: string;
32
+ style?: React.CSSProperties;
33
+ }
34
+ /**
35
+ * {@link NiceOAuthButtons} — OAuth login/registration buttons for popular providers.
36
+ */
37
+ export declare const NiceOAuthButtons: React.ForwardRefExoticComponent<NiceOAuthButtonsProps & React.RefAttributes<HTMLDivElement>>;
38
+ //# sourceMappingURL=NiceOAuthButtons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NiceOAuthButtons.d.ts","sourceRoot":"","sources":["../src/NiceOAuthButtons.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,iCAAiC;AACjC,MAAM,WAAW,aAAa;IAC5B,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wDAAwD;AACxD,MAAM,WAAW,qBAAqB;IACpC,4BAA4B;IAC5B,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;IAC5B,+CAA+C;IAC/C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB;IACxB,SAAS,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACtC,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAUD;;GAEG;AACH,eAAO,MAAM,gBAAgB,8FAkC3B,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { default as React } from 'react';
2
+ /** Password strength level (0 = very weak, 4 = very strong). */
3
+ export type PasswordStrengthLevel = 0 | 1 | 2 | 3 | 4;
4
+ /** Props for the {@link NicePasswordStrength} component. */
5
+ export interface NicePasswordStrengthProps {
6
+ /** The password to evaluate. */
7
+ password: string;
8
+ /** Override calculated strength. */
9
+ strength?: PasswordStrengthLevel;
10
+ /** Whether to show text labels. */
11
+ showLabel?: boolean;
12
+ /** Custom labels for each level. */
13
+ labels?: Record<PasswordStrengthLevel, string>;
14
+ className?: string;
15
+ }
16
+ /** Calculate password strength score (0-4). */
17
+ export declare function calcPasswordStrength(password: string): PasswordStrengthLevel;
18
+ /**
19
+ * {@link NicePasswordStrength} — Visual password strength indicator bar
20
+ * with color-coded levels and text labels.
21
+ */
22
+ export declare const NicePasswordStrength: React.ForwardRefExoticComponent<NicePasswordStrengthProps & React.RefAttributes<HTMLDivElement>>;
23
+ //# sourceMappingURL=NicePasswordStrength.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NicePasswordStrength.d.ts","sourceRoot":"","sources":["../src/NicePasswordStrength.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,gEAAgE;AAChE,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtD,4DAA4D;AAC5D,MAAM,WAAW,yBAAyB;IACxC,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,mCAAmC;IACnC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD,+CAA+C;AAC/C,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAS5E;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,kGAgB/B,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { default as React } from 'react';
2
+ /** Registration data payload. */
3
+ export interface RegistrationData {
4
+ firstName: string;
5
+ lastName: string;
6
+ email: string;
7
+ password: string;
8
+ acceptTerms: boolean;
9
+ }
10
+ /** Props for the {@link NiceRegistrationForm} component. */
11
+ export interface NiceRegistrationFormProps {
12
+ /** Fires on form submit. */
13
+ onSubmit?: (data: RegistrationData) => void;
14
+ /** Whether a request is in progress. */
15
+ loading?: boolean;
16
+ /** External error message. */
17
+ error?: string;
18
+ /** Fires when "Login" link is clicked. */
19
+ onLoginClick?: () => void;
20
+ /** Whether to show password strength meter. */
21
+ showPasswordStrength?: boolean;
22
+ /** Minimum password strength level to allow submit (0-4). */
23
+ minPasswordStrength?: number;
24
+ /** Terms URL. */
25
+ termsUrl?: string;
26
+ /** Privacy URL. */
27
+ privacyUrl?: string;
28
+ /** Title. */
29
+ title?: string;
30
+ /** Logo element. */
31
+ logo?: React.ReactNode;
32
+ /** Footer content (OAuth buttons, etc.). */
33
+ footer?: React.ReactNode;
34
+ className?: string;
35
+ style?: React.CSSProperties;
36
+ }
37
+ /**
38
+ * {@link NiceRegistrationForm} — Registration form with name, email, password,
39
+ * strength meter, terms acceptance, and optional OAuth footer.
40
+ */
41
+ export declare const NiceRegistrationForm: React.ForwardRefExoticComponent<NiceRegistrationFormProps & React.RefAttributes<HTMLFormElement>>;
42
+ //# sourceMappingURL=NiceRegistrationForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NiceRegistrationForm.d.ts","sourceRoot":"","sources":["../src/NiceRegistrationForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4C,MAAM,OAAO,CAAC;AAGjE,iCAAiC;AACjC,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,4DAA4D;AAC5D,MAAM,WAAW,yBAAyB;IACxC,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,+CAA+C;IAC/C,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,6DAA6D;IAC7D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,mGAyF/B,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { default as React } from 'react';
2
+ /** API token entry. */
3
+ export interface ApiToken {
4
+ id: string;
5
+ name: string;
6
+ prefix: string;
7
+ createdAt: string;
8
+ expiresAt?: string;
9
+ lastUsedAt?: string;
10
+ scopes?: string[];
11
+ }
12
+ /** Props for {@link NiceTokenManagement}. */
13
+ export interface NiceTokenManagementProps {
14
+ /** Existing tokens. */
15
+ tokens: ApiToken[];
16
+ /** Called to create a new token. Should return the full token string (only shown once). */
17
+ onCreate?: (name: string, scopes: string[], expiresInDays?: number) => Promise<string>;
18
+ /** Called to revoke a token. */
19
+ onRevoke?: (tokenId: string) => Promise<void>;
20
+ /** Available scopes for new tokens. */
21
+ availableScopes?: string[];
22
+ /** Maximum number of tokens allowed. */
23
+ maxTokens?: number;
24
+ /** Title. */
25
+ title?: string;
26
+ /** CSS class name. */
27
+ className?: string;
28
+ /** Inline styles. */
29
+ style?: React.CSSProperties;
30
+ }
31
+ /**
32
+ * {@link NiceTokenManagement} — API token management UI.
33
+ *
34
+ * Create, view, and revoke personal API tokens. New token values are shown
35
+ * once after creation. Supports scopes and expiration.
36
+ */
37
+ export declare const NiceTokenManagement: React.ForwardRefExoticComponent<NiceTokenManagementProps & React.RefAttributes<HTMLDivElement>>;
38
+ //# sourceMappingURL=NiceTokenManagement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NiceTokenManagement.d.ts","sourceRoot":"","sources":["../src/NiceTokenManagement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4C,MAAM,OAAO,CAAC;AAIjE,uBAAuB;AACvB,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,6CAA6C;AAC7C,MAAM,WAAW,wBAAwB;IACvC,uBAAuB;IACvB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,aAAa,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvF,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,iGAkK9B,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { default as React } from 'react';
2
+ /** Props for the {@link NiceTwoFaSetup} component. */
3
+ export interface NiceTwoFaSetupProps {
4
+ /** The TOTP secret key (base32 encoded). */
5
+ secret: string;
6
+ /** QR code image URL or data URL for the authenticator app. */
7
+ qrCodeUrl?: string;
8
+ /** Issuer name for the TOTP URI. */
9
+ issuer?: string;
10
+ /** User's account name. */
11
+ accountName?: string;
12
+ /** Fires when user submits verification code. */
13
+ onVerify?: (code: string) => void;
14
+ /** Whether verification is in progress. */
15
+ loading?: boolean;
16
+ /** Error message (e.g. "Invalid code"). */
17
+ error?: string;
18
+ /** Fires on back/cancel. */
19
+ onCancel?: () => void;
20
+ /** Recovery codes to display after setup. */
21
+ recoveryCodes?: string[];
22
+ /** Step: 'setup' = show QR, 'verify' = enter code, 'recovery' = show codes. */
23
+ step?: 'setup' | 'verify' | 'recovery';
24
+ /** Fires when step changes. */
25
+ onStepChange?: (step: 'setup' | 'verify' | 'recovery') => void;
26
+ className?: string;
27
+ style?: React.CSSProperties;
28
+ }
29
+ /**
30
+ * {@link NiceTwoFaSetup} — Two-factor authentication setup wizard with
31
+ * QR code display, secret key, verification code input, and recovery codes.
32
+ */
33
+ export declare const NiceTwoFaSetup: React.ForwardRefExoticComponent<NiceTwoFaSetupProps & React.RefAttributes<HTMLDivElement>>;
34
+ //# sourceMappingURL=NiceTwoFaSetup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NiceTwoFaSetup.d.ts","sourceRoot":"","sources":["../src/NiceTwoFaSetup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4C,MAAM,OAAO,CAAC;AAEjE,sDAAsD;AACtD,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;IACvC,+BAA+B;IAC/B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,KAAK,IAAI,CAAC;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,4FAmHzB,CAAC"}
package/dist/index.cjs ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react"),e=require("react/jsx-runtime");function B(n={}){const{onLogin:s,onRefresh:d,onLogout:m,storageKey:u="nice_auth",persistAuth:f=!1}=n,[i,p]=t.useState(()=>{if(f&&typeof window<"u")try{const o=localStorage.getItem(u);if(o)return{...JSON.parse(o),loading:!1,error:null}}catch{}return{isAuthenticated:!1,user:null,tokens:null,loading:!1,error:null}}),c=t.useCallback(o=>{p(l=>{const h={...l,...o};return f&&typeof window<"u"&&(h.isAuthenticated?localStorage.setItem(u,JSON.stringify({isAuthenticated:!0,user:h.user,tokens:h.tokens})):localStorage.removeItem(u)),h})},[f,u]),b=t.useCallback(async(o,l)=>{c({loading:!0,error:null});try{if(s){const h=await s(o,l);return c({isAuthenticated:!0,user:h.user,tokens:h.tokens,loading:!1}),!0}return c({loading:!1,error:"No login handler configured"}),!1}catch(h){return c({loading:!1,error:(h==null?void 0:h.message)??"Login failed"}),!1}},[s,c]),a=t.useCallback(()=>{m==null||m(),c({isAuthenticated:!1,user:null,tokens:null,loading:!1,error:null})},[m,c]),w=t.useCallback(async()=>{var o;if(!((o=i.tokens)!=null&&o.refreshToken)||!d)return!1;try{const l=await d(i.tokens.refreshToken);return c({tokens:l}),!0}catch{return a(),!1}},[i.tokens,d,c,a]),g=t.useCallback((o,l)=>{c({isAuthenticated:!0,user:o,tokens:l,loading:!1,error:null})},[c]),y=t.useCallback((...o)=>i.user?o.every(l=>i.user.roles.includes(l)):!1,[i.user]),_=t.useCallback((...o)=>i.user?o.every(l=>i.user.permissions.includes(l)):!1,[i.user]),v=t.useCallback(()=>{c({error:null})},[c]);return{...i,login:b,logout:a,refreshToken:w,setAuth:g,hasRoles:y,hasPermissions:_,clearError:v}}const D=t.forwardRef(({onSubmit:n,loading:s=!1,error:d,showRememberMe:m=!0,showForgotPassword:u=!0,onForgotPassword:f,showRegisterLink:i=!0,onRegisterClick:p,title:c="Sign In",submitLabel:b="Sign In",logo:a,footer:w,className:g,style:y,emailLabel:_="Email",passwordLabel:v="Password"},o)=>{const[l,h]=t.useState(""),[C,x]=t.useState(""),[S,N]=t.useState(!1),A=t.useCallback(k=>{k.preventDefault(),n==null||n({email:l,password:C,rememberMe:S})},[l,C,S,n]);return e.jsxs("form",{ref:o,className:`nice-login-form${g?` ${g}`:""}`,style:y,onSubmit:A,noValidate:!0,children:[a&&e.jsx("div",{className:"nice-login-form__logo",children:a}),e.jsx("h2",{className:"nice-login-form__title",children:c}),d&&e.jsx("div",{className:"nice-login-form__error",role:"alert",children:d}),e.jsxs("div",{className:"nice-login-form__field",children:[e.jsx("label",{htmlFor:"nice-login-email",children:_}),e.jsx("input",{id:"nice-login-email",className:"nice-input",type:"email",value:l,onChange:k=>h(k.target.value),autoComplete:"email",required:!0,disabled:s})]}),e.jsxs("div",{className:"nice-login-form__field",children:[e.jsx("label",{htmlFor:"nice-login-password",children:v}),e.jsx("input",{id:"nice-login-password",className:"nice-input",type:"password",value:C,onChange:k=>x(k.target.value),autoComplete:"current-password",required:!0,disabled:s})]}),e.jsxs("div",{className:"nice-login-form__options",children:[m&&e.jsxs("label",{className:"nice-login-form__remember",children:[e.jsx("input",{type:"checkbox",checked:S,onChange:k=>N(k.target.checked),disabled:s}),e.jsx("span",{children:"Remember me"})]}),u&&e.jsx("button",{type:"button",className:"nice-login-form__forgot",onClick:f,disabled:s,children:"Forgot password?"})]}),e.jsx("button",{type:"submit",className:"nice-btn nice-btn--primary nice-login-form__submit",disabled:s||!l||!C,children:s?"…":b}),i&&e.jsxs("div",{className:"nice-login-form__register",children:[e.jsx("span",{children:"Don't have an account? "}),e.jsx("button",{type:"button",onClick:p,disabled:s,children:"Register"})]}),w&&e.jsx("div",{className:"nice-login-form__footer",children:w})]})});D.displayName="NiceLoginForm";const G={0:"Very weak",1:"Weak",2:"Fair",3:"Strong",4:"Very strong"},Q={0:"#d9534f",1:"#f0ad4e",2:"#5bc0de",3:"#5cb85c",4:"#2e7d32"};function R(n){if(!n)return 0;let s=0;return n.length>=8&&s++,n.length>=12&&s++,/[a-z]/.test(n)&&/[A-Z]/.test(n)&&s++,/\d/.test(n)&&s++,/[^a-zA-Z0-9]/.test(n)&&s++,Math.min(4,s)}const P=t.forwardRef(({password:n,strength:s,showLabel:d=!0,labels:m=G,className:u},f)=>{const i=s??R(n),p=Q[i],c=(i+1)/5*100;return e.jsxs("div",{ref:f,className:`nice-password-strength${u?` ${u}`:""}`,children:[e.jsx("div",{className:"nice-password-strength__bar",children:e.jsx("div",{className:"nice-password-strength__fill",style:{width:`${c}%`,backgroundColor:p}})}),d&&e.jsx("span",{className:"nice-password-strength__label",style:{color:p},children:m[i]})]})});P.displayName="NicePasswordStrength";const L=t.forwardRef(({onSubmit:n,loading:s=!1,error:d,onLoginClick:m,showPasswordStrength:u=!0,minPasswordStrength:f=2,termsUrl:i,privacyUrl:p,title:c="Create Account",logo:b,footer:a,className:w,style:g},y)=>{const[_,v]=t.useState(""),[o,l]=t.useState(""),[h,C]=t.useState(""),[x,S]=t.useState(""),[N,A]=t.useState(""),[k,T]=t.useState(!1),E=R(x),$=x===N,F=_&&h&&x&&$&&k&&E>=f&&!s,r=t.useCallback(j=>{j.preventDefault(),F&&(n==null||n({firstName:_,lastName:o,email:h,password:x,acceptTerms:k}))},[F,_,o,h,x,k,n]);return e.jsxs("form",{ref:y,className:`nice-register-form${w?` ${w}`:""}`,style:g,onSubmit:r,noValidate:!0,children:[b&&e.jsx("div",{className:"nice-register-form__logo",children:b}),e.jsx("h2",{className:"nice-register-form__title",children:c}),d&&e.jsx("div",{className:"nice-register-form__error",role:"alert",children:d}),e.jsxs("div",{className:"nice-register-form__row",children:[e.jsxs("div",{className:"nice-register-form__field",children:[e.jsx("label",{htmlFor:"nice-reg-first",children:"First name *"}),e.jsx("input",{id:"nice-reg-first",className:"nice-input",type:"text",value:_,onChange:j=>v(j.target.value),required:!0,disabled:s,autoComplete:"given-name"})]}),e.jsxs("div",{className:"nice-register-form__field",children:[e.jsx("label",{htmlFor:"nice-reg-last",children:"Last name"}),e.jsx("input",{id:"nice-reg-last",className:"nice-input",type:"text",value:o,onChange:j=>l(j.target.value),disabled:s,autoComplete:"family-name"})]})]}),e.jsxs("div",{className:"nice-register-form__field",children:[e.jsx("label",{htmlFor:"nice-reg-email",children:"Email *"}),e.jsx("input",{id:"nice-reg-email",className:"nice-input",type:"email",value:h,onChange:j=>C(j.target.value),required:!0,disabled:s,autoComplete:"email"})]}),e.jsxs("div",{className:"nice-register-form__field",children:[e.jsx("label",{htmlFor:"nice-reg-pass",children:"Password *"}),e.jsx("input",{id:"nice-reg-pass",className:"nice-input",type:"password",value:x,onChange:j=>S(j.target.value),required:!0,disabled:s,autoComplete:"new-password"}),u&&x.length>0&&e.jsx(P,{password:x})]}),e.jsxs("div",{className:"nice-register-form__field",children:[e.jsx("label",{htmlFor:"nice-reg-confirm",children:"Confirm password *"}),e.jsx("input",{id:"nice-reg-confirm",className:"nice-input",type:"password",value:N,onChange:j=>A(j.target.value),required:!0,disabled:s,autoComplete:"new-password"}),N&&!$&&e.jsx("span",{className:"nice-error-text",children:"Passwords do not match"})]}),e.jsxs("label",{className:"nice-register-form__terms",children:[e.jsx("input",{type:"checkbox",checked:k,onChange:j=>T(j.target.checked),disabled:s}),e.jsxs("span",{children:["I accept the"," ",i?e.jsx("a",{href:i,target:"_blank",rel:"noopener noreferrer",children:"Terms"}):"Terms",p&&e.jsxs(e.Fragment,{children:[" and ",e.jsx("a",{href:p,target:"_blank",rel:"noopener noreferrer",children:"Privacy Policy"})]})," *"]})]}),e.jsx("button",{type:"submit",className:"nice-btn nice-btn--primary nice-register-form__submit",disabled:!F,children:s?"…":"Register"}),m&&e.jsxs("div",{className:"nice-register-form__login",children:[e.jsx("span",{children:"Already have an account? "}),e.jsx("button",{type:"button",onClick:m,children:"Sign in"})]}),a&&e.jsx("div",{className:"nice-register-form__footer",children:a})]})});L.displayName="NiceRegistrationForm";const M=t.forwardRef(({requireCurrentPassword:n=!0,onSubmit:s,loading:d=!1,error:m,success:u,minPasswordStrength:f=2,title:i="Change Password",className:p,style:c},b)=>{const[a,w]=t.useState(""),[g,y]=t.useState(""),[_,v]=t.useState(""),o=R(g),l=g===_,h=(!n||a.length>0)&&g.length>0&&l&&o>=f&&!d,C=t.useCallback(x=>{x.preventDefault(),h&&(s==null||s({currentPassword:n?a:void 0,newPassword:g}))},[h,a,g,n,s]);return e.jsxs("form",{ref:b,className:`nice-change-password${p?` ${p}`:""}`,style:c,onSubmit:C,noValidate:!0,children:[e.jsx("h3",{className:"nice-change-password__title",children:i}),m&&e.jsx("div",{className:"nice-change-password__error",role:"alert",children:m}),u&&e.jsx("div",{className:"nice-change-password__success",role:"status",children:u}),n&&e.jsxs("div",{className:"nice-change-password__field",children:[e.jsx("label",{htmlFor:"nice-cp-current",children:"Current password"}),e.jsx("input",{id:"nice-cp-current",className:"nice-input",type:"password",value:a,onChange:x=>w(x.target.value),autoComplete:"current-password",disabled:d,required:!0})]}),e.jsxs("div",{className:"nice-change-password__field",children:[e.jsx("label",{htmlFor:"nice-cp-new",children:"New password"}),e.jsx("input",{id:"nice-cp-new",className:"nice-input",type:"password",value:g,onChange:x=>y(x.target.value),autoComplete:"new-password",disabled:d,required:!0}),g.length>0&&e.jsx(P,{password:g})]}),e.jsxs("div",{className:"nice-change-password__field",children:[e.jsx("label",{htmlFor:"nice-cp-confirm",children:"Confirm new password"}),e.jsx("input",{id:"nice-cp-confirm",className:"nice-input",type:"password",value:_,onChange:x=>v(x.target.value),autoComplete:"new-password",disabled:d,required:!0}),_&&!l&&e.jsx("span",{className:"nice-error-text",children:"Passwords do not match"})]}),e.jsx("button",{type:"submit",className:"nice-btn nice-btn--primary",disabled:!h,children:d?"…":"Change Password"})]})});M.displayName="NiceChangePassword";const I=t.forwardRef(({secret:n,qrCodeUrl:s,issuer:d,accountName:m,onVerify:u,loading:f=!1,error:i,onCancel:p,recoveryCodes:c,step:b="setup",onStepChange:a,className:w,style:g},y)=>{const[_,v]=t.useState(""),[o,l]=t.useState(!1),[h,C]=t.useState(!1),x=t.useCallback(N=>{N.preventDefault(),_.length>=6&&(u==null||u(_))},[_,u]),S=`otpauth://totp/${d?`${d}:`:""}${m??"user"}?secret=${n}${d?`&issuer=${d}`:""}&digits=6&period=30`;return e.jsxs("div",{ref:y,className:`nice-2fa-setup${w?` ${w}`:""}`,style:g,children:[e.jsx("h3",{className:"nice-2fa-setup__title",children:"Two-Factor Authentication"}),b==="setup"&&e.jsxs("div",{className:"nice-2fa-setup__step",children:[e.jsx("p",{className:"nice-2fa-setup__instruction",children:"Scan this QR code with your authenticator app (Google Authenticator, Authy, etc.):"}),s?e.jsx("img",{src:s,alt:"2FA QR Code",className:"nice-2fa-setup__qr"}):e.jsxs("div",{className:"nice-2fa-setup__qr-placeholder",children:[e.jsx("span",{children:"QR Code"}),e.jsx("code",{className:"nice-2fa-setup__uri",children:S})]}),e.jsxs("div",{className:"nice-2fa-setup__secret",children:[e.jsx("span",{children:"Or enter manually: "}),o?e.jsx("code",{className:"nice-2fa-setup__secret-key",children:n}):e.jsx("button",{type:"button",onClick:()=>l(!0),children:"Show secret key"})]}),e.jsx("button",{type:"button",className:"nice-btn nice-btn--primary",onClick:()=>a==null?void 0:a("verify"),children:"Next — Verify"})]}),b==="verify"&&e.jsxs("form",{className:"nice-2fa-setup__step",onSubmit:x,children:[e.jsx("p",{className:"nice-2fa-setup__instruction",children:"Enter the 6-digit code from your authenticator app:"}),i&&e.jsx("div",{className:"nice-2fa-setup__error",role:"alert",children:i}),e.jsx("input",{className:"nice-input nice-2fa-setup__code-input",type:"text",inputMode:"numeric",maxLength:6,value:_,onChange:N=>v(N.target.value.replace(/\D/g,"").slice(0,6)),placeholder:"000000",autoFocus:!0,disabled:f,autoComplete:"one-time-code"}),e.jsxs("div",{className:"nice-2fa-setup__actions",children:[e.jsx("button",{type:"button",className:"nice-btn",onClick:()=>a==null?void 0:a("setup"),children:"Back"}),e.jsx("button",{type:"submit",className:"nice-btn nice-btn--primary",disabled:f||_.length<6,children:f?"…":"Verify"})]})]}),b==="recovery"&&c&&e.jsxs("div",{className:"nice-2fa-setup__step",children:[e.jsx("p",{className:"nice-2fa-setup__instruction",children:"Save these recovery codes in a safe place. Each code can only be used once:"}),e.jsx("div",{className:"nice-2fa-setup__recovery-codes",children:c.map((N,A)=>e.jsx("code",{className:"nice-2fa-setup__recovery-code",children:N},A))}),e.jsx("button",{type:"button",className:"nice-btn",onClick:()=>{var N;(N=navigator.clipboard)==null||N.writeText(c.join(`
2
+ `)),C(!0)},children:h?"Copied!":"Copy all codes"}),p&&e.jsx("button",{type:"button",className:"nice-btn nice-btn--primary",onClick:p,children:"Done"})]}),p&&b!=="recovery"&&e.jsx("button",{type:"button",className:"nice-2fa-setup__cancel",onClick:p,children:"Cancel"})]})});I.displayName="NiceTwoFaSetup";const O=t.forwardRef(({provider:n="custom",siteKey:s,onVerify:d,onExpire:m,onError:u,theme:f="light",size:i="normal",customRender:p,className:c,style:b},a)=>n==="custom"&&p?e.jsx("div",{ref:a,className:`nice-captcha nice-captcha--custom${c?` ${c}`:""}`,style:b,children:p}):e.jsx("div",{ref:a,className:`nice-captcha nice-captcha--${n} nice-captcha--${f}${i==="compact"?" nice-captcha--compact":""}${c?` ${c}`:""}`,style:b,"data-sitekey":s,"data-theme":f,"data-size":i,children:e.jsxs("div",{className:"nice-captcha__placeholder",children:[e.jsxs("span",{children:["🔒 Captcha (",n,")"]}),e.jsxs("p",{children:["Load the ",n," SDK to activate verification."]})]})}));O.displayName="NiceCaptcha";const z=[{id:"google",label:"Google",icon:"🔵",color:"#4285f4",textColor:"#fff"},{id:"microsoft",label:"Microsoft",icon:"🟦",color:"#00a4ef",textColor:"#fff"},{id:"discord",label:"Discord",icon:"💬",color:"#5865f2",textColor:"#fff"},{id:"spotify",label:"Spotify",icon:"🎵",color:"#1db954",textColor:"#fff"},{id:"github",label:"GitHub",icon:"🐙",color:"#24292e",textColor:"#fff"}],q=t.forwardRef(({providers:n=z,onProviderClick:s,disabled:d=!1,loadingProvider:m,direction:u="vertical",separatorText:f="or continue with",showSeparator:i=!0,className:p,style:c},b)=>e.jsxs("div",{ref:b,className:`nice-oauth nice-oauth--${u}${p?` ${p}`:""}`,style:c,children:[i&&e.jsxs("div",{className:"nice-oauth__separator",children:[e.jsx("hr",{}),e.jsx("span",{children:f}),e.jsx("hr",{})]}),e.jsx("div",{className:"nice-oauth__buttons",children:n.map(a=>e.jsxs("button",{type:"button",className:`nice-oauth__btn${m===a.id?" nice-oauth__btn--loading":""}`,style:{backgroundColor:a.color,color:a.textColor},onClick:()=>s==null?void 0:s(a.id),disabled:d||!!m,children:[a.icon&&e.jsx("span",{className:"nice-oauth__btn-icon",children:a.icon}),e.jsx("span",{className:"nice-oauth__btn-label",children:m===a.id?"…":a.label})]},a.id))})]}));q.displayName="NiceOAuthButtons";const J=t.forwardRef(function(s,d){const{tokens:m,onCreate:u,onRevoke:f,availableScopes:i=[],maxTokens:p=10,title:c="API Tokens",className:b,style:a}=s,[w,g]=t.useState(!1),[y,_]=t.useState(""),[v,o]=t.useState([]),[l,h]=t.useState("90"),[C,x]=t.useState(null),[S,N]=t.useState(!1),[A,k]=t.useState(null),T=t.useCallback(async()=>{if(!(!u||!y.trim())){N(!0);try{const r=l?parseInt(l,10):void 0,j=await u(y.trim(),v,r);x(j),_(""),o([]),g(!1)}finally{N(!1)}}},[u,y,v,l]),E=t.useCallback(async r=>{if(f){k(r);try{await f(r)}finally{k(null)}}},[f]),$=r=>{o(j=>j.includes(r)?j.filter(V=>V!==r):[...j,r])},F=m.length<p;return e.jsxs("div",{ref:d,className:`nice-token-management ${b??""}`,style:a,children:[e.jsxs("div",{className:"nice-token-management__header",children:[e.jsx("h3",{children:c}),F&&e.jsx("button",{className:"nice-token-management__new-btn",onClick:()=>g(!0),disabled:w,children:"+ New Token"})]}),C&&e.jsxs("div",{className:"nice-token-management__reveal",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"New token created!"})," Copy it now — it won't be shown again."]}),e.jsx("code",{className:"nice-token-management__token-value",children:C}),e.jsx("button",{onClick:()=>x(null),children:"Dismiss"})]}),w&&e.jsxs("div",{className:"nice-token-management__create-form",children:[e.jsxs("label",{children:["Name",e.jsx("input",{type:"text",value:y,onChange:r=>_(r.target.value),placeholder:"My API token",maxLength:64})]}),i.length>0&&e.jsxs("fieldset",{children:[e.jsx("legend",{children:"Scopes"}),i.map(r=>e.jsxs("label",{className:"nice-token-management__scope",children:[e.jsx("input",{type:"checkbox",checked:v.includes(r),onChange:()=>$(r)}),r]},r))]}),e.jsxs("label",{children:["Expires in (days)",e.jsx("input",{type:"number",value:l,onChange:r=>h(r.target.value),min:1,max:365})]}),e.jsxs("div",{className:"nice-token-management__create-actions",children:[e.jsx("button",{onClick:T,disabled:S||!y.trim(),children:S?"Creating…":"Create Token"}),e.jsx("button",{onClick:()=>g(!1),children:"Cancel"})]})]}),m.length===0?e.jsx("p",{className:"nice-token-management__empty",children:"No API tokens yet."}):e.jsxs("table",{className:"nice-token-management__table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Name"}),e.jsx("th",{children:"Prefix"}),e.jsx("th",{children:"Created"}),e.jsx("th",{children:"Expires"}),e.jsx("th",{children:"Last Used"}),e.jsx("th",{children:"Scopes"}),e.jsx("th",{})]})}),e.jsx("tbody",{children:m.map(r=>{var j;return e.jsxs("tr",{children:[e.jsx("td",{children:r.name}),e.jsx("td",{children:e.jsxs("code",{children:[r.prefix,"…"]})}),e.jsx("td",{children:r.createdAt}),e.jsx("td",{children:r.expiresAt??"—"}),e.jsx("td",{children:r.lastUsedAt??"Never"}),e.jsx("td",{children:((j=r.scopes)==null?void 0:j.join(", "))||"—"}),e.jsx("td",{children:e.jsx("button",{className:"nice-token-management__revoke-btn",onClick:()=>E(r.id),disabled:A===r.id,children:A===r.id?"Revoking…":"Revoke"})})]},r.id)})})]})]})});exports.NiceCaptcha=O;exports.NiceChangePassword=M;exports.NiceLoginForm=D;exports.NiceOAuthButtons=q;exports.NicePasswordStrength=P;exports.NiceRegistrationForm=L;exports.NiceTokenManagement=J;exports.NiceTwoFaSetup=I;exports.calcPasswordStrength=R;exports.useAuth=B;
3
+ //# sourceMappingURL=index.cjs.map