@nice2dev/auth 0.1.0 → 1.0.3
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 +20 -1
- package/dist/__tests__/NiceCaptcha.test.d.ts +2 -0
- package/dist/__tests__/NiceCaptcha.test.d.ts.map +1 -0
- package/dist/__tests__/NiceChangePassword.test.d.ts +2 -0
- package/dist/__tests__/NiceChangePassword.test.d.ts.map +1 -0
- package/dist/__tests__/NiceLoginForm.test.d.ts +2 -0
- package/dist/__tests__/NiceLoginForm.test.d.ts.map +1 -0
- package/dist/__tests__/NiceOAuthButtons.test.d.ts +2 -0
- package/dist/__tests__/NiceOAuthButtons.test.d.ts.map +1 -0
- package/dist/__tests__/NicePasswordStrength.test.d.ts +2 -0
- package/dist/__tests__/NicePasswordStrength.test.d.ts.map +1 -0
- package/dist/__tests__/NiceRegistrationForm.test.d.ts +2 -0
- package/dist/__tests__/NiceRegistrationForm.test.d.ts.map +1 -0
- package/dist/__tests__/NiceTokenManagement.test.d.ts +2 -0
- package/dist/__tests__/NiceTokenManagement.test.d.ts.map +1 -0
- package/dist/__tests__/NiceTwoFaSetup.test.d.ts +2 -0
- package/dist/__tests__/NiceTwoFaSetup.test.d.ts.map +1 -0
- package/dist/__tests__/setup.d.ts +1 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/useAuth.test.d.ts +2 -0
- package/dist/__tests__/useAuth.test.d.ts.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +61 -61
- package/dist/index.mjs.map +1 -1
- package/dist/useAuth.d.ts.map +1 -1
- package/package.json +26 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
# Changelog
|
|
1
|
+
# @nice2dev/auth — Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.0] — 2026-03-25
|
|
4
|
+
|
|
5
|
+
### Added (FAZA 7.6)
|
|
6
|
+
|
|
7
|
+
- **LoginForm** — complete login with validation, remember me, forgot password link
|
|
8
|
+
- **RegisterForm** — registration with password strength meter
|
|
9
|
+
- **OAuthButtons** — Google, Microsoft, GitHub, Apple, Facebook sign-in
|
|
10
|
+
- **TwoFactorSetup** — TOTP/SMS/email 2FA configuration
|
|
11
|
+
- **PasswordReset** — reset flow (email, code, new password)
|
|
12
|
+
- **SessionManager** — active sessions list with revoke
|
|
13
|
+
- **TokenRefresher** — automatic JWT token refresh
|
|
14
|
+
- 9 unit tests
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## [0.1.0] — 2025-06-01
|
|
19
|
+
|
|
20
|
+
Initial beta scaffolding.
|
|
2
21
|
|
|
3
22
|
All notable changes to this project will be documented in this file.
|
|
4
23
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NiceCaptcha.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/NiceCaptcha.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NiceChangePassword.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/NiceChangePassword.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NiceLoginForm.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/NiceLoginForm.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NiceOAuthButtons.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/NiceOAuthButtons.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NicePasswordStrength.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/NicePasswordStrength.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NiceRegistrationForm.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/NiceRegistrationForm.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NiceTokenManagement.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/NiceTokenManagement.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NiceTwoFaSetup.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/NiceTwoFaSetup.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AACA,OAAO,kCAAkC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuth.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/useAuth.test.ts"],"names":[],"mappings":""}
|
package/dist/index.cjs
CHANGED
|
@@ -1,3 +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:
|
|
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:h,storageKey:u="nice_auth",persistAuth:f=!1}=n,[i,m]=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=>{m(l=>{const p={...l,...o};return f&&typeof window<"u"&&(p.isAuthenticated?localStorage.setItem(u,JSON.stringify({isAuthenticated:!0,user:p.user})):localStorage.removeItem(u)),p})},[f,u]),b=t.useCallback(async(o,l)=>{c({loading:!0,error:null});try{if(s){const p=await s(o,l);return c({isAuthenticated:!0,user:p.user,tokens:p.tokens,loading:!1}),!0}return c({loading:!1,error:"No login handler configured"}),!1}catch(p){return c({loading:!1,error:(p==null?void 0:p.message)??"Login failed"}),!1}},[s,c]),a=t.useCallback(()=>{h==null||h(),c({isAuthenticated:!1,user:null,tokens:null,loading:!1,error:null})},[h,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:h=!0,showForgotPassword:u=!0,onForgotPassword:f,showRegisterLink:i=!0,onRegisterClick:m,title:c="Sign In",submitLabel:b="Sign In",logo:a,footer:w,className:g,style:y,emailLabel:_="Email",passwordLabel:v="Password"},o)=>{const[l,p]=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=>p(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:[h&&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:m,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:h=G,className:u},f)=>{const i=s??R(n),m=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:m}})}),d&&e.jsx("span",{className:"nice-password-strength__label",style:{color:m},children:h[i]})]})});P.displayName="NicePasswordStrength";const L=t.forwardRef(({onSubmit:n,loading:s=!1,error:d,onLoginClick:h,showPasswordStrength:u=!0,minPasswordStrength:f=2,termsUrl:i,privacyUrl:m,title:c="Create Account",logo:b,footer:a,className:w,style:g},y)=>{const[_,v]=t.useState(""),[o,l]=t.useState(""),[p,C]=t.useState(""),[x,S]=t.useState(""),[N,A]=t.useState(""),[k,T]=t.useState(!1),E=R(x),$=x===N,F=_&&p&&x&&$&&k&&E>=f&&!s,r=t.useCallback(j=>{j.preventDefault(),F&&(n==null||n({firstName:_,lastName:o,email:p,password:x,acceptTerms:k}))},[F,_,o,p,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:p,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",m&&e.jsxs(e.Fragment,{children:[" and ",e.jsx("a",{href:m,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"}),h&&e.jsxs("div",{className:"nice-register-form__login",children:[e.jsx("span",{children:"Already have an account? "}),e.jsx("button",{type:"button",onClick:h,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:h,success:u,minPasswordStrength:f=2,title:i="Change Password",className:m,style:c},b)=>{const[a,w]=t.useState(""),[g,y]=t.useState(""),[_,v]=t.useState(""),o=R(g),l=g===_,p=(!n||a.length>0)&&g.length>0&&l&&o>=f&&!d,C=t.useCallback(x=>{x.preventDefault(),p&&(s==null||s({currentPassword:n?a:void 0,newPassword:g}))},[p,a,g,n,s]);return e.jsxs("form",{ref:b,className:`nice-change-password${m?` ${m}`:""}`,style:c,onSubmit:C,noValidate:!0,children:[e.jsx("h3",{className:"nice-change-password__title",children:i}),h&&e.jsx("div",{className:"nice-change-password__error",role:"alert",children:h}),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:!p,children:d?"…":"Change Password"})]})});M.displayName="NiceChangePassword";const I=t.forwardRef(({secret:n,qrCodeUrl:s,issuer:d,accountName:h,onVerify:u,loading:f=!1,error:i,onCancel:m,recoveryCodes:c,step:b="setup",onStepChange:a,className:w,style:g},y)=>{const[_,v]=t.useState(""),[o,l]=t.useState(!1),[p,C]=t.useState(!1),x=t.useCallback(N=>{N.preventDefault(),_.length>=6&&(u==null||u(_))},[_,u]),S=`otpauth://totp/${d?`${d}:`:""}${h??"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:p?"Copied!":"Copy all codes"}),m&&e.jsx("button",{type:"button",className:"nice-btn nice-btn--primary",onClick:m,children:"Done"})]}),m&&b!=="recovery"&&e.jsx("button",{type:"button",className:"nice-2fa-setup__cancel",onClick:m,children:"Cancel"})]})});I.displayName="NiceTwoFaSetup";const O=t.forwardRef(({provider:n="custom",siteKey:s,onVerify:d,onExpire:h,onError:u,theme:f="light",size:i="normal",customRender:m,className:c,style:b},a)=>n==="custom"&&m?e.jsx("div",{ref:a,className:`nice-captcha nice-captcha--custom${c?` ${c}`:""}`,style:b,children:m}):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:h,direction:u="vertical",separatorText:f="or continue with",showSeparator:i=!0,className:m,style:c},b)=>e.jsxs("div",{ref:b,className:`nice-oauth nice-oauth--${u}${m?` ${m}`:""}`,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${h===a.id?" nice-oauth__btn--loading":""}`,style:{backgroundColor:a.color,color:a.textColor},onClick:()=>s==null?void 0:s(a.id),disabled:d||!!h,children:[a.icon&&e.jsx("span",{className:"nice-oauth__btn-icon",children:a.icon}),e.jsx("span",{className:"nice-oauth__btn-label",children:h===a.id?"…":a.label})]},a.id))})]}));q.displayName="NiceOAuthButtons";const J=t.forwardRef(function(s,d){const{tokens:h,onCreate:u,onRevoke:f,availableScopes:i=[],maxTokens:m=10,title:c="API Tokens",className:b,style:a}=s,[w,g]=t.useState(!1),[y,_]=t.useState(""),[v,o]=t.useState([]),[l,p]=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=h.length<m;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=>p(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"})]})]}),h.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:h.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
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/useAuth.ts","../src/NiceLoginForm.tsx","../src/NicePasswordStrength.tsx","../src/NiceRegistrationForm.tsx","../src/NiceChangePassword.tsx","../src/NiceTwoFaSetup.tsx","../src/NiceCaptcha.tsx","../src/NiceOAuthButtons.tsx","../src/NiceTokenManagement.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\r\n\r\n/** User info from auth. */\r\nexport interface AuthUser {\r\n id: string;\r\n email: string;\r\n name?: string;\r\n avatarUrl?: string;\r\n roles: string[];\r\n permissions: string[];\r\n}\r\n\r\n/** Auth tokens. */\r\nexport interface AuthTokens {\r\n accessToken: string;\r\n refreshToken?: string;\r\n expiresAt?: number;\r\n}\r\n\r\n/** Auth state. */\r\nexport interface AuthState {\r\n /** Whether the user is authenticated. */\r\n isAuthenticated: boolean;\r\n /** Current user info. */\r\n user: AuthUser | null;\r\n /** Tokens (for advanced usage). */\r\n tokens: AuthTokens | null;\r\n /** Whether a login/refresh is in progress. */\r\n loading: boolean;\r\n /** Last auth error. */\r\n error: string | null;\r\n}\r\n\r\n/** Auth actions returned by useAuth. */\r\nexport interface AuthActions {\r\n /** Login with credentials. Returns success status. */\r\n login: (email: string, password: string) => Promise<boolean>;\r\n /** Logout and clear tokens. */\r\n logout: () => void;\r\n /** Refresh the access token. */\r\n refreshToken: () => Promise<boolean>;\r\n /** Set auth state from external source (e.g. SSO callback). */\r\n setAuth: (user: AuthUser, tokens: AuthTokens) => void;\r\n /** Check if user has all specified roles. */\r\n hasRoles: (...roles: string[]) => boolean;\r\n /** Check if user has all specified permissions. */\r\n hasPermissions: (...permissions: string[]) => boolean;\r\n /** Clear error. */\r\n clearError: () => void;\r\n}\r\n\r\n/** Configuration for useAuth. */\r\nexport interface UseAuthConfig {\r\n /** Login endpoint. */\r\n loginUrl?: string;\r\n /** Refresh endpoint. */\r\n refreshUrl?: string;\r\n /** Logout endpoint. */\r\n logoutUrl?: string;\r\n /** Custom login handler (overrides loginUrl). */\r\n onLogin?: (email: string, password: string) => Promise<{ user: AuthUser; tokens: AuthTokens }>;\r\n /** Custom refresh handler (overrides refreshUrl). */\r\n onRefresh?: (refreshToken: string) => Promise<AuthTokens>;\r\n /** Custom logout handler. */\r\n onLogout?: () => void | Promise<void>;\r\n /** Storage key for persisting auth state. */\r\n storageKey?: string;\r\n /** Whether to persist in localStorage. */\r\n persistAuth?: boolean;\r\n}\r\n\r\n/**\r\n * {@link useAuth} — Auth state management hook with JWT, roles, refresh token, and logout.\r\n * \r\n * Usage:\r\n * ```tsx\r\n * const { isAuthenticated, user, login, logout, hasRoles } = useAuth({\r\n * onLogin: async (email, password) => {\r\n * const res = await api.login(email, password);\r\n * return { user: res.user, tokens: { accessToken: res.token } };\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport function useAuth(config: UseAuthConfig = {}): AuthState & AuthActions {\r\n const { onLogin, onRefresh, onLogout, storageKey = 'nice_auth', persistAuth = false } = config;\r\n\r\n const [state, setState] = useState<AuthState>(() => {\r\n if (persistAuth && typeof window !== 'undefined') {\r\n try {\r\n const stored = localStorage.getItem(storageKey);\r\n if (stored) {\r\n const parsed = JSON.parse(stored);\r\n return { ...parsed, loading: false, error: null };\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n return { isAuthenticated: false, user: null, tokens: null, loading: false, error: null };\r\n });\r\n\r\n const persist = useCallback((newState: Partial<AuthState>) => {\r\n setState(prev => {\r\n const next = { ...prev, ...newState };\r\n if (persistAuth && typeof window !== 'undefined') {\r\n if (next.isAuthenticated) {\r\n localStorage.setItem(storageKey, JSON.stringify({ isAuthenticated: true, user: next.user, tokens: next.tokens }));\r\n } else {\r\n localStorage.removeItem(storageKey);\r\n }\r\n }\r\n return next;\r\n });\r\n }, [persistAuth, storageKey]);\r\n\r\n const login = useCallback(async (email: string, password: string): Promise<boolean> => {\r\n persist({ loading: true, error: null });\r\n try {\r\n if (onLogin) {\r\n const result = await onLogin(email, password);\r\n persist({ isAuthenticated: true, user: result.user, tokens: result.tokens, loading: false });\r\n return true;\r\n }\r\n persist({ loading: false, error: 'No login handler configured' });\r\n return false;\r\n } catch (err: any) {\r\n persist({ loading: false, error: err?.message ?? 'Login failed' });\r\n return false;\r\n }\r\n }, [onLogin, persist]);\r\n\r\n const logout = useCallback(() => {\r\n onLogout?.();\r\n persist({ isAuthenticated: false, user: null, tokens: null, loading: false, error: null });\r\n }, [onLogout, persist]);\r\n\r\n const refreshToken = useCallback(async (): Promise<boolean> => {\r\n if (!state.tokens?.refreshToken || !onRefresh) return false;\r\n try {\r\n const tokens = await onRefresh(state.tokens.refreshToken);\r\n persist({ tokens });\r\n return true;\r\n } catch {\r\n logout();\r\n return false;\r\n }\r\n }, [state.tokens, onRefresh, persist, logout]);\r\n\r\n const setAuth = useCallback((user: AuthUser, tokens: AuthTokens) => {\r\n persist({ isAuthenticated: true, user, tokens, loading: false, error: null });\r\n }, [persist]);\r\n\r\n const hasRoles = useCallback((...roles: string[]) => {\r\n if (!state.user) return false;\r\n return roles.every(r => state.user!.roles.includes(r));\r\n }, [state.user]);\r\n\r\n const hasPermissions = useCallback((...permissions: string[]) => {\r\n if (!state.user) return false;\r\n return permissions.every(p => state.user!.permissions.includes(p));\r\n }, [state.user]);\r\n\r\n const clearError = useCallback(() => {\r\n persist({ error: null });\r\n }, [persist]);\r\n\r\n return {\r\n ...state,\r\n login,\r\n logout,\r\n refreshToken,\r\n setAuth,\r\n hasRoles,\r\n hasPermissions,\r\n clearError,\r\n };\r\n}\r\n","import React, { forwardRef, useState, useCallback } from 'react';\r\n\r\n/** Props for the {@link NiceLoginForm} component. */\r\nexport interface NiceLoginFormProps {\r\n /** Fires on form submit. */\r\n onSubmit?: (credentials: { email: string; password: string; rememberMe: boolean }) => void;\r\n /** Whether a login request is in progress. */\r\n loading?: boolean;\r\n /** External error message (e.g. \"Invalid credentials\"). */\r\n error?: string;\r\n /** Whether to show \"Remember me\" checkbox. */\r\n showRememberMe?: boolean;\r\n /** Whether to show \"Forgot password\" link. */\r\n showForgotPassword?: boolean;\r\n /** Fires when \"Forgot password\" is clicked. */\r\n onForgotPassword?: () => void;\r\n /** Whether to show \"Register\" link. */\r\n showRegisterLink?: boolean;\r\n /** Fires when \"Register\" is clicked. */\r\n onRegisterClick?: () => void;\r\n /** Title text. */\r\n title?: string;\r\n /** Submit button label. */\r\n submitLabel?: string;\r\n /** Logo element. */\r\n logo?: React.ReactNode;\r\n /** Additional content below the form (OAuth buttons, etc.). */\r\n footer?: React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n /** Email field label. */\r\n emailLabel?: string;\r\n /** Password field label. */\r\n passwordLabel?: string;\r\n}\r\n\r\n/**\r\n * {@link NiceLoginForm} — Login form with email, password, remember me,\r\n * forgot password link, and optional OAuth footer.\r\n */\r\nexport const NiceLoginForm = forwardRef<HTMLFormElement, NiceLoginFormProps>(({\r\n onSubmit, loading = false, error,\r\n showRememberMe = true, showForgotPassword = true,\r\n onForgotPassword, showRegisterLink = true, onRegisterClick,\r\n title = 'Sign In', submitLabel = 'Sign In', logo, footer,\r\n className, style, emailLabel = 'Email', passwordLabel = 'Password',\r\n}, ref) => {\r\n const [email, setEmail] = useState('');\r\n const [password, setPassword] = useState('');\r\n const [rememberMe, setRememberMe] = useState(false);\r\n\r\n const handleSubmit = useCallback((e: React.FormEvent) => {\r\n e.preventDefault();\r\n onSubmit?.({ email, password, rememberMe });\r\n }, [email, password, rememberMe, onSubmit]);\r\n\r\n return (\r\n <form\r\n ref={ref}\r\n className={`nice-login-form${className ? ` ${className}` : ''}`}\r\n style={style}\r\n onSubmit={handleSubmit}\r\n noValidate\r\n >\r\n {logo && <div className=\"nice-login-form__logo\">{logo}</div>}\r\n <h2 className=\"nice-login-form__title\">{title}</h2>\r\n\r\n {error && <div className=\"nice-login-form__error\" role=\"alert\">{error}</div>}\r\n\r\n <div className=\"nice-login-form__field\">\r\n <label htmlFor=\"nice-login-email\">{emailLabel}</label>\r\n <input\r\n id=\"nice-login-email\"\r\n className=\"nice-input\"\r\n type=\"email\"\r\n value={email}\r\n onChange={e => setEmail(e.target.value)}\r\n autoComplete=\"email\"\r\n required\r\n disabled={loading}\r\n />\r\n </div>\r\n\r\n <div className=\"nice-login-form__field\">\r\n <label htmlFor=\"nice-login-password\">{passwordLabel}</label>\r\n <input\r\n id=\"nice-login-password\"\r\n className=\"nice-input\"\r\n type=\"password\"\r\n value={password}\r\n onChange={e => setPassword(e.target.value)}\r\n autoComplete=\"current-password\"\r\n required\r\n disabled={loading}\r\n />\r\n </div>\r\n\r\n <div className=\"nice-login-form__options\">\r\n {showRememberMe && (\r\n <label className=\"nice-login-form__remember\">\r\n <input type=\"checkbox\" checked={rememberMe} onChange={e => setRememberMe(e.target.checked)} disabled={loading} />\r\n <span>Remember me</span>\r\n </label>\r\n )}\r\n {showForgotPassword && (\r\n <button type=\"button\" className=\"nice-login-form__forgot\" onClick={onForgotPassword} disabled={loading}>\r\n Forgot password?\r\n </button>\r\n )}\r\n </div>\r\n\r\n <button type=\"submit\" className=\"nice-btn nice-btn--primary nice-login-form__submit\" disabled={loading || !email || !password}>\r\n {loading ? '…' : submitLabel}\r\n </button>\r\n\r\n {showRegisterLink && (\r\n <div className=\"nice-login-form__register\">\r\n <span>Don't have an account? </span>\r\n <button type=\"button\" onClick={onRegisterClick} disabled={loading}>Register</button>\r\n </div>\r\n )}\r\n\r\n {footer && <div className=\"nice-login-form__footer\">{footer}</div>}\r\n </form>\r\n );\r\n});\r\n\r\nNiceLoginForm.displayName = 'NiceLoginForm';\r\n","import React, { forwardRef, useMemo } from 'react';\r\n\r\n/** Password strength level (0 = very weak, 4 = very strong). */\r\nexport type PasswordStrengthLevel = 0 | 1 | 2 | 3 | 4;\r\n\r\n/** Props for the {@link NicePasswordStrength} component. */\r\nexport interface NicePasswordStrengthProps {\r\n /** The password to evaluate. */\r\n password: string;\r\n /** Override calculated strength. */\r\n strength?: PasswordStrengthLevel;\r\n /** Whether to show text labels. */\r\n showLabel?: boolean;\r\n /** Custom labels for each level. */\r\n labels?: Record<PasswordStrengthLevel, string>;\r\n className?: string;\r\n}\r\n\r\nconst DEFAULT_LABELS: Record<PasswordStrengthLevel, string> = {\r\n 0: 'Very weak',\r\n 1: 'Weak',\r\n 2: 'Fair',\r\n 3: 'Strong',\r\n 4: 'Very strong',\r\n};\r\n\r\nconst COLORS: Record<PasswordStrengthLevel, string> = {\r\n 0: '#d9534f',\r\n 1: '#f0ad4e',\r\n 2: '#5bc0de',\r\n 3: '#5cb85c',\r\n 4: '#2e7d32',\r\n};\r\n\r\n/** Calculate password strength score (0-4). */\r\nexport function calcPasswordStrength(password: string): PasswordStrengthLevel {\r\n if (!password) return 0;\r\n let score = 0;\r\n if (password.length >= 8) score++;\r\n if (password.length >= 12) score++;\r\n if (/[a-z]/.test(password) && /[A-Z]/.test(password)) score++;\r\n if (/\\d/.test(password)) score++;\r\n if (/[^a-zA-Z0-9]/.test(password)) score++;\r\n return Math.min(4, score) as PasswordStrengthLevel;\r\n}\r\n\r\n/**\r\n * {@link NicePasswordStrength} — Visual password strength indicator bar\r\n * with color-coded levels and text labels.\r\n */\r\nexport const NicePasswordStrength = forwardRef<HTMLDivElement, NicePasswordStrengthProps>(({\r\n password, strength: overrideStrength, showLabel = true,\r\n labels = DEFAULT_LABELS, className,\r\n}, ref) => {\r\n const level = overrideStrength ?? calcPasswordStrength(password);\r\n const color = COLORS[level];\r\n const pct = ((level + 1) / 5) * 100;\r\n\r\n return (\r\n <div ref={ref} className={`nice-password-strength${className ? ` ${className}` : ''}`}>\r\n <div className=\"nice-password-strength__bar\">\r\n <div className=\"nice-password-strength__fill\" style={{ width: `${pct}%`, backgroundColor: color }} />\r\n </div>\r\n {showLabel && <span className=\"nice-password-strength__label\" style={{ color }}>{labels[level]}</span>}\r\n </div>\r\n );\r\n});\r\n\r\nNicePasswordStrength.displayName = 'NicePasswordStrength';\r\n","import React, { forwardRef, useState, useCallback } from 'react';\r\nimport { NicePasswordStrength, calcPasswordStrength } from './NicePasswordStrength';\r\n\r\n/** Registration data payload. */\r\nexport interface RegistrationData {\r\n firstName: string;\r\n lastName: string;\r\n email: string;\r\n password: string;\r\n acceptTerms: boolean;\r\n}\r\n\r\n/** Props for the {@link NiceRegistrationForm} component. */\r\nexport interface NiceRegistrationFormProps {\r\n /** Fires on form submit. */\r\n onSubmit?: (data: RegistrationData) => void;\r\n /** Whether a request is in progress. */\r\n loading?: boolean;\r\n /** External error message. */\r\n error?: string;\r\n /** Fires when \"Login\" link is clicked. */\r\n onLoginClick?: () => void;\r\n /** Whether to show password strength meter. */\r\n showPasswordStrength?: boolean;\r\n /** Minimum password strength level to allow submit (0-4). */\r\n minPasswordStrength?: number;\r\n /** Terms URL. */\r\n termsUrl?: string;\r\n /** Privacy URL. */\r\n privacyUrl?: string;\r\n /** Title. */\r\n title?: string;\r\n /** Logo element. */\r\n logo?: React.ReactNode;\r\n /** Footer content (OAuth buttons, etc.). */\r\n footer?: React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceRegistrationForm} — Registration form with name, email, password,\r\n * strength meter, terms acceptance, and optional OAuth footer.\r\n */\r\nexport const NiceRegistrationForm = forwardRef<HTMLFormElement, NiceRegistrationFormProps>(({\r\n onSubmit, loading = false, error, onLoginClick,\r\n showPasswordStrength = true, minPasswordStrength = 2,\r\n termsUrl, privacyUrl, title = 'Create Account',\r\n logo, footer, className, style,\r\n}, ref) => {\r\n const [firstName, setFirstName] = useState('');\r\n const [lastName, setLastName] = useState('');\r\n const [email, setEmail] = useState('');\r\n const [password, setPassword] = useState('');\r\n const [confirmPassword, setConfirmPassword] = useState('');\r\n const [acceptTerms, setAcceptTerms] = useState(false);\r\n\r\n const strength = calcPasswordStrength(password);\r\n const passwordsMatch = password === confirmPassword;\r\n const canSubmit = firstName && email && password && passwordsMatch && acceptTerms && strength >= minPasswordStrength && !loading;\r\n\r\n const handleSubmit = useCallback((e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (canSubmit) {\r\n onSubmit?.({ firstName, lastName, email, password, acceptTerms });\r\n }\r\n }, [canSubmit, firstName, lastName, email, password, acceptTerms, onSubmit]);\r\n\r\n return (\r\n <form\r\n ref={ref}\r\n className={`nice-register-form${className ? ` ${className}` : ''}`}\r\n style={style}\r\n onSubmit={handleSubmit}\r\n noValidate\r\n >\r\n {logo && <div className=\"nice-register-form__logo\">{logo}</div>}\r\n <h2 className=\"nice-register-form__title\">{title}</h2>\r\n\r\n {error && <div className=\"nice-register-form__error\" role=\"alert\">{error}</div>}\r\n\r\n <div className=\"nice-register-form__row\">\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-first\">First name *</label>\r\n <input id=\"nice-reg-first\" className=\"nice-input\" type=\"text\" value={firstName} onChange={e => setFirstName(e.target.value)} required disabled={loading} autoComplete=\"given-name\" />\r\n </div>\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-last\">Last name</label>\r\n <input id=\"nice-reg-last\" className=\"nice-input\" type=\"text\" value={lastName} onChange={e => setLastName(e.target.value)} disabled={loading} autoComplete=\"family-name\" />\r\n </div>\r\n </div>\r\n\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-email\">Email *</label>\r\n <input id=\"nice-reg-email\" className=\"nice-input\" type=\"email\" value={email} onChange={e => setEmail(e.target.value)} required disabled={loading} autoComplete=\"email\" />\r\n </div>\r\n\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-pass\">Password *</label>\r\n <input id=\"nice-reg-pass\" className=\"nice-input\" type=\"password\" value={password} onChange={e => setPassword(e.target.value)} required disabled={loading} autoComplete=\"new-password\" />\r\n {showPasswordStrength && password.length > 0 && <NicePasswordStrength password={password} />}\r\n </div>\r\n\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-confirm\">Confirm password *</label>\r\n <input id=\"nice-reg-confirm\" className=\"nice-input\" type=\"password\" value={confirmPassword} onChange={e => setConfirmPassword(e.target.value)} required disabled={loading} autoComplete=\"new-password\" />\r\n {confirmPassword && !passwordsMatch && <span className=\"nice-error-text\">Passwords do not match</span>}\r\n </div>\r\n\r\n <label className=\"nice-register-form__terms\">\r\n <input type=\"checkbox\" checked={acceptTerms} onChange={e => setAcceptTerms(e.target.checked)} disabled={loading} />\r\n <span>\r\n I accept the{' '}\r\n {termsUrl ? <a href={termsUrl} target=\"_blank\" rel=\"noopener noreferrer\">Terms</a> : 'Terms'}\r\n {privacyUrl && <> and <a href={privacyUrl} target=\"_blank\" rel=\"noopener noreferrer\">Privacy Policy</a></>}\r\n {' *'}\r\n </span>\r\n </label>\r\n\r\n <button type=\"submit\" className=\"nice-btn nice-btn--primary nice-register-form__submit\" disabled={!canSubmit}>\r\n {loading ? '…' : 'Register'}\r\n </button>\r\n\r\n {onLoginClick && (\r\n <div className=\"nice-register-form__login\">\r\n <span>Already have an account? </span>\r\n <button type=\"button\" onClick={onLoginClick}>Sign in</button>\r\n </div>\r\n )}\r\n\r\n {footer && <div className=\"nice-register-form__footer\">{footer}</div>}\r\n </form>\r\n );\r\n});\r\n\r\nNiceRegistrationForm.displayName = 'NiceRegistrationForm';\r\n","import React, { forwardRef, useState, useCallback } from 'react';\r\nimport { NicePasswordStrength, calcPasswordStrength } from './NicePasswordStrength';\r\n\r\n/** Props for the {@link NiceChangePassword} component. */\r\nexport interface NiceChangePasswordProps {\r\n /** Whether the user must provide current password. */\r\n requireCurrentPassword?: boolean;\r\n /** Fires on submit. */\r\n onSubmit?: (data: { currentPassword?: string; newPassword: string }) => void;\r\n /** Whether a request is in progress. */\r\n loading?: boolean;\r\n /** External error message. */\r\n error?: string;\r\n /** Success message after password change. */\r\n success?: string;\r\n /** Minimum password strength to allow submit (0-4). */\r\n minPasswordStrength?: number;\r\n /** Title. */\r\n title?: string;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceChangePassword} — Change/reset password form with strength meter.\r\n */\r\nexport const NiceChangePassword = forwardRef<HTMLFormElement, NiceChangePasswordProps>(({\r\n requireCurrentPassword = true, onSubmit, loading = false,\r\n error, success, minPasswordStrength = 2,\r\n title = 'Change Password', className, style,\r\n}, ref) => {\r\n const [currentPassword, setCurrentPassword] = useState('');\r\n const [newPassword, setNewPassword] = useState('');\r\n const [confirmPassword, setConfirmPassword] = useState('');\r\n\r\n const strength = calcPasswordStrength(newPassword);\r\n const passwordsMatch = newPassword === confirmPassword;\r\n const canSubmit = (!requireCurrentPassword || currentPassword.length > 0) &&\r\n newPassword.length > 0 && passwordsMatch && strength >= minPasswordStrength && !loading;\r\n\r\n const handleSubmit = useCallback((e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (canSubmit) {\r\n onSubmit?.({\r\n currentPassword: requireCurrentPassword ? currentPassword : undefined,\r\n newPassword,\r\n });\r\n }\r\n }, [canSubmit, currentPassword, newPassword, requireCurrentPassword, onSubmit]);\r\n\r\n return (\r\n <form\r\n ref={ref}\r\n className={`nice-change-password${className ? ` ${className}` : ''}`}\r\n style={style}\r\n onSubmit={handleSubmit}\r\n noValidate\r\n >\r\n <h3 className=\"nice-change-password__title\">{title}</h3>\r\n\r\n {error && <div className=\"nice-change-password__error\" role=\"alert\">{error}</div>}\r\n {success && <div className=\"nice-change-password__success\" role=\"status\">{success}</div>}\r\n\r\n {requireCurrentPassword && (\r\n <div className=\"nice-change-password__field\">\r\n <label htmlFor=\"nice-cp-current\">Current password</label>\r\n <input\r\n id=\"nice-cp-current\"\r\n className=\"nice-input\"\r\n type=\"password\"\r\n value={currentPassword}\r\n onChange={e => setCurrentPassword(e.target.value)}\r\n autoComplete=\"current-password\"\r\n disabled={loading}\r\n required\r\n />\r\n </div>\r\n )}\r\n\r\n <div className=\"nice-change-password__field\">\r\n <label htmlFor=\"nice-cp-new\">New password</label>\r\n <input\r\n id=\"nice-cp-new\"\r\n className=\"nice-input\"\r\n type=\"password\"\r\n value={newPassword}\r\n onChange={e => setNewPassword(e.target.value)}\r\n autoComplete=\"new-password\"\r\n disabled={loading}\r\n required\r\n />\r\n {newPassword.length > 0 && <NicePasswordStrength password={newPassword} />}\r\n </div>\r\n\r\n <div className=\"nice-change-password__field\">\r\n <label htmlFor=\"nice-cp-confirm\">Confirm new password</label>\r\n <input\r\n id=\"nice-cp-confirm\"\r\n className=\"nice-input\"\r\n type=\"password\"\r\n value={confirmPassword}\r\n onChange={e => setConfirmPassword(e.target.value)}\r\n autoComplete=\"new-password\"\r\n disabled={loading}\r\n required\r\n />\r\n {confirmPassword && !passwordsMatch && <span className=\"nice-error-text\">Passwords do not match</span>}\r\n </div>\r\n\r\n <button type=\"submit\" className=\"nice-btn nice-btn--primary\" disabled={!canSubmit}>\r\n {loading ? '…' : 'Change Password'}\r\n </button>\r\n </form>\r\n );\r\n});\r\n\r\nNiceChangePassword.displayName = 'NiceChangePassword';\r\n","import React, { forwardRef, useState, useCallback } from 'react';\r\n\r\n/** Props for the {@link NiceTwoFaSetup} component. */\r\nexport interface NiceTwoFaSetupProps {\r\n /** The TOTP secret key (base32 encoded). */\r\n secret: string;\r\n /** QR code image URL or data URL for the authenticator app. */\r\n qrCodeUrl?: string;\r\n /** Issuer name for the TOTP URI. */\r\n issuer?: string;\r\n /** User's account name. */\r\n accountName?: string;\r\n /** Fires when user submits verification code. */\r\n onVerify?: (code: string) => void;\r\n /** Whether verification is in progress. */\r\n loading?: boolean;\r\n /** Error message (e.g. \"Invalid code\"). */\r\n error?: string;\r\n /** Fires on back/cancel. */\r\n onCancel?: () => void;\r\n /** Recovery codes to display after setup. */\r\n recoveryCodes?: string[];\r\n /** Step: 'setup' = show QR, 'verify' = enter code, 'recovery' = show codes. */\r\n step?: 'setup' | 'verify' | 'recovery';\r\n /** Fires when step changes. */\r\n onStepChange?: (step: 'setup' | 'verify' | 'recovery') => void;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceTwoFaSetup} — Two-factor authentication setup wizard with\r\n * QR code display, secret key, verification code input, and recovery codes.\r\n */\r\nexport const NiceTwoFaSetup = forwardRef<HTMLDivElement, NiceTwoFaSetupProps>(({\r\n secret, qrCodeUrl, issuer, accountName,\r\n onVerify, loading = false, error, onCancel,\r\n recoveryCodes, step = 'setup', onStepChange,\r\n className, style,\r\n}, ref) => {\r\n const [code, setCode] = useState('');\r\n const [showSecret, setShowSecret] = useState(false);\r\n const [copiedCodes, setCopiedCodes] = useState(false);\r\n\r\n const handleVerify = useCallback((e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (code.length >= 6) {\r\n onVerify?.(code);\r\n }\r\n }, [code, onVerify]);\r\n\r\n const totpUri = `otpauth://totp/${issuer ? `${issuer}:` : ''}${accountName ?? 'user'}?secret=${secret}${issuer ? `&issuer=${issuer}` : ''}&digits=6&period=30`;\r\n\r\n return (\r\n <div ref={ref} className={`nice-2fa-setup${className ? ` ${className}` : ''}`} style={style}>\r\n <h3 className=\"nice-2fa-setup__title\">Two-Factor Authentication</h3>\r\n\r\n {step === 'setup' && (\r\n <div className=\"nice-2fa-setup__step\">\r\n <p className=\"nice-2fa-setup__instruction\">\r\n Scan this QR code with your authenticator app (Google Authenticator, Authy, etc.):\r\n </p>\r\n\r\n {qrCodeUrl ? (\r\n <img src={qrCodeUrl} alt=\"2FA QR Code\" className=\"nice-2fa-setup__qr\" />\r\n ) : (\r\n <div className=\"nice-2fa-setup__qr-placeholder\">\r\n <span>QR Code</span>\r\n <code className=\"nice-2fa-setup__uri\">{totpUri}</code>\r\n </div>\r\n )}\r\n\r\n <div className=\"nice-2fa-setup__secret\">\r\n <span>Or enter manually: </span>\r\n {showSecret ? (\r\n <code className=\"nice-2fa-setup__secret-key\">{secret}</code>\r\n ) : (\r\n <button type=\"button\" onClick={() => setShowSecret(true)}>Show secret key</button>\r\n )}\r\n </div>\r\n\r\n <button type=\"button\" className=\"nice-btn nice-btn--primary\" onClick={() => onStepChange?.('verify')}>\r\n Next — Verify\r\n </button>\r\n </div>\r\n )}\r\n\r\n {step === 'verify' && (\r\n <form className=\"nice-2fa-setup__step\" onSubmit={handleVerify}>\r\n <p className=\"nice-2fa-setup__instruction\">\r\n Enter the 6-digit code from your authenticator app:\r\n </p>\r\n\r\n {error && <div className=\"nice-2fa-setup__error\" role=\"alert\">{error}</div>}\r\n\r\n <input\r\n className=\"nice-input nice-2fa-setup__code-input\"\r\n type=\"text\"\r\n inputMode=\"numeric\"\r\n maxLength={6}\r\n value={code}\r\n onChange={e => setCode(e.target.value.replace(/\\D/g, '').slice(0, 6))}\r\n placeholder=\"000000\"\r\n autoFocus\r\n disabled={loading}\r\n autoComplete=\"one-time-code\"\r\n />\r\n\r\n <div className=\"nice-2fa-setup__actions\">\r\n <button type=\"button\" className=\"nice-btn\" onClick={() => onStepChange?.('setup')}>Back</button>\r\n <button type=\"submit\" className=\"nice-btn nice-btn--primary\" disabled={loading || code.length < 6}>\r\n {loading ? '…' : 'Verify'}\r\n </button>\r\n </div>\r\n </form>\r\n )}\r\n\r\n {step === 'recovery' && recoveryCodes && (\r\n <div className=\"nice-2fa-setup__step\">\r\n <p className=\"nice-2fa-setup__instruction\">\r\n Save these recovery codes in a safe place. Each code can only be used once:\r\n </p>\r\n\r\n <div className=\"nice-2fa-setup__recovery-codes\">\r\n {recoveryCodes.map((rc, i) => (\r\n <code key={i} className=\"nice-2fa-setup__recovery-code\">{rc}</code>\r\n ))}\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n className=\"nice-btn\"\r\n onClick={() => {\r\n navigator.clipboard?.writeText(recoveryCodes.join('\\n'));\r\n setCopiedCodes(true);\r\n }}\r\n >\r\n {copiedCodes ? 'Copied!' : 'Copy all codes'}\r\n </button>\r\n\r\n {onCancel && <button type=\"button\" className=\"nice-btn nice-btn--primary\" onClick={onCancel}>Done</button>}\r\n </div>\r\n )}\r\n\r\n {onCancel && step !== 'recovery' && (\r\n <button type=\"button\" className=\"nice-2fa-setup__cancel\" onClick={onCancel}>Cancel</button>\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\nNiceTwoFaSetup.displayName = 'NiceTwoFaSetup';\r\n","import React, { forwardRef } from 'react';\r\n\r\n/** Captcha provider type. */\r\nexport type CaptchaProvider = 'custom' | 'recaptcha' | 'hcaptcha' | 'turnstile';\r\n\r\n/** Props for the {@link NiceCaptcha} component. */\r\nexport interface NiceCaptchaProps {\r\n /** Captcha provider. */\r\n provider?: CaptchaProvider;\r\n /** Site key for the captcha provider. */\r\n siteKey?: string;\r\n /** Fires when captcha is verified with a token. */\r\n onVerify?: (token: string) => void;\r\n /** Fires when captcha expires. */\r\n onExpire?: () => void;\r\n /** Fires on captcha error. */\r\n onError?: (error: unknown) => void;\r\n /** Theme. */\r\n theme?: 'light' | 'dark';\r\n /** Size. */\r\n size?: 'normal' | 'compact' | 'invisible';\r\n /** Custom render for provider='custom'. */\r\n customRender?: React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceCaptcha} — Pluggable captcha widget shell.\r\n * For production use, inject the actual captcha SDK via `customRender` or\r\n * integrate the provider script externally. This component provides a\r\n * consistent wrapper API.\r\n */\r\nexport const NiceCaptcha = forwardRef<HTMLDivElement, NiceCaptchaProps>(({\r\n provider = 'custom', siteKey, onVerify, onExpire, onError,\r\n theme = 'light', size = 'normal', customRender,\r\n className, style,\r\n}, ref) => {\r\n if (provider === 'custom' && customRender) {\r\n return (\r\n <div ref={ref} className={`nice-captcha nice-captcha--custom${className ? ` ${className}` : ''}`} style={style}>\r\n {customRender}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={`nice-captcha nice-captcha--${provider} nice-captcha--${theme}${size === 'compact' ? ' nice-captcha--compact' : ''}${className ? ` ${className}` : ''}`}\r\n style={style}\r\n data-sitekey={siteKey}\r\n data-theme={theme}\r\n data-size={size}\r\n >\r\n <div className=\"nice-captcha__placeholder\">\r\n <span>🔒 Captcha ({provider})</span>\r\n <p>Load the {provider} SDK to activate verification.</p>\r\n </div>\r\n </div>\r\n );\r\n});\r\n\r\nNiceCaptcha.displayName = 'NiceCaptcha';\r\n","import React, { forwardRef } from 'react';\r\n\r\n/** OAuth provider definition. */\r\nexport interface OAuthProvider {\r\n /** Unique provider id. */\r\n id: string;\r\n /** Display label. */\r\n label: string;\r\n /** Icon (emoji, SVG element, or URL). */\r\n icon?: React.ReactNode;\r\n /** Brand color for the button. */\r\n color?: string;\r\n /** Text color. */\r\n textColor?: string;\r\n}\r\n\r\n/** Props for the {@link NiceOAuthButtons} component. */\r\nexport interface NiceOAuthButtonsProps {\r\n /** Providers to display. */\r\n providers?: OAuthProvider[];\r\n /** Fires when a provider button is clicked. */\r\n onProviderClick?: (providerId: string) => void;\r\n /** Whether buttons are disabled. */\r\n disabled?: boolean;\r\n /** Loading provider id (shows spinner on that button). */\r\n loadingProvider?: string;\r\n /** Layout direction. */\r\n direction?: 'horizontal' | 'vertical';\r\n /** Separator text (e.g. \"or continue with\"). */\r\n separatorText?: string;\r\n /** Whether to show separator above buttons. */\r\n showSeparator?: boolean;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\nconst DEFAULT_PROVIDERS: OAuthProvider[] = [\r\n { id: 'google', label: 'Google', icon: '🔵', color: '#4285f4', textColor: '#fff' },\r\n { id: 'microsoft', label: 'Microsoft', icon: '🟦', color: '#00a4ef', textColor: '#fff' },\r\n { id: 'discord', label: 'Discord', icon: '💬', color: '#5865f2', textColor: '#fff' },\r\n { id: 'spotify', label: 'Spotify', icon: '🎵', color: '#1db954', textColor: '#fff' },\r\n { id: 'github', label: 'GitHub', icon: '🐙', color: '#24292e', textColor: '#fff' },\r\n];\r\n\r\n/**\r\n * {@link NiceOAuthButtons} — OAuth login/registration buttons for popular providers.\r\n */\r\nexport const NiceOAuthButtons = forwardRef<HTMLDivElement, NiceOAuthButtonsProps>(({\r\n providers = DEFAULT_PROVIDERS, onProviderClick, disabled = false,\r\n loadingProvider, direction = 'vertical', separatorText = 'or continue with',\r\n showSeparator = true, className, style,\r\n}, ref) => (\r\n <div\r\n ref={ref}\r\n className={`nice-oauth nice-oauth--${direction}${className ? ` ${className}` : ''}`}\r\n style={style}\r\n >\r\n {showSeparator && (\r\n <div className=\"nice-oauth__separator\">\r\n <hr /><span>{separatorText}</span><hr />\r\n </div>\r\n )}\r\n\r\n <div className=\"nice-oauth__buttons\">\r\n {providers.map(provider => (\r\n <button\r\n key={provider.id}\r\n type=\"button\"\r\n className={`nice-oauth__btn${loadingProvider === provider.id ? ' nice-oauth__btn--loading' : ''}`}\r\n style={{ backgroundColor: provider.color, color: provider.textColor }}\r\n onClick={() => onProviderClick?.(provider.id)}\r\n disabled={disabled || !!loadingProvider}\r\n >\r\n {provider.icon && <span className=\"nice-oauth__btn-icon\">{provider.icon}</span>}\r\n <span className=\"nice-oauth__btn-label\">\r\n {loadingProvider === provider.id ? '…' : provider.label}\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n));\r\n\r\nNiceOAuthButtons.displayName = 'NiceOAuthButtons';\r\n","import React, { useState, forwardRef, useCallback } from 'react';\r\n\r\n// ── Types ──────────────────────────────────────────────────\r\n\r\n/** API token entry. */\r\nexport interface ApiToken {\r\n id: string;\r\n name: string;\r\n prefix: string;\r\n createdAt: string;\r\n expiresAt?: string;\r\n lastUsedAt?: string;\r\n scopes?: string[];\r\n}\r\n\r\n/** Props for {@link NiceTokenManagement}. */\r\nexport interface NiceTokenManagementProps {\r\n /** Existing tokens. */\r\n tokens: ApiToken[];\r\n /** Called to create a new token. Should return the full token string (only shown once). */\r\n onCreate?: (name: string, scopes: string[], expiresInDays?: number) => Promise<string>;\r\n /** Called to revoke a token. */\r\n onRevoke?: (tokenId: string) => Promise<void>;\r\n /** Available scopes for new tokens. */\r\n availableScopes?: string[];\r\n /** Maximum number of tokens allowed. */\r\n maxTokens?: number;\r\n /** Title. */\r\n title?: string;\r\n /** CSS class name. */\r\n className?: string;\r\n /** Inline styles. */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceTokenManagement} — API token management UI.\r\n * \r\n * Create, view, and revoke personal API tokens. New token values are shown\r\n * once after creation. Supports scopes and expiration.\r\n */\r\nexport const NiceTokenManagement = forwardRef<HTMLDivElement, NiceTokenManagementProps>(function NiceTokenManagement(props, ref) {\r\n const {\r\n tokens,\r\n onCreate,\r\n onRevoke,\r\n availableScopes = [],\r\n maxTokens = 10,\r\n title = 'API Tokens',\r\n className,\r\n style,\r\n } = props;\r\n\r\n const [showCreate, setShowCreate] = useState(false);\r\n const [newName, setNewName] = useState('');\r\n const [selectedScopes, setSelectedScopes] = useState<string[]>([]);\r\n const [expDays, setExpDays] = useState('90');\r\n const [newTokenValue, setNewTokenValue] = useState<string | null>(null);\r\n const [loading, setLoading] = useState(false);\r\n const [revoking, setRevoking] = useState<string | null>(null);\r\n\r\n const handleCreate = useCallback(async () => {\r\n if (!onCreate || !newName.trim()) return;\r\n setLoading(true);\r\n try {\r\n const days = expDays ? parseInt(expDays, 10) : undefined;\r\n const tokenStr = await onCreate(newName.trim(), selectedScopes, days);\r\n setNewTokenValue(tokenStr);\r\n setNewName('');\r\n setSelectedScopes([]);\r\n setShowCreate(false);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [onCreate, newName, selectedScopes, expDays]);\r\n\r\n const handleRevoke = useCallback(async (id: string) => {\r\n if (!onRevoke) return;\r\n setRevoking(id);\r\n try {\r\n await onRevoke(id);\r\n } finally {\r\n setRevoking(null);\r\n }\r\n }, [onRevoke]);\r\n\r\n const toggleScope = (scope: string) => {\r\n setSelectedScopes(prev => prev.includes(scope) ? prev.filter(s => s !== scope) : [...prev, scope]);\r\n };\r\n\r\n const canCreate = tokens.length < maxTokens;\r\n\r\n return (\r\n <div ref={ref} className={`nice-token-management ${className ?? ''}`} style={style}>\r\n <div className=\"nice-token-management__header\">\r\n <h3>{title}</h3>\r\n {canCreate && (\r\n <button className=\"nice-token-management__new-btn\" onClick={() => setShowCreate(true)} disabled={showCreate}>\r\n + New Token\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* ── Reveal banner ── */}\r\n {newTokenValue && (\r\n <div className=\"nice-token-management__reveal\">\r\n <p><strong>New token created!</strong> Copy it now — it won't be shown again.</p>\r\n <code className=\"nice-token-management__token-value\">{newTokenValue}</code>\r\n <button onClick={() => setNewTokenValue(null)}>Dismiss</button>\r\n </div>\r\n )}\r\n\r\n {/* ── Create form ── */}\r\n {showCreate && (\r\n <div className=\"nice-token-management__create-form\">\r\n <label>\r\n Name\r\n <input\r\n type=\"text\"\r\n value={newName}\r\n onChange={e => setNewName(e.target.value)}\r\n placeholder=\"My API token\"\r\n maxLength={64}\r\n />\r\n </label>\r\n\r\n {availableScopes.length > 0 && (\r\n <fieldset>\r\n <legend>Scopes</legend>\r\n {availableScopes.map(scope => (\r\n <label key={scope} className=\"nice-token-management__scope\">\r\n <input\r\n type=\"checkbox\"\r\n checked={selectedScopes.includes(scope)}\r\n onChange={() => toggleScope(scope)}\r\n />\r\n {scope}\r\n </label>\r\n ))}\r\n </fieldset>\r\n )}\r\n\r\n <label>\r\n Expires in (days)\r\n <input\r\n type=\"number\"\r\n value={expDays}\r\n onChange={e => setExpDays(e.target.value)}\r\n min={1}\r\n max={365}\r\n />\r\n </label>\r\n\r\n <div className=\"nice-token-management__create-actions\">\r\n <button onClick={handleCreate} disabled={loading || !newName.trim()}>\r\n {loading ? 'Creating…' : 'Create Token'}\r\n </button>\r\n <button onClick={() => setShowCreate(false)}>Cancel</button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* ── Token list ── */}\r\n {tokens.length === 0 ? (\r\n <p className=\"nice-token-management__empty\">No API tokens yet.</p>\r\n ) : (\r\n <table className=\"nice-token-management__table\">\r\n <thead>\r\n <tr>\r\n <th>Name</th>\r\n <th>Prefix</th>\r\n <th>Created</th>\r\n <th>Expires</th>\r\n <th>Last Used</th>\r\n <th>Scopes</th>\r\n <th />\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {tokens.map(t => (\r\n <tr key={t.id}>\r\n <td>{t.name}</td>\r\n <td><code>{t.prefix}…</code></td>\r\n <td>{t.createdAt}</td>\r\n <td>{t.expiresAt ?? '—'}</td>\r\n <td>{t.lastUsedAt ?? 'Never'}</td>\r\n <td>{t.scopes?.join(', ') || '—'}</td>\r\n <td>\r\n <button\r\n className=\"nice-token-management__revoke-btn\"\r\n onClick={() => handleRevoke(t.id)}\r\n disabled={revoking === t.id}\r\n >\r\n {revoking === t.id ? 'Revoking…' : 'Revoke'}\r\n </button>\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n )}\r\n </div>\r\n );\r\n});\r\n"],"names":["useAuth","config","onLogin","onRefresh","onLogout","storageKey","persistAuth","state","setState","useState","stored","persist","useCallback","newState","prev","next","login","email","password","result","err","logout","refreshToken","_a","tokens","setAuth","user","hasRoles","roles","r","hasPermissions","permissions","p","clearError","NiceLoginForm","forwardRef","onSubmit","loading","error","showRememberMe","showForgotPassword","onForgotPassword","showRegisterLink","onRegisterClick","title","submitLabel","logo","footer","className","style","emailLabel","passwordLabel","ref","setEmail","setPassword","rememberMe","setRememberMe","handleSubmit","e","jsxs","jsx","DEFAULT_LABELS","COLORS","calcPasswordStrength","score","NicePasswordStrength","overrideStrength","showLabel","labels","level","color","pct","NiceRegistrationForm","onLoginClick","showPasswordStrength","minPasswordStrength","termsUrl","privacyUrl","firstName","setFirstName","lastName","setLastName","confirmPassword","setConfirmPassword","acceptTerms","setAcceptTerms","strength","passwordsMatch","canSubmit","Fragment","NiceChangePassword","requireCurrentPassword","success","currentPassword","setCurrentPassword","newPassword","setNewPassword","NiceTwoFaSetup","secret","qrCodeUrl","issuer","accountName","onVerify","onCancel","recoveryCodes","step","onStepChange","code","setCode","showSecret","setShowSecret","copiedCodes","setCopiedCodes","handleVerify","totpUri","rc","i","NiceCaptcha","provider","siteKey","onExpire","onError","theme","size","customRender","DEFAULT_PROVIDERS","NiceOAuthButtons","providers","onProviderClick","disabled","loadingProvider","direction","separatorText","showSeparator","NiceTokenManagement","props","onCreate","onRevoke","availableScopes","maxTokens","showCreate","setShowCreate","newName","setNewName","selectedScopes","setSelectedScopes","expDays","setExpDays","newTokenValue","setNewTokenValue","setLoading","revoking","setRevoking","handleCreate","days","tokenStr","handleRevoke","id","toggleScope","scope","s","canCreate","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/useAuth.ts","../src/NiceLoginForm.tsx","../src/NicePasswordStrength.tsx","../src/NiceRegistrationForm.tsx","../src/NiceChangePassword.tsx","../src/NiceTwoFaSetup.tsx","../src/NiceCaptcha.tsx","../src/NiceOAuthButtons.tsx","../src/NiceTokenManagement.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\r\n\r\n/** User info from auth. */\r\nexport interface AuthUser {\r\n id: string;\r\n email: string;\r\n name?: string;\r\n avatarUrl?: string;\r\n roles: string[];\r\n permissions: string[];\r\n}\r\n\r\n/** Auth tokens. */\r\nexport interface AuthTokens {\r\n accessToken: string;\r\n refreshToken?: string;\r\n expiresAt?: number;\r\n}\r\n\r\n/** Auth state. */\r\nexport interface AuthState {\r\n /** Whether the user is authenticated. */\r\n isAuthenticated: boolean;\r\n /** Current user info. */\r\n user: AuthUser | null;\r\n /** Tokens (for advanced usage). */\r\n tokens: AuthTokens | null;\r\n /** Whether a login/refresh is in progress. */\r\n loading: boolean;\r\n /** Last auth error. */\r\n error: string | null;\r\n}\r\n\r\n/** Auth actions returned by useAuth. */\r\nexport interface AuthActions {\r\n /** Login with credentials. Returns success status. */\r\n login: (email: string, password: string) => Promise<boolean>;\r\n /** Logout and clear tokens. */\r\n logout: () => void;\r\n /** Refresh the access token. */\r\n refreshToken: () => Promise<boolean>;\r\n /** Set auth state from external source (e.g. SSO callback). */\r\n setAuth: (user: AuthUser, tokens: AuthTokens) => void;\r\n /** Check if user has all specified roles. */\r\n hasRoles: (...roles: string[]) => boolean;\r\n /** Check if user has all specified permissions. */\r\n hasPermissions: (...permissions: string[]) => boolean;\r\n /** Clear error. */\r\n clearError: () => void;\r\n}\r\n\r\n/** Configuration for useAuth. */\r\nexport interface UseAuthConfig {\r\n /** Login endpoint. */\r\n loginUrl?: string;\r\n /** Refresh endpoint. */\r\n refreshUrl?: string;\r\n /** Logout endpoint. */\r\n logoutUrl?: string;\r\n /** Custom login handler (overrides loginUrl). */\r\n onLogin?: (email: string, password: string) => Promise<{ user: AuthUser; tokens: AuthTokens }>;\r\n /** Custom refresh handler (overrides refreshUrl). */\r\n onRefresh?: (refreshToken: string) => Promise<AuthTokens>;\r\n /** Custom logout handler. */\r\n onLogout?: () => void | Promise<void>;\r\n /** Storage key for persisting auth state. */\r\n storageKey?: string;\r\n /** Whether to persist in localStorage. */\r\n persistAuth?: boolean;\r\n}\r\n\r\n/**\r\n * {@link useAuth} — Auth state management hook with JWT, roles, refresh token, and logout.\r\n * \r\n * Usage:\r\n * ```tsx\r\n * const { isAuthenticated, user, login, logout, hasRoles } = useAuth({\r\n * onLogin: async (email, password) => {\r\n * const res = await api.login(email, password);\r\n * return { user: res.user, tokens: { accessToken: res.token } };\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport function useAuth(config: UseAuthConfig = {}): AuthState & AuthActions {\r\n const { onLogin, onRefresh, onLogout, storageKey = 'nice_auth', persistAuth = false } = config;\r\n\r\n const [state, setState] = useState<AuthState>(() => {\r\n if (persistAuth && typeof window !== 'undefined') {\r\n try {\r\n const stored = localStorage.getItem(storageKey);\r\n if (stored) {\r\n const parsed = JSON.parse(stored);\r\n return { ...parsed, loading: false, error: null };\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n return { isAuthenticated: false, user: null, tokens: null, loading: false, error: null };\r\n });\r\n\r\n const persist = useCallback((newState: Partial<AuthState>) => {\r\n setState(prev => {\r\n const next = { ...prev, ...newState };\r\n if (persistAuth && typeof window !== 'undefined') {\r\n if (next.isAuthenticated) {\r\n // Security: only persist non-sensitive data (user info).\r\n // Tokens are kept in-memory only to prevent XSS-based token theft.\r\n localStorage.setItem(storageKey, JSON.stringify({ isAuthenticated: true, user: next.user }));\r\n } else {\r\n localStorage.removeItem(storageKey);\r\n }\r\n }\r\n return next;\r\n });\r\n }, [persistAuth, storageKey]);\r\n\r\n const login = useCallback(async (email: string, password: string): Promise<boolean> => {\r\n persist({ loading: true, error: null });\r\n try {\r\n if (onLogin) {\r\n const result = await onLogin(email, password);\r\n persist({ isAuthenticated: true, user: result.user, tokens: result.tokens, loading: false });\r\n return true;\r\n }\r\n persist({ loading: false, error: 'No login handler configured' });\r\n return false;\r\n } catch (err: any) {\r\n persist({ loading: false, error: err?.message ?? 'Login failed' });\r\n return false;\r\n }\r\n }, [onLogin, persist]);\r\n\r\n const logout = useCallback(() => {\r\n onLogout?.();\r\n persist({ isAuthenticated: false, user: null, tokens: null, loading: false, error: null });\r\n }, [onLogout, persist]);\r\n\r\n const refreshToken = useCallback(async (): Promise<boolean> => {\r\n if (!state.tokens?.refreshToken || !onRefresh) return false;\r\n try {\r\n const tokens = await onRefresh(state.tokens.refreshToken);\r\n persist({ tokens });\r\n return true;\r\n } catch {\r\n logout();\r\n return false;\r\n }\r\n }, [state.tokens, onRefresh, persist, logout]);\r\n\r\n const setAuth = useCallback((user: AuthUser, tokens: AuthTokens) => {\r\n persist({ isAuthenticated: true, user, tokens, loading: false, error: null });\r\n }, [persist]);\r\n\r\n const hasRoles = useCallback((...roles: string[]) => {\r\n if (!state.user) return false;\r\n return roles.every(r => state.user!.roles.includes(r));\r\n }, [state.user]);\r\n\r\n const hasPermissions = useCallback((...permissions: string[]) => {\r\n if (!state.user) return false;\r\n return permissions.every(p => state.user!.permissions.includes(p));\r\n }, [state.user]);\r\n\r\n const clearError = useCallback(() => {\r\n persist({ error: null });\r\n }, [persist]);\r\n\r\n return {\r\n ...state,\r\n login,\r\n logout,\r\n refreshToken,\r\n setAuth,\r\n hasRoles,\r\n hasPermissions,\r\n clearError,\r\n };\r\n}\r\n","import React, { forwardRef, useState, useCallback } from 'react';\r\n\r\n/** Props for the {@link NiceLoginForm} component. */\r\nexport interface NiceLoginFormProps {\r\n /** Fires on form submit. */\r\n onSubmit?: (credentials: { email: string; password: string; rememberMe: boolean }) => void;\r\n /** Whether a login request is in progress. */\r\n loading?: boolean;\r\n /** External error message (e.g. \"Invalid credentials\"). */\r\n error?: string;\r\n /** Whether to show \"Remember me\" checkbox. */\r\n showRememberMe?: boolean;\r\n /** Whether to show \"Forgot password\" link. */\r\n showForgotPassword?: boolean;\r\n /** Fires when \"Forgot password\" is clicked. */\r\n onForgotPassword?: () => void;\r\n /** Whether to show \"Register\" link. */\r\n showRegisterLink?: boolean;\r\n /** Fires when \"Register\" is clicked. */\r\n onRegisterClick?: () => void;\r\n /** Title text. */\r\n title?: string;\r\n /** Submit button label. */\r\n submitLabel?: string;\r\n /** Logo element. */\r\n logo?: React.ReactNode;\r\n /** Additional content below the form (OAuth buttons, etc.). */\r\n footer?: React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n /** Email field label. */\r\n emailLabel?: string;\r\n /** Password field label. */\r\n passwordLabel?: string;\r\n}\r\n\r\n/**\r\n * {@link NiceLoginForm} — Login form with email, password, remember me,\r\n * forgot password link, and optional OAuth footer.\r\n */\r\nexport const NiceLoginForm = forwardRef<HTMLFormElement, NiceLoginFormProps>(({\r\n onSubmit, loading = false, error,\r\n showRememberMe = true, showForgotPassword = true,\r\n onForgotPassword, showRegisterLink = true, onRegisterClick,\r\n title = 'Sign In', submitLabel = 'Sign In', logo, footer,\r\n className, style, emailLabel = 'Email', passwordLabel = 'Password',\r\n}, ref) => {\r\n const [email, setEmail] = useState('');\r\n const [password, setPassword] = useState('');\r\n const [rememberMe, setRememberMe] = useState(false);\r\n\r\n const handleSubmit = useCallback((e: React.FormEvent) => {\r\n e.preventDefault();\r\n onSubmit?.({ email, password, rememberMe });\r\n }, [email, password, rememberMe, onSubmit]);\r\n\r\n return (\r\n <form\r\n ref={ref}\r\n className={`nice-login-form${className ? ` ${className}` : ''}`}\r\n style={style}\r\n onSubmit={handleSubmit}\r\n noValidate\r\n >\r\n {logo && <div className=\"nice-login-form__logo\">{logo}</div>}\r\n <h2 className=\"nice-login-form__title\">{title}</h2>\r\n\r\n {error && <div className=\"nice-login-form__error\" role=\"alert\">{error}</div>}\r\n\r\n <div className=\"nice-login-form__field\">\r\n <label htmlFor=\"nice-login-email\">{emailLabel}</label>\r\n <input\r\n id=\"nice-login-email\"\r\n className=\"nice-input\"\r\n type=\"email\"\r\n value={email}\r\n onChange={e => setEmail(e.target.value)}\r\n autoComplete=\"email\"\r\n required\r\n disabled={loading}\r\n />\r\n </div>\r\n\r\n <div className=\"nice-login-form__field\">\r\n <label htmlFor=\"nice-login-password\">{passwordLabel}</label>\r\n <input\r\n id=\"nice-login-password\"\r\n className=\"nice-input\"\r\n type=\"password\"\r\n value={password}\r\n onChange={e => setPassword(e.target.value)}\r\n autoComplete=\"current-password\"\r\n required\r\n disabled={loading}\r\n />\r\n </div>\r\n\r\n <div className=\"nice-login-form__options\">\r\n {showRememberMe && (\r\n <label className=\"nice-login-form__remember\">\r\n <input type=\"checkbox\" checked={rememberMe} onChange={e => setRememberMe(e.target.checked)} disabled={loading} />\r\n <span>Remember me</span>\r\n </label>\r\n )}\r\n {showForgotPassword && (\r\n <button type=\"button\" className=\"nice-login-form__forgot\" onClick={onForgotPassword} disabled={loading}>\r\n Forgot password?\r\n </button>\r\n )}\r\n </div>\r\n\r\n <button type=\"submit\" className=\"nice-btn nice-btn--primary nice-login-form__submit\" disabled={loading || !email || !password}>\r\n {loading ? '…' : submitLabel}\r\n </button>\r\n\r\n {showRegisterLink && (\r\n <div className=\"nice-login-form__register\">\r\n <span>Don't have an account? </span>\r\n <button type=\"button\" onClick={onRegisterClick} disabled={loading}>Register</button>\r\n </div>\r\n )}\r\n\r\n {footer && <div className=\"nice-login-form__footer\">{footer}</div>}\r\n </form>\r\n );\r\n});\r\n\r\nNiceLoginForm.displayName = 'NiceLoginForm';\r\n","import React, { forwardRef, useMemo } from 'react';\r\n\r\n/** Password strength level (0 = very weak, 4 = very strong). */\r\nexport type PasswordStrengthLevel = 0 | 1 | 2 | 3 | 4;\r\n\r\n/** Props for the {@link NicePasswordStrength} component. */\r\nexport interface NicePasswordStrengthProps {\r\n /** The password to evaluate. */\r\n password: string;\r\n /** Override calculated strength. */\r\n strength?: PasswordStrengthLevel;\r\n /** Whether to show text labels. */\r\n showLabel?: boolean;\r\n /** Custom labels for each level. */\r\n labels?: Record<PasswordStrengthLevel, string>;\r\n className?: string;\r\n}\r\n\r\nconst DEFAULT_LABELS: Record<PasswordStrengthLevel, string> = {\r\n 0: 'Very weak',\r\n 1: 'Weak',\r\n 2: 'Fair',\r\n 3: 'Strong',\r\n 4: 'Very strong',\r\n};\r\n\r\nconst COLORS: Record<PasswordStrengthLevel, string> = {\r\n 0: '#d9534f',\r\n 1: '#f0ad4e',\r\n 2: '#5bc0de',\r\n 3: '#5cb85c',\r\n 4: '#2e7d32',\r\n};\r\n\r\n/** Calculate password strength score (0-4). */\r\nexport function calcPasswordStrength(password: string): PasswordStrengthLevel {\r\n if (!password) return 0;\r\n let score = 0;\r\n if (password.length >= 8) score++;\r\n if (password.length >= 12) score++;\r\n if (/[a-z]/.test(password) && /[A-Z]/.test(password)) score++;\r\n if (/\\d/.test(password)) score++;\r\n if (/[^a-zA-Z0-9]/.test(password)) score++;\r\n return Math.min(4, score) as PasswordStrengthLevel;\r\n}\r\n\r\n/**\r\n * {@link NicePasswordStrength} — Visual password strength indicator bar\r\n * with color-coded levels and text labels.\r\n */\r\nexport const NicePasswordStrength = forwardRef<HTMLDivElement, NicePasswordStrengthProps>(({\r\n password, strength: overrideStrength, showLabel = true,\r\n labels = DEFAULT_LABELS, className,\r\n}, ref) => {\r\n const level = overrideStrength ?? calcPasswordStrength(password);\r\n const color = COLORS[level];\r\n const pct = ((level + 1) / 5) * 100;\r\n\r\n return (\r\n <div ref={ref} className={`nice-password-strength${className ? ` ${className}` : ''}`}>\r\n <div className=\"nice-password-strength__bar\">\r\n <div className=\"nice-password-strength__fill\" style={{ width: `${pct}%`, backgroundColor: color }} />\r\n </div>\r\n {showLabel && <span className=\"nice-password-strength__label\" style={{ color }}>{labels[level]}</span>}\r\n </div>\r\n );\r\n});\r\n\r\nNicePasswordStrength.displayName = 'NicePasswordStrength';\r\n","import React, { forwardRef, useState, useCallback } from 'react';\r\nimport { NicePasswordStrength, calcPasswordStrength } from './NicePasswordStrength';\r\n\r\n/** Registration data payload. */\r\nexport interface RegistrationData {\r\n firstName: string;\r\n lastName: string;\r\n email: string;\r\n password: string;\r\n acceptTerms: boolean;\r\n}\r\n\r\n/** Props for the {@link NiceRegistrationForm} component. */\r\nexport interface NiceRegistrationFormProps {\r\n /** Fires on form submit. */\r\n onSubmit?: (data: RegistrationData) => void;\r\n /** Whether a request is in progress. */\r\n loading?: boolean;\r\n /** External error message. */\r\n error?: string;\r\n /** Fires when \"Login\" link is clicked. */\r\n onLoginClick?: () => void;\r\n /** Whether to show password strength meter. */\r\n showPasswordStrength?: boolean;\r\n /** Minimum password strength level to allow submit (0-4). */\r\n minPasswordStrength?: number;\r\n /** Terms URL. */\r\n termsUrl?: string;\r\n /** Privacy URL. */\r\n privacyUrl?: string;\r\n /** Title. */\r\n title?: string;\r\n /** Logo element. */\r\n logo?: React.ReactNode;\r\n /** Footer content (OAuth buttons, etc.). */\r\n footer?: React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceRegistrationForm} — Registration form with name, email, password,\r\n * strength meter, terms acceptance, and optional OAuth footer.\r\n */\r\nexport const NiceRegistrationForm = forwardRef<HTMLFormElement, NiceRegistrationFormProps>(({\r\n onSubmit, loading = false, error, onLoginClick,\r\n showPasswordStrength = true, minPasswordStrength = 2,\r\n termsUrl, privacyUrl, title = 'Create Account',\r\n logo, footer, className, style,\r\n}, ref) => {\r\n const [firstName, setFirstName] = useState('');\r\n const [lastName, setLastName] = useState('');\r\n const [email, setEmail] = useState('');\r\n const [password, setPassword] = useState('');\r\n const [confirmPassword, setConfirmPassword] = useState('');\r\n const [acceptTerms, setAcceptTerms] = useState(false);\r\n\r\n const strength = calcPasswordStrength(password);\r\n const passwordsMatch = password === confirmPassword;\r\n const canSubmit = firstName && email && password && passwordsMatch && acceptTerms && strength >= minPasswordStrength && !loading;\r\n\r\n const handleSubmit = useCallback((e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (canSubmit) {\r\n onSubmit?.({ firstName, lastName, email, password, acceptTerms });\r\n }\r\n }, [canSubmit, firstName, lastName, email, password, acceptTerms, onSubmit]);\r\n\r\n return (\r\n <form\r\n ref={ref}\r\n className={`nice-register-form${className ? ` ${className}` : ''}`}\r\n style={style}\r\n onSubmit={handleSubmit}\r\n noValidate\r\n >\r\n {logo && <div className=\"nice-register-form__logo\">{logo}</div>}\r\n <h2 className=\"nice-register-form__title\">{title}</h2>\r\n\r\n {error && <div className=\"nice-register-form__error\" role=\"alert\">{error}</div>}\r\n\r\n <div className=\"nice-register-form__row\">\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-first\">First name *</label>\r\n <input id=\"nice-reg-first\" className=\"nice-input\" type=\"text\" value={firstName} onChange={e => setFirstName(e.target.value)} required disabled={loading} autoComplete=\"given-name\" />\r\n </div>\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-last\">Last name</label>\r\n <input id=\"nice-reg-last\" className=\"nice-input\" type=\"text\" value={lastName} onChange={e => setLastName(e.target.value)} disabled={loading} autoComplete=\"family-name\" />\r\n </div>\r\n </div>\r\n\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-email\">Email *</label>\r\n <input id=\"nice-reg-email\" className=\"nice-input\" type=\"email\" value={email} onChange={e => setEmail(e.target.value)} required disabled={loading} autoComplete=\"email\" />\r\n </div>\r\n\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-pass\">Password *</label>\r\n <input id=\"nice-reg-pass\" className=\"nice-input\" type=\"password\" value={password} onChange={e => setPassword(e.target.value)} required disabled={loading} autoComplete=\"new-password\" />\r\n {showPasswordStrength && password.length > 0 && <NicePasswordStrength password={password} />}\r\n </div>\r\n\r\n <div className=\"nice-register-form__field\">\r\n <label htmlFor=\"nice-reg-confirm\">Confirm password *</label>\r\n <input id=\"nice-reg-confirm\" className=\"nice-input\" type=\"password\" value={confirmPassword} onChange={e => setConfirmPassword(e.target.value)} required disabled={loading} autoComplete=\"new-password\" />\r\n {confirmPassword && !passwordsMatch && <span className=\"nice-error-text\">Passwords do not match</span>}\r\n </div>\r\n\r\n <label className=\"nice-register-form__terms\">\r\n <input type=\"checkbox\" checked={acceptTerms} onChange={e => setAcceptTerms(e.target.checked)} disabled={loading} />\r\n <span>\r\n I accept the{' '}\r\n {termsUrl ? <a href={termsUrl} target=\"_blank\" rel=\"noopener noreferrer\">Terms</a> : 'Terms'}\r\n {privacyUrl && <> and <a href={privacyUrl} target=\"_blank\" rel=\"noopener noreferrer\">Privacy Policy</a></>}\r\n {' *'}\r\n </span>\r\n </label>\r\n\r\n <button type=\"submit\" className=\"nice-btn nice-btn--primary nice-register-form__submit\" disabled={!canSubmit}>\r\n {loading ? '…' : 'Register'}\r\n </button>\r\n\r\n {onLoginClick && (\r\n <div className=\"nice-register-form__login\">\r\n <span>Already have an account? </span>\r\n <button type=\"button\" onClick={onLoginClick}>Sign in</button>\r\n </div>\r\n )}\r\n\r\n {footer && <div className=\"nice-register-form__footer\">{footer}</div>}\r\n </form>\r\n );\r\n});\r\n\r\nNiceRegistrationForm.displayName = 'NiceRegistrationForm';\r\n","import React, { forwardRef, useState, useCallback } from 'react';\r\nimport { NicePasswordStrength, calcPasswordStrength } from './NicePasswordStrength';\r\n\r\n/** Props for the {@link NiceChangePassword} component. */\r\nexport interface NiceChangePasswordProps {\r\n /** Whether the user must provide current password. */\r\n requireCurrentPassword?: boolean;\r\n /** Fires on submit. */\r\n onSubmit?: (data: { currentPassword?: string; newPassword: string }) => void;\r\n /** Whether a request is in progress. */\r\n loading?: boolean;\r\n /** External error message. */\r\n error?: string;\r\n /** Success message after password change. */\r\n success?: string;\r\n /** Minimum password strength to allow submit (0-4). */\r\n minPasswordStrength?: number;\r\n /** Title. */\r\n title?: string;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceChangePassword} — Change/reset password form with strength meter.\r\n */\r\nexport const NiceChangePassword = forwardRef<HTMLFormElement, NiceChangePasswordProps>(({\r\n requireCurrentPassword = true, onSubmit, loading = false,\r\n error, success, minPasswordStrength = 2,\r\n title = 'Change Password', className, style,\r\n}, ref) => {\r\n const [currentPassword, setCurrentPassword] = useState('');\r\n const [newPassword, setNewPassword] = useState('');\r\n const [confirmPassword, setConfirmPassword] = useState('');\r\n\r\n const strength = calcPasswordStrength(newPassword);\r\n const passwordsMatch = newPassword === confirmPassword;\r\n const canSubmit = (!requireCurrentPassword || currentPassword.length > 0) &&\r\n newPassword.length > 0 && passwordsMatch && strength >= minPasswordStrength && !loading;\r\n\r\n const handleSubmit = useCallback((e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (canSubmit) {\r\n onSubmit?.({\r\n currentPassword: requireCurrentPassword ? currentPassword : undefined,\r\n newPassword,\r\n });\r\n }\r\n }, [canSubmit, currentPassword, newPassword, requireCurrentPassword, onSubmit]);\r\n\r\n return (\r\n <form\r\n ref={ref}\r\n className={`nice-change-password${className ? ` ${className}` : ''}`}\r\n style={style}\r\n onSubmit={handleSubmit}\r\n noValidate\r\n >\r\n <h3 className=\"nice-change-password__title\">{title}</h3>\r\n\r\n {error && <div className=\"nice-change-password__error\" role=\"alert\">{error}</div>}\r\n {success && <div className=\"nice-change-password__success\" role=\"status\">{success}</div>}\r\n\r\n {requireCurrentPassword && (\r\n <div className=\"nice-change-password__field\">\r\n <label htmlFor=\"nice-cp-current\">Current password</label>\r\n <input\r\n id=\"nice-cp-current\"\r\n className=\"nice-input\"\r\n type=\"password\"\r\n value={currentPassword}\r\n onChange={e => setCurrentPassword(e.target.value)}\r\n autoComplete=\"current-password\"\r\n disabled={loading}\r\n required\r\n />\r\n </div>\r\n )}\r\n\r\n <div className=\"nice-change-password__field\">\r\n <label htmlFor=\"nice-cp-new\">New password</label>\r\n <input\r\n id=\"nice-cp-new\"\r\n className=\"nice-input\"\r\n type=\"password\"\r\n value={newPassword}\r\n onChange={e => setNewPassword(e.target.value)}\r\n autoComplete=\"new-password\"\r\n disabled={loading}\r\n required\r\n />\r\n {newPassword.length > 0 && <NicePasswordStrength password={newPassword} />}\r\n </div>\r\n\r\n <div className=\"nice-change-password__field\">\r\n <label htmlFor=\"nice-cp-confirm\">Confirm new password</label>\r\n <input\r\n id=\"nice-cp-confirm\"\r\n className=\"nice-input\"\r\n type=\"password\"\r\n value={confirmPassword}\r\n onChange={e => setConfirmPassword(e.target.value)}\r\n autoComplete=\"new-password\"\r\n disabled={loading}\r\n required\r\n />\r\n {confirmPassword && !passwordsMatch && <span className=\"nice-error-text\">Passwords do not match</span>}\r\n </div>\r\n\r\n <button type=\"submit\" className=\"nice-btn nice-btn--primary\" disabled={!canSubmit}>\r\n {loading ? '…' : 'Change Password'}\r\n </button>\r\n </form>\r\n );\r\n});\r\n\r\nNiceChangePassword.displayName = 'NiceChangePassword';\r\n","import React, { forwardRef, useState, useCallback } from 'react';\r\n\r\n/** Props for the {@link NiceTwoFaSetup} component. */\r\nexport interface NiceTwoFaSetupProps {\r\n /** The TOTP secret key (base32 encoded). */\r\n secret: string;\r\n /** QR code image URL or data URL for the authenticator app. */\r\n qrCodeUrl?: string;\r\n /** Issuer name for the TOTP URI. */\r\n issuer?: string;\r\n /** User's account name. */\r\n accountName?: string;\r\n /** Fires when user submits verification code. */\r\n onVerify?: (code: string) => void;\r\n /** Whether verification is in progress. */\r\n loading?: boolean;\r\n /** Error message (e.g. \"Invalid code\"). */\r\n error?: string;\r\n /** Fires on back/cancel. */\r\n onCancel?: () => void;\r\n /** Recovery codes to display after setup. */\r\n recoveryCodes?: string[];\r\n /** Step: 'setup' = show QR, 'verify' = enter code, 'recovery' = show codes. */\r\n step?: 'setup' | 'verify' | 'recovery';\r\n /** Fires when step changes. */\r\n onStepChange?: (step: 'setup' | 'verify' | 'recovery') => void;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceTwoFaSetup} — Two-factor authentication setup wizard with\r\n * QR code display, secret key, verification code input, and recovery codes.\r\n */\r\nexport const NiceTwoFaSetup = forwardRef<HTMLDivElement, NiceTwoFaSetupProps>(({\r\n secret, qrCodeUrl, issuer, accountName,\r\n onVerify, loading = false, error, onCancel,\r\n recoveryCodes, step = 'setup', onStepChange,\r\n className, style,\r\n}, ref) => {\r\n const [code, setCode] = useState('');\r\n const [showSecret, setShowSecret] = useState(false);\r\n const [copiedCodes, setCopiedCodes] = useState(false);\r\n\r\n const handleVerify = useCallback((e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (code.length >= 6) {\r\n onVerify?.(code);\r\n }\r\n }, [code, onVerify]);\r\n\r\n const totpUri = `otpauth://totp/${issuer ? `${issuer}:` : ''}${accountName ?? 'user'}?secret=${secret}${issuer ? `&issuer=${issuer}` : ''}&digits=6&period=30`;\r\n\r\n return (\r\n <div ref={ref} className={`nice-2fa-setup${className ? ` ${className}` : ''}`} style={style}>\r\n <h3 className=\"nice-2fa-setup__title\">Two-Factor Authentication</h3>\r\n\r\n {step === 'setup' && (\r\n <div className=\"nice-2fa-setup__step\">\r\n <p className=\"nice-2fa-setup__instruction\">\r\n Scan this QR code with your authenticator app (Google Authenticator, Authy, etc.):\r\n </p>\r\n\r\n {qrCodeUrl ? (\r\n <img src={qrCodeUrl} alt=\"2FA QR Code\" className=\"nice-2fa-setup__qr\" />\r\n ) : (\r\n <div className=\"nice-2fa-setup__qr-placeholder\">\r\n <span>QR Code</span>\r\n <code className=\"nice-2fa-setup__uri\">{totpUri}</code>\r\n </div>\r\n )}\r\n\r\n <div className=\"nice-2fa-setup__secret\">\r\n <span>Or enter manually: </span>\r\n {showSecret ? (\r\n <code className=\"nice-2fa-setup__secret-key\">{secret}</code>\r\n ) : (\r\n <button type=\"button\" onClick={() => setShowSecret(true)}>Show secret key</button>\r\n )}\r\n </div>\r\n\r\n <button type=\"button\" className=\"nice-btn nice-btn--primary\" onClick={() => onStepChange?.('verify')}>\r\n Next — Verify\r\n </button>\r\n </div>\r\n )}\r\n\r\n {step === 'verify' && (\r\n <form className=\"nice-2fa-setup__step\" onSubmit={handleVerify}>\r\n <p className=\"nice-2fa-setup__instruction\">\r\n Enter the 6-digit code from your authenticator app:\r\n </p>\r\n\r\n {error && <div className=\"nice-2fa-setup__error\" role=\"alert\">{error}</div>}\r\n\r\n <input\r\n className=\"nice-input nice-2fa-setup__code-input\"\r\n type=\"text\"\r\n inputMode=\"numeric\"\r\n maxLength={6}\r\n value={code}\r\n onChange={e => setCode(e.target.value.replace(/\\D/g, '').slice(0, 6))}\r\n placeholder=\"000000\"\r\n autoFocus\r\n disabled={loading}\r\n autoComplete=\"one-time-code\"\r\n />\r\n\r\n <div className=\"nice-2fa-setup__actions\">\r\n <button type=\"button\" className=\"nice-btn\" onClick={() => onStepChange?.('setup')}>Back</button>\r\n <button type=\"submit\" className=\"nice-btn nice-btn--primary\" disabled={loading || code.length < 6}>\r\n {loading ? '…' : 'Verify'}\r\n </button>\r\n </div>\r\n </form>\r\n )}\r\n\r\n {step === 'recovery' && recoveryCodes && (\r\n <div className=\"nice-2fa-setup__step\">\r\n <p className=\"nice-2fa-setup__instruction\">\r\n Save these recovery codes in a safe place. Each code can only be used once:\r\n </p>\r\n\r\n <div className=\"nice-2fa-setup__recovery-codes\">\r\n {recoveryCodes.map((rc, i) => (\r\n <code key={i} className=\"nice-2fa-setup__recovery-code\">{rc}</code>\r\n ))}\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n className=\"nice-btn\"\r\n onClick={() => {\r\n navigator.clipboard?.writeText(recoveryCodes.join('\\n'));\r\n setCopiedCodes(true);\r\n }}\r\n >\r\n {copiedCodes ? 'Copied!' : 'Copy all codes'}\r\n </button>\r\n\r\n {onCancel && <button type=\"button\" className=\"nice-btn nice-btn--primary\" onClick={onCancel}>Done</button>}\r\n </div>\r\n )}\r\n\r\n {onCancel && step !== 'recovery' && (\r\n <button type=\"button\" className=\"nice-2fa-setup__cancel\" onClick={onCancel}>Cancel</button>\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\nNiceTwoFaSetup.displayName = 'NiceTwoFaSetup';\r\n","import React, { forwardRef } from 'react';\r\n\r\n/** Captcha provider type. */\r\nexport type CaptchaProvider = 'custom' | 'recaptcha' | 'hcaptcha' | 'turnstile';\r\n\r\n/** Props for the {@link NiceCaptcha} component. */\r\nexport interface NiceCaptchaProps {\r\n /** Captcha provider. */\r\n provider?: CaptchaProvider;\r\n /** Site key for the captcha provider. */\r\n siteKey?: string;\r\n /** Fires when captcha is verified with a token. */\r\n onVerify?: (token: string) => void;\r\n /** Fires when captcha expires. */\r\n onExpire?: () => void;\r\n /** Fires on captcha error. */\r\n onError?: (error: unknown) => void;\r\n /** Theme. */\r\n theme?: 'light' | 'dark';\r\n /** Size. */\r\n size?: 'normal' | 'compact' | 'invisible';\r\n /** Custom render for provider='custom'. */\r\n customRender?: React.ReactNode;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceCaptcha} — Pluggable captcha widget shell.\r\n * For production use, inject the actual captcha SDK via `customRender` or\r\n * integrate the provider script externally. This component provides a\r\n * consistent wrapper API.\r\n */\r\nexport const NiceCaptcha = forwardRef<HTMLDivElement, NiceCaptchaProps>(({\r\n provider = 'custom', siteKey, onVerify, onExpire, onError,\r\n theme = 'light', size = 'normal', customRender,\r\n className, style,\r\n}, ref) => {\r\n if (provider === 'custom' && customRender) {\r\n return (\r\n <div ref={ref} className={`nice-captcha nice-captcha--custom${className ? ` ${className}` : ''}`} style={style}>\r\n {customRender}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={`nice-captcha nice-captcha--${provider} nice-captcha--${theme}${size === 'compact' ? ' nice-captcha--compact' : ''}${className ? ` ${className}` : ''}`}\r\n style={style}\r\n data-sitekey={siteKey}\r\n data-theme={theme}\r\n data-size={size}\r\n >\r\n <div className=\"nice-captcha__placeholder\">\r\n <span>🔒 Captcha ({provider})</span>\r\n <p>Load the {provider} SDK to activate verification.</p>\r\n </div>\r\n </div>\r\n );\r\n});\r\n\r\nNiceCaptcha.displayName = 'NiceCaptcha';\r\n","import React, { forwardRef } from 'react';\r\n\r\n/** OAuth provider definition. */\r\nexport interface OAuthProvider {\r\n /** Unique provider id. */\r\n id: string;\r\n /** Display label. */\r\n label: string;\r\n /** Icon (emoji, SVG element, or URL). */\r\n icon?: React.ReactNode;\r\n /** Brand color for the button. */\r\n color?: string;\r\n /** Text color. */\r\n textColor?: string;\r\n}\r\n\r\n/** Props for the {@link NiceOAuthButtons} component. */\r\nexport interface NiceOAuthButtonsProps {\r\n /** Providers to display. */\r\n providers?: OAuthProvider[];\r\n /** Fires when a provider button is clicked. */\r\n onProviderClick?: (providerId: string) => void;\r\n /** Whether buttons are disabled. */\r\n disabled?: boolean;\r\n /** Loading provider id (shows spinner on that button). */\r\n loadingProvider?: string;\r\n /** Layout direction. */\r\n direction?: 'horizontal' | 'vertical';\r\n /** Separator text (e.g. \"or continue with\"). */\r\n separatorText?: string;\r\n /** Whether to show separator above buttons. */\r\n showSeparator?: boolean;\r\n className?: string;\r\n style?: React.CSSProperties;\r\n}\r\n\r\nconst DEFAULT_PROVIDERS: OAuthProvider[] = [\r\n { id: 'google', label: 'Google', icon: '🔵', color: '#4285f4', textColor: '#fff' },\r\n { id: 'microsoft', label: 'Microsoft', icon: '🟦', color: '#00a4ef', textColor: '#fff' },\r\n { id: 'discord', label: 'Discord', icon: '💬', color: '#5865f2', textColor: '#fff' },\r\n { id: 'spotify', label: 'Spotify', icon: '🎵', color: '#1db954', textColor: '#fff' },\r\n { id: 'github', label: 'GitHub', icon: '🐙', color: '#24292e', textColor: '#fff' },\r\n];\r\n\r\n/**\r\n * {@link NiceOAuthButtons} — OAuth login/registration buttons for popular providers.\r\n */\r\nexport const NiceOAuthButtons = forwardRef<HTMLDivElement, NiceOAuthButtonsProps>(({\r\n providers = DEFAULT_PROVIDERS, onProviderClick, disabled = false,\r\n loadingProvider, direction = 'vertical', separatorText = 'or continue with',\r\n showSeparator = true, className, style,\r\n}, ref) => (\r\n <div\r\n ref={ref}\r\n className={`nice-oauth nice-oauth--${direction}${className ? ` ${className}` : ''}`}\r\n style={style}\r\n >\r\n {showSeparator && (\r\n <div className=\"nice-oauth__separator\">\r\n <hr /><span>{separatorText}</span><hr />\r\n </div>\r\n )}\r\n\r\n <div className=\"nice-oauth__buttons\">\r\n {providers.map(provider => (\r\n <button\r\n key={provider.id}\r\n type=\"button\"\r\n className={`nice-oauth__btn${loadingProvider === provider.id ? ' nice-oauth__btn--loading' : ''}`}\r\n style={{ backgroundColor: provider.color, color: provider.textColor }}\r\n onClick={() => onProviderClick?.(provider.id)}\r\n disabled={disabled || !!loadingProvider}\r\n >\r\n {provider.icon && <span className=\"nice-oauth__btn-icon\">{provider.icon}</span>}\r\n <span className=\"nice-oauth__btn-label\">\r\n {loadingProvider === provider.id ? '…' : provider.label}\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n));\r\n\r\nNiceOAuthButtons.displayName = 'NiceOAuthButtons';\r\n","import React, { useState, forwardRef, useCallback } from 'react';\r\n\r\n// ── Types ──────────────────────────────────────────────────\r\n\r\n/** API token entry. */\r\nexport interface ApiToken {\r\n id: string;\r\n name: string;\r\n prefix: string;\r\n createdAt: string;\r\n expiresAt?: string;\r\n lastUsedAt?: string;\r\n scopes?: string[];\r\n}\r\n\r\n/** Props for {@link NiceTokenManagement}. */\r\nexport interface NiceTokenManagementProps {\r\n /** Existing tokens. */\r\n tokens: ApiToken[];\r\n /** Called to create a new token. Should return the full token string (only shown once). */\r\n onCreate?: (name: string, scopes: string[], expiresInDays?: number) => Promise<string>;\r\n /** Called to revoke a token. */\r\n onRevoke?: (tokenId: string) => Promise<void>;\r\n /** Available scopes for new tokens. */\r\n availableScopes?: string[];\r\n /** Maximum number of tokens allowed. */\r\n maxTokens?: number;\r\n /** Title. */\r\n title?: string;\r\n /** CSS class name. */\r\n className?: string;\r\n /** Inline styles. */\r\n style?: React.CSSProperties;\r\n}\r\n\r\n/**\r\n * {@link NiceTokenManagement} — API token management UI.\r\n * \r\n * Create, view, and revoke personal API tokens. New token values are shown\r\n * once after creation. Supports scopes and expiration.\r\n */\r\nexport const NiceTokenManagement = forwardRef<HTMLDivElement, NiceTokenManagementProps>(function NiceTokenManagement(props, ref) {\r\n const {\r\n tokens,\r\n onCreate,\r\n onRevoke,\r\n availableScopes = [],\r\n maxTokens = 10,\r\n title = 'API Tokens',\r\n className,\r\n style,\r\n } = props;\r\n\r\n const [showCreate, setShowCreate] = useState(false);\r\n const [newName, setNewName] = useState('');\r\n const [selectedScopes, setSelectedScopes] = useState<string[]>([]);\r\n const [expDays, setExpDays] = useState('90');\r\n const [newTokenValue, setNewTokenValue] = useState<string | null>(null);\r\n const [loading, setLoading] = useState(false);\r\n const [revoking, setRevoking] = useState<string | null>(null);\r\n\r\n const handleCreate = useCallback(async () => {\r\n if (!onCreate || !newName.trim()) return;\r\n setLoading(true);\r\n try {\r\n const days = expDays ? parseInt(expDays, 10) : undefined;\r\n const tokenStr = await onCreate(newName.trim(), selectedScopes, days);\r\n setNewTokenValue(tokenStr);\r\n setNewName('');\r\n setSelectedScopes([]);\r\n setShowCreate(false);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [onCreate, newName, selectedScopes, expDays]);\r\n\r\n const handleRevoke = useCallback(async (id: string) => {\r\n if (!onRevoke) return;\r\n setRevoking(id);\r\n try {\r\n await onRevoke(id);\r\n } finally {\r\n setRevoking(null);\r\n }\r\n }, [onRevoke]);\r\n\r\n const toggleScope = (scope: string) => {\r\n setSelectedScopes(prev => prev.includes(scope) ? prev.filter(s => s !== scope) : [...prev, scope]);\r\n };\r\n\r\n const canCreate = tokens.length < maxTokens;\r\n\r\n return (\r\n <div ref={ref} className={`nice-token-management ${className ?? ''}`} style={style}>\r\n <div className=\"nice-token-management__header\">\r\n <h3>{title}</h3>\r\n {canCreate && (\r\n <button className=\"nice-token-management__new-btn\" onClick={() => setShowCreate(true)} disabled={showCreate}>\r\n + New Token\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* ── Reveal banner ── */}\r\n {newTokenValue && (\r\n <div className=\"nice-token-management__reveal\">\r\n <p><strong>New token created!</strong> Copy it now — it won't be shown again.</p>\r\n <code className=\"nice-token-management__token-value\">{newTokenValue}</code>\r\n <button onClick={() => setNewTokenValue(null)}>Dismiss</button>\r\n </div>\r\n )}\r\n\r\n {/* ── Create form ── */}\r\n {showCreate && (\r\n <div className=\"nice-token-management__create-form\">\r\n <label>\r\n Name\r\n <input\r\n type=\"text\"\r\n value={newName}\r\n onChange={e => setNewName(e.target.value)}\r\n placeholder=\"My API token\"\r\n maxLength={64}\r\n />\r\n </label>\r\n\r\n {availableScopes.length > 0 && (\r\n <fieldset>\r\n <legend>Scopes</legend>\r\n {availableScopes.map(scope => (\r\n <label key={scope} className=\"nice-token-management__scope\">\r\n <input\r\n type=\"checkbox\"\r\n checked={selectedScopes.includes(scope)}\r\n onChange={() => toggleScope(scope)}\r\n />\r\n {scope}\r\n </label>\r\n ))}\r\n </fieldset>\r\n )}\r\n\r\n <label>\r\n Expires in (days)\r\n <input\r\n type=\"number\"\r\n value={expDays}\r\n onChange={e => setExpDays(e.target.value)}\r\n min={1}\r\n max={365}\r\n />\r\n </label>\r\n\r\n <div className=\"nice-token-management__create-actions\">\r\n <button onClick={handleCreate} disabled={loading || !newName.trim()}>\r\n {loading ? 'Creating…' : 'Create Token'}\r\n </button>\r\n <button onClick={() => setShowCreate(false)}>Cancel</button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* ── Token list ── */}\r\n {tokens.length === 0 ? (\r\n <p className=\"nice-token-management__empty\">No API tokens yet.</p>\r\n ) : (\r\n <table className=\"nice-token-management__table\">\r\n <thead>\r\n <tr>\r\n <th>Name</th>\r\n <th>Prefix</th>\r\n <th>Created</th>\r\n <th>Expires</th>\r\n <th>Last Used</th>\r\n <th>Scopes</th>\r\n <th />\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {tokens.map(t => (\r\n <tr key={t.id}>\r\n <td>{t.name}</td>\r\n <td><code>{t.prefix}…</code></td>\r\n <td>{t.createdAt}</td>\r\n <td>{t.expiresAt ?? '—'}</td>\r\n <td>{t.lastUsedAt ?? 'Never'}</td>\r\n <td>{t.scopes?.join(', ') || '—'}</td>\r\n <td>\r\n <button\r\n className=\"nice-token-management__revoke-btn\"\r\n onClick={() => handleRevoke(t.id)}\r\n disabled={revoking === t.id}\r\n >\r\n {revoking === t.id ? 'Revoking…' : 'Revoke'}\r\n </button>\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n )}\r\n </div>\r\n );\r\n});\r\n"],"names":["useAuth","config","onLogin","onRefresh","onLogout","storageKey","persistAuth","state","setState","useState","stored","persist","useCallback","newState","prev","next","login","email","password","result","err","logout","refreshToken","_a","tokens","setAuth","user","hasRoles","roles","r","hasPermissions","permissions","p","clearError","NiceLoginForm","forwardRef","onSubmit","loading","error","showRememberMe","showForgotPassword","onForgotPassword","showRegisterLink","onRegisterClick","title","submitLabel","logo","footer","className","style","emailLabel","passwordLabel","ref","setEmail","setPassword","rememberMe","setRememberMe","handleSubmit","e","jsxs","jsx","DEFAULT_LABELS","COLORS","calcPasswordStrength","score","NicePasswordStrength","overrideStrength","showLabel","labels","level","color","pct","NiceRegistrationForm","onLoginClick","showPasswordStrength","minPasswordStrength","termsUrl","privacyUrl","firstName","setFirstName","lastName","setLastName","confirmPassword","setConfirmPassword","acceptTerms","setAcceptTerms","strength","passwordsMatch","canSubmit","Fragment","NiceChangePassword","requireCurrentPassword","success","currentPassword","setCurrentPassword","newPassword","setNewPassword","NiceTwoFaSetup","secret","qrCodeUrl","issuer","accountName","onVerify","onCancel","recoveryCodes","step","onStepChange","code","setCode","showSecret","setShowSecret","copiedCodes","setCopiedCodes","handleVerify","totpUri","rc","i","NiceCaptcha","provider","siteKey","onExpire","onError","theme","size","customRender","DEFAULT_PROVIDERS","NiceOAuthButtons","providers","onProviderClick","disabled","loadingProvider","direction","separatorText","showSeparator","NiceTokenManagement","props","onCreate","onRevoke","availableScopes","maxTokens","showCreate","setShowCreate","newName","setNewName","selectedScopes","setSelectedScopes","expDays","setExpDays","newTokenValue","setNewTokenValue","setLoading","revoking","setRevoking","handleCreate","days","tokenStr","handleRevoke","id","toggleScope","scope","s","canCreate","t"],"mappings":"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"}
|