@dudousxd/adonis-authkit-react 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +26 -0
  2. package/build/index.d.ts +47 -0
  3. package/build/index.js +24 -0
  4. package/build/src/authkit_provider.d.ts +13 -0
  5. package/build/src/authkit_provider.js +11 -0
  6. package/build/src/components/authorized_apps.d.ts +8 -0
  7. package/build/src/components/authorized_apps.js +26 -0
  8. package/build/src/components/avatar.d.ts +22 -0
  9. package/build/src/components/avatar.js +15 -0
  10. package/build/src/components/organization_profile.d.ts +8 -0
  11. package/build/src/components/organization_profile.js +87 -0
  12. package/build/src/components/organization_switcher.d.ts +7 -0
  13. package/build/src/components/organization_switcher.js +57 -0
  14. package/build/src/components/password_strength_meter.d.ts +11 -0
  15. package/build/src/components/password_strength_meter.js +39 -0
  16. package/build/src/components/sign_in_button.d.ts +297 -0
  17. package/build/src/components/sign_in_button.js +16 -0
  18. package/build/src/components/sign_out_button.d.ts +296 -0
  19. package/build/src/components/sign_out_button.js +16 -0
  20. package/build/src/components/user_button.d.ts +8 -0
  21. package/build/src/components/user_button.js +31 -0
  22. package/build/src/components/user_profile.d.ts +6 -0
  23. package/build/src/components/user_profile.js +27 -0
  24. package/build/src/config.d.ts +27 -0
  25. package/build/src/config.js +40 -0
  26. package/build/src/hooks/use_authorized_apps.d.ts +16 -0
  27. package/build/src/hooks/use_authorized_apps.js +15 -0
  28. package/build/src/hooks/use_org_invitations.d.ts +19 -0
  29. package/build/src/hooks/use_org_invitations.js +20 -0
  30. package/build/src/hooks/use_organization.d.ts +23 -0
  31. package/build/src/hooks/use_organization.js +8 -0
  32. package/build/src/hooks/use_organizations.d.ts +18 -0
  33. package/build/src/hooks/use_organizations.js +14 -0
  34. package/build/src/hooks/use_password_strength.d.ts +11 -0
  35. package/build/src/hooks/use_password_strength.js +34 -0
  36. package/build/src/hooks/use_profile.d.ts +13 -0
  37. package/build/src/hooks/use_profile.js +28 -0
  38. package/build/src/hooks/use_resource.d.ts +11 -0
  39. package/build/src/hooks/use_resource.js +48 -0
  40. package/build/src/hooks/use_sessions.d.ts +16 -0
  41. package/build/src/hooks/use_sessions.js +15 -0
  42. package/build/src/hooks/use_sign_in.d.ts +6 -0
  43. package/build/src/hooks/use_sign_in.js +13 -0
  44. package/build/src/hooks/use_sign_out.d.ts +6 -0
  45. package/build/src/hooks/use_sign_out.js +11 -0
  46. package/build/src/hooks/use_switch_organization.d.ts +7 -0
  47. package/build/src/hooks/use_switch_organization.js +42 -0
  48. package/build/src/hooks/use_user.d.ts +6 -0
  49. package/build/src/hooks/use_user.js +5 -0
  50. package/build/src/use_auth.js +1 -1
  51. package/build/src/utils.d.ts +2 -0
  52. package/build/src/utils.js +18 -0
  53. package/package.json +9 -7
  54. package/styles.css +294 -0
package/README.md CHANGED
@@ -108,6 +108,32 @@ import { AuthProvider } from '@dudousxd/adonis-authkit-react'
108
108
  </AuthProvider>
109
109
  ```
110
110
 
111
+ ## 5. Config + componentes prontos
112
+
113
+ Envolva a app com `<AuthkitProvider>` para configurar URLs/endpoints e use os
114
+ hooks headless e componentes prontos:
115
+
116
+ ```tsx
117
+ import '@dudousxd/adonis-authkit-react/styles.css'
118
+ import {
119
+ AuthkitProvider,
120
+ useSignIn, useSignOut, useUser, useProfile, useSessions, useAuthorizedApps,
121
+ SignInButton, SignOutButton, UserButton, UserProfile, AuthorizedApps,
122
+ } from '@dudousxd/adonis-authkit-react'
123
+
124
+ <AuthkitProvider config={{ csrfToken: page.props.csrfToken }}>
125
+ <UserButton />
126
+ <UserProfile />
127
+ <AuthorizedApps />
128
+ </AuthkitProvider>
129
+ ```
130
+
131
+ Defaults dos endpoints apontam para as rotas reais do host-kit
132
+ (`/auth/login`, `/account/logout`, `/account/security`, `/account/security/profile`,
133
+ `/account/apps`, …). Numa topologia de *client app*, aponte-os para rotas locais que
134
+ redirecionam para o IdP. Temável via CSS vars `--authkit-*`. Veja a
135
+ [doc de React](https://...) para detalhes.
136
+
111
137
  ## Helpers puros
112
138
 
113
139
  Para uso fora de componentes, as funções de papéis são exportadas e livres de React:
package/build/index.d.ts CHANGED
@@ -1,9 +1,56 @@
1
1
  export { useAuth } from './src/use_auth.js';
2
2
  export { AuthProvider, AuthContext } from './src/provider.js';
3
3
  export type { AuthProviderProps } from './src/provider.js';
4
+ export { AuthkitProvider } from './src/authkit_provider.js';
5
+ export type { AuthkitProviderProps } from './src/authkit_provider.js';
6
+ export { AuthkitConfigContext, useAuthkitConfig, resolveConfig, buildAuthUrl, DEFAULT_CONFIG, } from './src/config.js';
7
+ export type { AuthkitConfig, ResolvedAuthkitConfig, AuthkitEndpoints, } from './src/config.js';
8
+ export { useSignIn } from './src/hooks/use_sign_in.js';
9
+ export type { SignInOptions } from './src/hooks/use_sign_in.js';
10
+ export { useSignOut } from './src/hooks/use_sign_out.js';
11
+ export type { SignOutOptions } from './src/hooks/use_sign_out.js';
12
+ export { useUser } from './src/hooks/use_user.js';
13
+ export type { UseUserResult } from './src/hooks/use_user.js';
14
+ export { useProfile } from './src/hooks/use_profile.js';
15
+ export type { UseProfileResult, ProfileUpdate } from './src/hooks/use_profile.js';
16
+ export { useSessions } from './src/hooks/use_sessions.js';
17
+ export type { UseSessionsResult, AuthSession } from './src/hooks/use_sessions.js';
18
+ export { useAuthorizedApps } from './src/hooks/use_authorized_apps.js';
19
+ export type { UseAuthorizedAppsResult, AuthorizedApp } from './src/hooks/use_authorized_apps.js';
20
+ export { useOrganizations } from './src/hooks/use_organizations.js';
21
+ export type { UseOrganizationsResult, OrgEntry } from './src/hooks/use_organizations.js';
22
+ export { useOrganization } from './src/hooks/use_organization.js';
23
+ export type { UseOrganizationResult, ActiveOrgDetail, OrgMemberEntry } from './src/hooks/use_organization.js';
24
+ export { useSwitchOrganization } from './src/hooks/use_switch_organization.js';
25
+ export type { UseSwitchOrganizationResult } from './src/hooks/use_switch_organization.js';
26
+ export { useOrgInvitations } from './src/hooks/use_org_invitations.js';
27
+ export type { UseOrgInvitationsResult, OrgInvitationEntry } from './src/hooks/use_org_invitations.js';
28
+ export { jsonRequest, useResource } from './src/hooks/use_resource.js';
29
+ export type { ResourceState } from './src/hooks/use_resource.js';
30
+ export { usePasswordStrength, heuristicScorer, } from './src/hooks/use_password_strength.js';
31
+ export type { PasswordStrengthScore, PasswordStrengthResult, PasswordScorer, UsePasswordStrengthOptions, } from './src/hooks/use_password_strength.js';
32
+ export { deriveInitials, currentUrl } from './src/utils.js';
4
33
  export { Authenticated, Guest } from './src/components/authenticated.js';
5
34
  export type { AuthenticatedProps, GuestProps } from './src/components/authenticated.js';
6
35
  export { Can } from './src/components/can.js';
7
36
  export type { CanProps } from './src/components/can.js';
37
+ export { SignInButton } from './src/components/sign_in_button.js';
38
+ export type { SignInButtonProps } from './src/components/sign_in_button.js';
39
+ export { SignOutButton } from './src/components/sign_out_button.js';
40
+ export type { SignOutButtonProps } from './src/components/sign_out_button.js';
41
+ export { Avatar } from './src/components/avatar.js';
42
+ export type { AvatarProps } from './src/components/avatar.js';
43
+ export { UserButton } from './src/components/user_button.js';
44
+ export type { UserButtonProps } from './src/components/user_button.js';
45
+ export { UserProfile } from './src/components/user_profile.js';
46
+ export type { UserProfileProps } from './src/components/user_profile.js';
47
+ export { AuthorizedApps } from './src/components/authorized_apps.js';
48
+ export type { AuthorizedAppsProps } from './src/components/authorized_apps.js';
49
+ export { PasswordStrengthMeter } from './src/components/password_strength_meter.js';
50
+ export type { PasswordStrengthMeterProps } from './src/components/password_strength_meter.js';
51
+ export { OrganizationSwitcher } from './src/components/organization_switcher.js';
52
+ export type { OrganizationSwitcherProps } from './src/components/organization_switcher.js';
53
+ export { OrganizationProfile } from './src/components/organization_profile.js';
54
+ export type { OrganizationProfileProps } from './src/components/organization_profile.js';
8
55
  export { hasGlobalRole, hasAnyGlobalRole, hasAllGlobalRoles, hasAppRole, hasAnyAppRole, hasAllAppRoles, } from './src/roles.js';
9
56
  export type { AuthUser, AuthSharedProps, AuthState } from './src/types.js';
package/build/index.js CHANGED
@@ -1,5 +1,29 @@
1
1
  export { useAuth } from './src/use_auth.js';
2
2
  export { AuthProvider, AuthContext } from './src/provider.js';
3
+ export { AuthkitProvider } from './src/authkit_provider.js';
4
+ export { AuthkitConfigContext, useAuthkitConfig, resolveConfig, buildAuthUrl, DEFAULT_CONFIG, } from './src/config.js';
5
+ export { useSignIn } from './src/hooks/use_sign_in.js';
6
+ export { useSignOut } from './src/hooks/use_sign_out.js';
7
+ export { useUser } from './src/hooks/use_user.js';
8
+ export { useProfile } from './src/hooks/use_profile.js';
9
+ export { useSessions } from './src/hooks/use_sessions.js';
10
+ export { useAuthorizedApps } from './src/hooks/use_authorized_apps.js';
11
+ export { useOrganizations } from './src/hooks/use_organizations.js';
12
+ export { useOrganization } from './src/hooks/use_organization.js';
13
+ export { useSwitchOrganization } from './src/hooks/use_switch_organization.js';
14
+ export { useOrgInvitations } from './src/hooks/use_org_invitations.js';
15
+ export { jsonRequest, useResource } from './src/hooks/use_resource.js';
16
+ export { usePasswordStrength, heuristicScorer, } from './src/hooks/use_password_strength.js';
17
+ export { deriveInitials, currentUrl } from './src/utils.js';
3
18
  export { Authenticated, Guest } from './src/components/authenticated.js';
4
19
  export { Can } from './src/components/can.js';
20
+ export { SignInButton } from './src/components/sign_in_button.js';
21
+ export { SignOutButton } from './src/components/sign_out_button.js';
22
+ export { Avatar } from './src/components/avatar.js';
23
+ export { UserButton } from './src/components/user_button.js';
24
+ export { UserProfile } from './src/components/user_profile.js';
25
+ export { AuthorizedApps } from './src/components/authorized_apps.js';
26
+ export { PasswordStrengthMeter } from './src/components/password_strength_meter.js';
27
+ export { OrganizationSwitcher } from './src/components/organization_switcher.js';
28
+ export { OrganizationProfile } from './src/components/organization_profile.js';
5
29
  export { hasGlobalRole, hasAnyGlobalRole, hasAllGlobalRoles, hasAppRole, hasAnyAppRole, hasAllAppRoles, } from './src/roles.js';
@@ -0,0 +1,13 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type AuthkitConfig } from './config.js';
3
+ import type { AuthSharedProps } from './types.js';
4
+ export interface AuthkitProviderProps {
5
+ config?: AuthkitConfig;
6
+ value?: AuthSharedProps['authkit'];
7
+ children: ReactNode;
8
+ }
9
+ export declare function AuthkitProvider({ config, value, children }: AuthkitProviderProps): import("react").FunctionComponentElement<import("react").ProviderProps<{
10
+ user: import("./types.js").AuthUser | null;
11
+ globalRoles: string[];
12
+ appRoles?: string[];
13
+ } | undefined>> | import("react").FunctionComponentElement<import("react").ProviderProps<import("./config.js").ResolvedAuthkitConfig>>;
@@ -0,0 +1,11 @@
1
+ import { createElement } from 'react';
2
+ import { AuthContext } from './provider.js';
3
+ import { AuthkitConfigContext, resolveConfig } from './config.js';
4
+ export function AuthkitProvider({ config, value, children }) {
5
+ const resolved = resolveConfig(config);
6
+ const tree = createElement(AuthkitConfigContext.Provider, { value: resolved }, children);
7
+ if (value !== undefined) {
8
+ return createElement(AuthContext.Provider, { value }, tree);
9
+ }
10
+ return tree;
11
+ }
@@ -0,0 +1,8 @@
1
+ export interface AuthorizedAppsProps {
2
+ className?: string;
3
+ revokeLabel?: string;
4
+ emptyLabel?: string;
5
+ }
6
+ export declare function AuthorizedApps({ className, revokeLabel, emptyLabel, }: AuthorizedAppsProps): import("react").DetailedReactHTMLElement<{
7
+ className: string;
8
+ }, HTMLElement>;
@@ -0,0 +1,26 @@
1
+ import { createElement } from 'react';
2
+ import { useAuthorizedApps } from '../hooks/use_authorized_apps.js';
3
+ export function AuthorizedApps({ className, revokeLabel = 'Revogar', emptyLabel = 'Nenhum app autorizado.', }) {
4
+ const { data, loading, error, actions } = useAuthorizedApps();
5
+ if (loading && !data) {
6
+ return createElement('div', { className: 'authkit-apps__loading' }, 'Carregando…');
7
+ }
8
+ if (error) {
9
+ return createElement('p', { className: 'authkit-error', role: 'alert' }, error.message);
10
+ }
11
+ const apps = data ?? [];
12
+ if (apps.length === 0) {
13
+ return createElement('p', { className: 'authkit-apps__empty' }, emptyLabel);
14
+ }
15
+ return createElement('ul', { className: ['authkit-apps', className].filter(Boolean).join(' ') }, ...apps.map((app) => createElement('li', { key: app.clientId, className: 'authkit-apps__item' }, createElement('div', { className: 'authkit-apps__info' }, app.logoUrl
16
+ ? createElement('img', {
17
+ className: 'authkit-apps__logo',
18
+ src: app.logoUrl,
19
+ alt: '',
20
+ })
21
+ : null, createElement('span', { className: 'authkit-apps__name' }, app.name ?? app.clientId)), createElement('button', {
22
+ type: 'button',
23
+ className: 'authkit-button authkit-button--danger',
24
+ onClick: () => void actions.revoke(app.clientId),
25
+ }, revokeLabel))));
26
+ }
@@ -0,0 +1,22 @@
1
+ import type { AuthUser } from '../types.js';
2
+ export interface AvatarProps {
3
+ user: Pick<AuthUser, 'name' | 'email' | 'avatarUrl'>;
4
+ size?: number;
5
+ className?: string;
6
+ }
7
+ export declare function Avatar({ user, size, className }: AvatarProps): import("react").DetailedReactHTMLElement<{
8
+ className: string;
9
+ src: string;
10
+ alt: string;
11
+ style: {
12
+ width: number;
13
+ height: number;
14
+ };
15
+ }, HTMLElement> | import("react").DetailedReactHTMLElement<{
16
+ className: string;
17
+ style: {
18
+ width: number;
19
+ height: number;
20
+ };
21
+ 'aria-hidden': true;
22
+ }, HTMLElement>;
@@ -0,0 +1,15 @@
1
+ import { createElement } from 'react';
2
+ import { deriveInitials } from '../utils.js';
3
+ export function Avatar({ user, size = 36, className }) {
4
+ const cls = ['authkit-avatar', className].filter(Boolean).join(' ');
5
+ const style = { width: size, height: size };
6
+ if (user.avatarUrl) {
7
+ return createElement('img', {
8
+ className: cls,
9
+ src: user.avatarUrl,
10
+ alt: user.name ?? user.email ?? '',
11
+ style,
12
+ });
13
+ }
14
+ return createElement('span', { className: cls, style, 'aria-hidden': true }, deriveInitials(user.name, user.email));
15
+ }
@@ -0,0 +1,8 @@
1
+ export interface OrganizationProfileProps {
2
+ inviteLabel?: string;
3
+ leaveLabel?: string;
4
+ className?: string;
5
+ }
6
+ export declare function OrganizationProfile({ inviteLabel, leaveLabel, className, }: OrganizationProfileProps): import("react").DetailedReactHTMLElement<{
7
+ className: string;
8
+ }, HTMLElement> | null;
@@ -0,0 +1,87 @@
1
+ import { createElement, useState } from 'react';
2
+ import { useOrganizations } from '../hooks/use_organizations.js';
3
+ import { useOrganization } from '../hooks/use_organization.js';
4
+ import { useAuth } from '../use_auth.js';
5
+ import { useAuthkitConfig } from '../config.js';
6
+ import { jsonRequest } from '../hooks/use_resource.js';
7
+ export function OrganizationProfile({ inviteLabel = 'Convidar membro', leaveLabel = 'Sair da organização', className, }) {
8
+ const { isAuthenticated } = useAuth();
9
+ const config = useAuthkitConfig();
10
+ const { activeOrgId, actions: orgListActions } = useOrganizations();
11
+ const { data: org, loading, error, actions } = useOrganization(activeOrgId);
12
+ const [inviteEmail, setInviteEmail] = useState('');
13
+ const [inviteRole, setInviteRole] = useState('member');
14
+ const [inviteLoading, setInviteLoading] = useState(false);
15
+ const [inviteError, setInviteError] = useState(null);
16
+ if (!isAuthenticated || !activeOrgId)
17
+ return null;
18
+ if (loading)
19
+ return createElement('div', { className: 'authkit-org-profile__loading' }, 'Carregando…');
20
+ if (error)
21
+ return createElement('div', { className: 'authkit-error' }, error.message);
22
+ if (!org)
23
+ return null;
24
+ const base = config.endpoints.orgs.replace('/json', '');
25
+ const handleInvite = async (e) => {
26
+ e.preventDefault();
27
+ if (!inviteEmail.trim())
28
+ return;
29
+ setInviteLoading(true);
30
+ setInviteError(null);
31
+ try {
32
+ await jsonRequest(`${base}/${encodeURIComponent(activeOrgId)}/invite`, {
33
+ method: 'POST',
34
+ body: JSON.stringify({ email: inviteEmail.trim(), role: inviteRole }),
35
+ csrfToken: config.csrfToken,
36
+ });
37
+ setInviteEmail('');
38
+ await actions.refetch();
39
+ }
40
+ catch (err) {
41
+ setInviteError(err);
42
+ }
43
+ finally {
44
+ setInviteLoading(false);
45
+ }
46
+ };
47
+ const handleLeave = async () => {
48
+ try {
49
+ await jsonRequest(`${base}/${encodeURIComponent(activeOrgId)}/leave`, {
50
+ method: 'POST',
51
+ csrfToken: config.csrfToken,
52
+ });
53
+ await orgListActions.refetch();
54
+ }
55
+ catch {
56
+ }
57
+ };
58
+ const memberList = createElement('div', { className: 'authkit-org-profile__members' }, createElement('h3', { className: 'authkit-org-profile__section-title' }, 'Membros'), ...(org.members.length === 0
59
+ ? [createElement('p', { className: 'authkit-org-profile__empty' }, 'Nenhum membro.')]
60
+ : org.members.map((m) => createElement('div', { key: m.accountId, className: 'authkit-org-profile__member' }, createElement('div', { className: 'authkit-org-profile__member-info' }, createElement('span', { className: 'authkit-org-profile__member-email' }, m.email ?? m.accountId), createElement('span', { className: 'authkit-org-profile__member-role' }, m.role))))));
61
+ const inviteForm = org.canManage
62
+ ? createElement('form', { className: 'authkit-org-profile__invite-form', onSubmit: handleInvite }, createElement('h3', { className: 'authkit-org-profile__section-title' }, inviteLabel), createElement('input', {
63
+ className: 'authkit-input',
64
+ type: 'email',
65
+ placeholder: 'Email',
66
+ value: inviteEmail,
67
+ onChange: (e) => setInviteEmail(e.target.value),
68
+ }), createElement('input', {
69
+ className: 'authkit-input',
70
+ placeholder: 'Papel (ex: member)',
71
+ value: inviteRole,
72
+ onChange: (e) => setInviteRole(e.target.value),
73
+ }), inviteError
74
+ ? createElement('p', { className: 'authkit-error', role: 'alert' }, inviteError.message)
75
+ : null, createElement('button', {
76
+ type: 'submit',
77
+ className: 'authkit-button authkit-button--primary',
78
+ disabled: inviteLoading,
79
+ }, inviteLoading ? 'Enviando…' : inviteLabel))
80
+ : null;
81
+ const leaveButton = createElement('button', {
82
+ type: 'button',
83
+ className: 'authkit-button authkit-button--danger',
84
+ onClick: handleLeave,
85
+ }, leaveLabel);
86
+ return createElement('div', { className: ['authkit-card', 'authkit-org-profile', className].filter(Boolean).join(' ') }, createElement('div', { className: 'authkit-org-profile__header' }, createElement('div', { className: 'authkit-org-profile__name' }, org.name), createElement('div', { className: 'authkit-org-profile__slug' }, org.slug)), memberList, inviteForm, leaveButton);
87
+ }
@@ -0,0 +1,7 @@
1
+ export interface OrganizationSwitcherProps {
2
+ personalAccountLabel?: string;
3
+ className?: string;
4
+ }
5
+ export declare function OrganizationSwitcher({ personalAccountLabel, className, }: OrganizationSwitcherProps): import("react").DetailedReactHTMLElement<{
6
+ className: string;
7
+ }, HTMLElement> | null;
@@ -0,0 +1,57 @@
1
+ import { createElement, useState } from 'react';
2
+ import { useOrganizations } from '../hooks/use_organizations.js';
3
+ import { useSwitchOrganization } from '../hooks/use_switch_organization.js';
4
+ import { useAuth } from '../use_auth.js';
5
+ export function OrganizationSwitcher({ personalAccountLabel = 'Conta pessoal', className, }) {
6
+ const { isAuthenticated } = useAuth();
7
+ const { data: orgs, activeOrgId, supported } = useOrganizations();
8
+ const { activate, deactivate, loading: switching } = useSwitchOrganization();
9
+ const [open, setOpen] = useState(false);
10
+ if (!isAuthenticated || !supported)
11
+ return null;
12
+ const activeOrg = orgs?.find((o) => o.id === activeOrgId) ?? null;
13
+ const label = activeOrg ? activeOrg.name : personalAccountLabel;
14
+ const trigger = createElement('button', {
15
+ type: 'button',
16
+ className: 'authkit-orgswitcher__trigger',
17
+ 'aria-haspopup': 'listbox',
18
+ 'aria-expanded': open,
19
+ disabled: switching,
20
+ onClick: () => setOpen((v) => !v),
21
+ }, createElement('span', { className: 'authkit-orgswitcher__label' }, label), createElement('span', { className: 'authkit-orgswitcher__chevron', 'aria-hidden': 'true' }, '▾'));
22
+ const menu = open
23
+ ? createElement('div', { className: 'authkit-orgswitcher__menu', role: 'listbox' }, createElement('button', {
24
+ type: 'button',
25
+ className: [
26
+ 'authkit-orgswitcher__item',
27
+ !activeOrgId ? 'authkit-orgswitcher__item--active' : '',
28
+ ]
29
+ .filter(Boolean)
30
+ .join(' '),
31
+ role: 'option',
32
+ 'aria-selected': !activeOrgId,
33
+ onClick: async () => {
34
+ setOpen(false);
35
+ if (activeOrgId)
36
+ await deactivate();
37
+ },
38
+ }, createElement('span', { className: 'authkit-orgswitcher__item-name' }, personalAccountLabel)), ...(orgs ?? []).map((org) => createElement('button', {
39
+ key: org.id,
40
+ type: 'button',
41
+ className: [
42
+ 'authkit-orgswitcher__item',
43
+ org.isActive ? 'authkit-orgswitcher__item--active' : '',
44
+ ]
45
+ .filter(Boolean)
46
+ .join(' '),
47
+ role: 'option',
48
+ 'aria-selected': org.isActive,
49
+ onClick: async () => {
50
+ setOpen(false);
51
+ if (!org.isActive)
52
+ await activate(org.id);
53
+ },
54
+ }, createElement('span', { className: 'authkit-orgswitcher__item-name' }, org.name), createElement('span', { className: 'authkit-orgswitcher__item-role' }, org.role))))
55
+ : null;
56
+ return createElement('div', { className: ['authkit-orgswitcher', className].filter(Boolean).join(' ') }, trigger, menu);
57
+ }
@@ -0,0 +1,11 @@
1
+ import { type PasswordScorer } from '../hooks/use_password_strength.js';
2
+ export interface PasswordStrengthMeterProps {
3
+ password: string;
4
+ scorer?: PasswordScorer;
5
+ showFeedback?: boolean;
6
+ labels?: [string, string, string, string, string];
7
+ className?: string;
8
+ }
9
+ export declare function PasswordStrengthMeter({ password, scorer, showFeedback, labels, className, }: PasswordStrengthMeterProps): import("react").DetailedReactHTMLElement<{
10
+ className: string;
11
+ }, HTMLElement>;
@@ -0,0 +1,39 @@
1
+ import { createElement } from 'react';
2
+ import { usePasswordStrength, } from '../hooks/use_password_strength.js';
3
+ const DEFAULT_LABELS = [
4
+ 'Very weak',
5
+ 'Weak',
6
+ 'Fair',
7
+ 'Good',
8
+ 'Strong',
9
+ ];
10
+ export function PasswordStrengthMeter({ password, scorer, showFeedback = true, labels = DEFAULT_LABELS, className, }) {
11
+ const { score, feedback } = usePasswordStrength(password, { scorer });
12
+ const cls = ['authkit-strength', className].filter(Boolean).join(' ');
13
+ const segments = [0, 1, 2, 3].map((i) => createElement('span', {
14
+ key: i,
15
+ className: [
16
+ 'authkit-strength__segment',
17
+ i < score ? 'authkit-strength__segment--filled' : '',
18
+ ]
19
+ .filter(Boolean)
20
+ .join(' '),
21
+ }));
22
+ const children = [
23
+ createElement('div', {
24
+ key: 'bar',
25
+ className: 'authkit-strength__bar',
26
+ role: 'meter',
27
+ 'aria-valuemin': 0,
28
+ 'aria-valuemax': 4,
29
+ 'aria-valuenow': score,
30
+ 'aria-label': labels[score],
31
+ 'data-score': score,
32
+ }, segments),
33
+ createElement('span', { key: 'label', className: 'authkit-strength__label' }, labels[score]),
34
+ ];
35
+ if (showFeedback && feedback && feedback.length > 0) {
36
+ children.push(createElement('ul', { key: 'feedback', className: 'authkit-strength__feedback' }, feedback.map((tip, i) => createElement('li', { key: i }, tip))));
37
+ }
38
+ return createElement('div', { className: cls }, children);
39
+ }