@djangocfg/layouts 2.1.426 → 2.1.428

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 (77) hide show
  1. package/README.md +29 -21
  2. package/package.json +15 -17
  3. package/src/components/errors/ErrorsTracker/components/ErrorToast.tsx +19 -0
  4. package/src/components/errors/ErrorsTracker/utils/curl-generator.ts +24 -10
  5. package/src/components/errors/README.md +63 -0
  6. package/src/layouts/AppLayout/BaseApp.tsx +36 -52
  7. package/src/layouts/AppLayout/README.md +79 -64
  8. package/src/layouts/AppLayout/index.ts +12 -19
  9. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupLoading.tsx +6 -4
  10. package/src/layouts/PrivateLayout/PrivateLayout.tsx +7 -4
  11. package/src/layouts/PrivateLayout/README.md +30 -0
  12. package/src/layouts/PrivateLayout/components/PrivateContent.tsx +6 -2
  13. package/src/layouts/PrivateLayout/components/PrivateSidebarAccount.tsx +105 -70
  14. package/src/layouts/PrivateLayout/hooks/useAuthGuard.ts +12 -3
  15. package/src/layouts/PrivateLayout/types.ts +8 -3
  16. package/src/layouts/PublicLayout/components/UserMenu.tsx +68 -113
  17. package/src/layouts/PublicLayout/navbars/MinimalNavbar/MinimalNavbar.tsx +0 -6
  18. package/src/layouts/PublicLayout/navbars/MinimalNavbar/index.ts +1 -1
  19. package/src/layouts/SettingsLayout/README.md +258 -0
  20. package/src/layouts/SettingsLayout/SettingsDialog.tsx +101 -0
  21. package/src/layouts/SettingsLayout/SettingsForm.tsx +100 -0
  22. package/src/layouts/SettingsLayout/components/ApiKeySection/ApiKeySection.tsx +192 -0
  23. package/src/layouts/SettingsLayout/components/SettingsNav.tsx +71 -0
  24. package/src/layouts/SettingsLayout/components/SettingsNavItem.tsx +57 -0
  25. package/src/layouts/SettingsLayout/components/SettingsPanel.tsx +48 -0
  26. package/src/layouts/SettingsLayout/components/SettingsSearch.tsx +50 -0
  27. package/src/layouts/SettingsLayout/components/SettingsShell.tsx +77 -0
  28. package/src/layouts/SettingsLayout/components/SettingsTabs.tsx +56 -0
  29. package/src/layouts/{ProfileLayout → SettingsLayout}/components/TwoFactorSection/TwoFactorSection.tsx +84 -130
  30. package/src/layouts/SettingsLayout/components/index.ts +6 -0
  31. package/src/layouts/SettingsLayout/context/SettingsContext.tsx +122 -0
  32. package/src/layouts/SettingsLayout/context/index.ts +2 -0
  33. package/src/layouts/SettingsLayout/hooks/index.ts +12 -0
  34. package/src/layouts/SettingsLayout/hooks/useProfileSave.ts +95 -0
  35. package/src/layouts/SettingsLayout/hooks/useSettingsDialog.ts +52 -0
  36. package/src/layouts/SettingsLayout/hooks/useSettingsSections.ts +123 -0
  37. package/src/layouts/SettingsLayout/hooks/useSettingsUrl.ts +140 -0
  38. package/src/layouts/SettingsLayout/index.ts +67 -0
  39. package/src/layouts/SettingsLayout/sections/AccountSection.tsx +100 -0
  40. package/src/layouts/SettingsLayout/sections/ApiKeysSection.tsx +15 -0
  41. package/src/layouts/SettingsLayout/sections/DeleteAccountRow.tsx +57 -0
  42. package/src/layouts/SettingsLayout/sections/PreferencesRows.tsx +43 -0
  43. package/src/layouts/SettingsLayout/sections/SecuritySection.tsx +15 -0
  44. package/src/layouts/SettingsLayout/sections/builtins.tsx +77 -0
  45. package/src/layouts/SettingsLayout/sections/index.ts +8 -0
  46. package/src/layouts/SettingsLayout/store.ts +47 -0
  47. package/src/layouts/SettingsLayout/types.ts +107 -0
  48. package/src/layouts/index.ts +1 -2
  49. package/src/layouts/types/index.ts +0 -1
  50. package/src/layouts/types/layout.types.ts +0 -4
  51. package/src/utils/logger.ts +9 -4
  52. package/src/layouts/AdminLayout/AdminLayout.tsx +0 -57
  53. package/src/layouts/AdminLayout/index.ts +0 -7
  54. package/src/layouts/AppLayout/AppLayout.tsx +0 -520
  55. package/src/layouts/ProfileLayout/ProfileDialog/ProfileDialog.tsx +0 -56
  56. package/src/layouts/ProfileLayout/ProfileDialog/index.ts +0 -4
  57. package/src/layouts/ProfileLayout/ProfileDialog/store.ts +0 -51
  58. package/src/layouts/ProfileLayout/ProfileForm/context.tsx +0 -123
  59. package/src/layouts/ProfileLayout/ProfileForm/index.tsx +0 -147
  60. package/src/layouts/ProfileLayout/README.md +0 -150
  61. package/src/layouts/ProfileLayout/components/ActionButton.tsx +0 -38
  62. package/src/layouts/ProfileLayout/components/ApiKeySection/ApiKeySection.tsx +0 -197
  63. package/src/layouts/ProfileLayout/components/DeleteAccountSection.tsx +0 -44
  64. package/src/layouts/ProfileLayout/components/EditableField.tsx +0 -128
  65. package/src/layouts/ProfileLayout/components/PreferencesSection.tsx +0 -56
  66. package/src/layouts/ProfileLayout/components/ProfileHeader.tsx +0 -110
  67. package/src/layouts/ProfileLayout/components/ProfileTab.tsx +0 -35
  68. package/src/layouts/ProfileLayout/components/Section.tsx +0 -22
  69. package/src/layouts/ProfileLayout/components/index.ts +0 -11
  70. package/src/layouts/ProfileLayout/hooks/index.ts +0 -2
  71. package/src/layouts/ProfileLayout/hooks/useProfileTabs.ts +0 -56
  72. package/src/layouts/ProfileLayout/index.ts +0 -8
  73. package/src/layouts/ProfileLayout/types.ts +0 -48
  74. /package/src/layouts/{ProfileLayout → SettingsLayout}/components/ApiKeySection/context.tsx +0 -0
  75. /package/src/layouts/{ProfileLayout → SettingsLayout}/components/ApiKeySection/index.ts +0 -0
  76. /package/src/layouts/{ProfileLayout → SettingsLayout}/components/AvatarSection.tsx +0 -0
  77. /package/src/layouts/{ProfileLayout → SettingsLayout}/components/TwoFactorSection/index.ts +0 -0
@@ -1,44 +0,0 @@
1
- 'use client';
2
-
3
- import { Trash2 } from 'lucide-react';
4
- import React from 'react';
5
-
6
- import { useAuth, useDeleteAccount } from '@djangocfg/api/auth';
7
- import { useAppT } from '@djangocfg/i18n';
8
-
9
- import { ActionButton } from './ActionButton';
10
-
11
- export const DeleteAccountSection: React.FC = () => {
12
- const { logout } = useAuth();
13
- const { deleteAccount } = useDeleteAccount();
14
- const t = useAppT();
15
-
16
- const confirmationWord = t('layouts.profilePage.confirmationWord');
17
-
18
- const handleClick = async () => {
19
- const value = await window.dialog.prompt({
20
- title: t('layouts.profilePage.deleteAccountTitle'),
21
- message: t('layouts.profilePage.deleteAccountDesc'),
22
- placeholder: confirmationWord,
23
- confirmText: t('layouts.profilePage.deleteAccount'),
24
- cancelText: t('layouts.profilePage.cancel'),
25
- variant: 'destructive',
26
- });
27
-
28
- if (value?.toUpperCase() !== confirmationWord.toUpperCase()) return;
29
-
30
- const result = await deleteAccount();
31
- if (result.success) logout();
32
- };
33
-
34
- return (
35
- <ActionButton
36
- icon={<Trash2 className="w-4 h-4 text-destructive" />}
37
- label={<span className="text-destructive">{t('layouts.profilePage.deleteAccount')}</span>}
38
- onClick={handleClick}
39
- />
40
- );
41
- };
42
-
43
- // Keep export so nothing breaks — no longer used but exported for backwards compat
44
- export const DeleteAccountScreen: React.FC = () => null;
@@ -1,128 +0,0 @@
1
- 'use client';
2
-
3
- import React, { useEffect, useState } from 'react';
4
- import { parsePhoneNumberFromString } from 'libphonenumber-js';
5
-
6
- import { Button, Input, PhoneInput } from '@djangocfg/ui-core/components';
7
- import { toast } from '@djangocfg/ui-core/hooks';
8
- import { cn } from '@djangocfg/ui-core/lib';
9
-
10
- import { useProfileContext } from '../ProfileForm/context';
11
-
12
- function formatPhone(raw: string): string {
13
- if (!raw) return '';
14
- try {
15
- return parsePhoneNumberFromString(raw)?.formatInternational() ?? raw;
16
- } catch {
17
- return raw;
18
- }
19
- }
20
-
21
- interface EditableFieldProps {
22
- label: string;
23
- value: string;
24
- placeholder: string;
25
- onSave: (value: string) => Promise<void>;
26
- disabled?: boolean;
27
- type?: 'text' | 'phone';
28
- }
29
-
30
- export const EditableField = ({
31
- label,
32
- value,
33
- placeholder,
34
- onSave,
35
- disabled,
36
- type = 'text',
37
- }: EditableFieldProps) => {
38
- const { labels } = useProfileContext();
39
- const [isEditing, setIsEditing] = useState(false);
40
- const [editValue, setEditValue] = useState(value);
41
- const [isSaving, setIsSaving] = useState(false);
42
-
43
- useEffect(() => {
44
- setEditValue(value);
45
- }, [value]);
46
-
47
- const handleSave = async () => {
48
- if (editValue === value) {
49
- setIsEditing(false);
50
- return;
51
- }
52
- setIsSaving(true);
53
- try {
54
- await onSave(editValue);
55
- setIsEditing(false);
56
- } catch {
57
- // Keep editing mode open with the entered value so the user can retry.
58
- toast.error(labels.failedToUpdate);
59
- } finally {
60
- setIsSaving(false);
61
- }
62
- };
63
-
64
- const handleCancel = () => {
65
- setEditValue(value);
66
- setIsEditing(false);
67
- };
68
-
69
- const handleKeyDown = (e: React.KeyboardEvent) => {
70
- if (e.key === 'Enter') handleSave();
71
- else if (e.key === 'Escape') handleCancel();
72
- };
73
-
74
- if (isEditing) {
75
- return (
76
- <div className="py-4 border-b border-border/50 last:border-0">
77
- <label className="block text-[13px] text-muted-foreground mb-1.5">{label}</label>
78
- {type === 'phone' ? (
79
- <div className="space-y-2">
80
- <PhoneInput
81
- value={editValue}
82
- onChange={(val) => setEditValue(val ?? '')}
83
- placeholder={placeholder}
84
- disabled={isSaving}
85
- />
86
- <div className="flex gap-2">
87
- <Button size="sm" onClick={handleSave} disabled={isSaving}>
88
- {isSaving ? labels.saving : labels.save}
89
- </Button>
90
- <Button size="sm" variant="ghost" onClick={handleCancel} disabled={isSaving}>
91
- {labels.cancel}
92
- </Button>
93
- </div>
94
- </div>
95
- ) : (
96
- <Input
97
- value={editValue}
98
- onChange={(e) => setEditValue(e.target.value)}
99
- onKeyDown={handleKeyDown}
100
- onBlur={handleSave}
101
- placeholder={placeholder}
102
- autoFocus
103
- disabled={isSaving}
104
- className="h-9 text-[15px]"
105
- />
106
- )}
107
- </div>
108
- );
109
- }
110
-
111
- return (
112
- <button
113
- type="button"
114
- onClick={() => !disabled && setIsEditing(true)}
115
- disabled={disabled}
116
- className={cn(
117
- 'w-full py-4 border-b border-border/50 last:border-0 text-left',
118
- 'transition-colors hover:bg-muted/30',
119
- disabled && 'cursor-default hover:bg-transparent'
120
- )}
121
- >
122
- <div className="text-[13px] text-muted-foreground mb-0.5">{label}</div>
123
- <div className={cn('text-[15px]', value ? 'text-foreground' : 'text-muted-foreground/60')}>
124
- {value ? (type === 'phone' ? formatPhone(value) : value) : placeholder}
125
- </div>
126
- </button>
127
- );
128
- };
@@ -1,56 +0,0 @@
1
- /**
2
- * Preferences Section
3
- *
4
- * Language + theme controls for ProfileForm.
5
- * Uses ThemeToggle from ui-nextjs and LocaleSwitcherDropdown from _components.
6
- */
7
-
8
- 'use client';
9
-
10
- import React from 'react';
11
-
12
- import { ThemeToggle } from '@djangocfg/ui-core/theme';
13
- import { cn } from '@djangocfg/ui-core/lib';
14
-
15
- import { LocaleSwitcherDropdown } from '../../_components/locale-switcher';
16
- import { useLayoutI18nOptional } from '../../AppLayout/LayoutI18nProvider';
17
-
18
- interface PreferencesSectionProps {
19
- /** Extra className for the root. */
20
- className?: string;
21
- }
22
-
23
- export const PreferencesSection: React.FC<PreferencesSectionProps> = ({
24
- className,
25
- }) => {
26
- const layoutI18n = useLayoutI18nOptional();
27
-
28
- return (
29
- <div className={cn('py-0', className)}>
30
- {layoutI18n && (
31
- <>
32
- <div className="flex items-center justify-between py-3">
33
- <span className="text-sm">Language</span>
34
- <LocaleSwitcherDropdown
35
- locale={layoutI18n.locale}
36
- locales={layoutI18n.locales}
37
- onChange={layoutI18n.onLocaleChange}
38
- variant="outline"
39
- size="sm"
40
- showCode
41
- showIcon={false}
42
- showFlag
43
- showTriggerLabel
44
- />
45
- </div>
46
- <div className="h-px bg-border/60" />
47
- </>
48
- )}
49
-
50
- <div className="flex items-center justify-between py-3">
51
- <span className="text-sm">Theme</span>
52
- <ThemeToggle size="default" />
53
- </div>
54
- </div>
55
- );
56
- };
@@ -1,110 +0,0 @@
1
- 'use client';
2
-
3
- import { LogOut, MoreHorizontal, Trash2 } from 'lucide-react';
4
- import moment from 'moment';
5
- import React, { useCallback } from 'react';
6
-
7
- import { useAuth, useDeleteAccount } from '@djangocfg/api/auth';
8
- import { useAppT } from '@djangocfg/i18n';
9
- import {
10
- Button,
11
- DropdownMenu,
12
- DropdownMenuContent,
13
- DropdownMenuItem,
14
- DropdownMenuSeparator,
15
- DropdownMenuTrigger,
16
- } from '@djangocfg/ui-core/components';
17
-
18
- import { AvatarSection } from './AvatarSection';
19
- import { useProfileContext } from '../ProfileForm/context';
20
- import type { ProfileSlots } from '../types';
21
-
22
- interface ProfileHeaderProps {
23
- slots?: ProfileSlots;
24
- enableDeleteAccount?: boolean;
25
- }
26
-
27
- export const ProfileHeader: React.FC<ProfileHeaderProps> = ({ slots, enableDeleteAccount }) => {
28
- const { labels, onLogout } = useProfileContext();
29
- const { user, logout } = useAuth();
30
- const { deleteAccount } = useDeleteAccount();
31
- const t = useAppT();
32
-
33
- const handleDeleteAccount = useCallback(async () => {
34
- const confirmationWord = t('layouts.profilePage.confirmationWord');
35
- const value = await window.dialog.prompt({
36
- title: t('layouts.profilePage.deleteAccountTitle'),
37
- message: t('layouts.profilePage.deleteAccountDesc'),
38
- placeholder: confirmationWord,
39
- confirmText: t('layouts.profilePage.deleteAccount'),
40
- cancelText: t('layouts.profilePage.cancel'),
41
- variant: 'destructive',
42
- });
43
- if (value?.toUpperCase() !== confirmationWord.toUpperCase()) return;
44
- const result = await deleteAccount();
45
- if (result.success) logout();
46
- }, [t, deleteAccount, logout]);
47
-
48
- if (!user) return null;
49
-
50
- const displayName = user.full_name || user.display_username || user.email;
51
- const memberSince = user.date_joined
52
- ? moment.utc(user.date_joined).local().format('MMMM YYYY')
53
- : null;
54
-
55
- const badge = slots?.headerBadge ?? null;
56
- const menuItems = slots?.headerMenuItems ?? null;
57
- const headerAfter = slots?.headerAfter ?? null;
58
-
59
- return (
60
- <div className="pb-4 md:pb-6 border-b mb-2">
61
- <div className="flex items-center gap-3 md:gap-4">
62
- <AvatarSection />
63
-
64
- <div className="flex-1 min-w-0">
65
- <div className="flex items-center gap-2 flex-wrap">
66
- <h1 className="text-lg md:text-xl font-semibold truncate">{displayName}</h1>
67
- {badge}
68
- </div>
69
- <p className="text-sm text-muted-foreground truncate">{user.email}</p>
70
- {memberSince && (
71
- <p className="text-xs text-muted-foreground/60 mt-0.5">
72
- Member since {memberSince}
73
- </p>
74
- )}
75
- </div>
76
-
77
- <DropdownMenu>
78
- <DropdownMenuTrigger asChild>
79
- <Button variant="ghost" size="icon" className="flex-shrink-0 rounded-full">
80
- <MoreHorizontal className="w-4 h-4" />
81
- </Button>
82
- </DropdownMenuTrigger>
83
- <DropdownMenuContent align="end" className="w-48">
84
- <DropdownMenuItem onClick={onLogout} className="gap-2">
85
- <LogOut className="w-4 h-4" />
86
- {labels.signOut}
87
- </DropdownMenuItem>
88
-
89
- {menuItems && <><DropdownMenuSeparator />{menuItems}</>}
90
-
91
- {enableDeleteAccount && (
92
- <>
93
- <DropdownMenuSeparator />
94
- <DropdownMenuItem
95
- onClick={handleDeleteAccount}
96
- className="gap-2 text-destructive focus:text-destructive"
97
- >
98
- <Trash2 className="w-4 h-4" />
99
- {labels.deleteAccount}
100
- </DropdownMenuItem>
101
- </>
102
- )}
103
- </DropdownMenuContent>
104
- </DropdownMenu>
105
- </div>
106
-
107
- {headerAfter && <div className="mt-4">{headerAfter}</div>}
108
- </div>
109
- );
110
- };
@@ -1,35 +0,0 @@
1
- 'use client';
2
-
3
- import React from 'react';
4
-
5
- import { useAuth } from '@djangocfg/api/auth';
6
-
7
- import { EditableField, PreferencesSection, Section } from '.';
8
- import { useProfileContext } from '../ProfileForm/context';
9
-
10
- export const ProfileTab: React.FC = () => {
11
- const { labels, onFieldSave } = useProfileContext();
12
- const { user } = useAuth();
13
- if (!user) return null;
14
-
15
- return (
16
- <div className="space-y-6 pt-4">
17
- <div className="grid grid-cols-1 md:grid-cols-2 gap-3 md:gap-6">
18
- <Section title={labels.personalInfo}>
19
- <EditableField label={labels.firstName} value={user.first_name || ''} placeholder={labels.addFirstName} onSave={(v) => onFieldSave('first_name', v)} />
20
- <EditableField label={labels.lastName} value={user.last_name || ''} placeholder={labels.addLastName} onSave={(v) => onFieldSave('last_name', v)} />
21
- <EditableField label={labels.phone} value={user.phone || ''} placeholder={labels.addPhone} onSave={(v) => onFieldSave('phone', v)} type="phone" />
22
- </Section>
23
-
24
- <Section title={labels.work}>
25
- <EditableField label={labels.company} value={user.company || ''} placeholder={labels.addCompany} onSave={(v) => onFieldSave('company', v)} />
26
- <EditableField label={labels.position} value={user.position || ''} placeholder={labels.addPosition} onSave={(v) => onFieldSave('position', v)} />
27
- </Section>
28
- </div>
29
-
30
- <Section title={labels.preferences ?? 'Preferences'}>
31
- <PreferencesSection />
32
- </Section>
33
- </div>
34
- );
35
- };
@@ -1,22 +0,0 @@
1
- 'use client';
2
-
3
- import React from 'react';
4
-
5
- import { cn } from '@djangocfg/ui-core/lib';
6
-
7
- interface SectionProps {
8
- title?: string;
9
- children: React.ReactNode;
10
- className?: string;
11
- }
12
-
13
- export const Section = ({ title, children, className }: SectionProps) => (
14
- <div className={cn('mb-4 md:mb-6', className)}>
15
- {title && (
16
- <h2 className="text-[11px] font-medium text-muted-foreground uppercase tracking-wider mb-2 px-1">
17
- {title}
18
- </h2>
19
- )}
20
- <div className="bg-card rounded-xl px-4">{children}</div>
21
- </div>
22
- );
@@ -1,11 +0,0 @@
1
- export { ActionButton } from './ActionButton';
2
- export { ApiKeySection, ApiKeyProvider, useApiKeyContext } from './ApiKeySection';
3
- export type { ApiKeyLabels } from './ApiKeySection';
4
- export { AvatarSection } from './AvatarSection';
5
- export { DeleteAccountSection, DeleteAccountScreen } from './DeleteAccountSection';
6
- export { EditableField } from './EditableField';
7
- export { PreferencesSection } from './PreferencesSection';
8
- export { ProfileHeader } from './ProfileHeader';
9
- export { ProfileTab } from './ProfileTab';
10
- export { Section } from './Section';
11
- export { TwoFactorSection } from './TwoFactorSection';
@@ -1,2 +0,0 @@
1
- export { useProfileTabs } from './useProfileTabs';
2
- export type { ProfileTabValue, ProfileTabValueOrCustom, UseProfileTabsOptions } from './useProfileTabs';
@@ -1,56 +0,0 @@
1
- 'use client';
2
-
3
- import { useMemo, useState, useCallback } from 'react';
4
-
5
- /** Built-in tab values. */
6
- export type ProfileTabValue = 'profile' | 'security' | 'api-keys';
7
-
8
- /**
9
- * Any tab value: a built-in one, or a custom tab's `value` string.
10
- * `(string & {})` keeps the built-in literals as autocomplete hints while
11
- * still accepting arbitrary strings (custom tabs added via `tabs`).
12
- */
13
- export type ProfileTabValueOrCustom = ProfileTabValue | (string & {});
14
-
15
- export interface UseProfileTabsOptions {
16
- enable2FA?: boolean;
17
- enableAPIKeys?: boolean;
18
- extraTabValues?: string[];
19
- /** Initial active tab. Defaults to `'profile'`. Accepts custom tab values. */
20
- defaultTab?: ProfileTabValueOrCustom;
21
- }
22
-
23
- /**
24
- * Manages the active profile tab with local React state.
25
- *
26
- * Falls back to `'profile'` when `defaultTab` is missing or not allowed.
27
- *
28
- * @example
29
- * const { tab, setTab, allowed } = useProfileTabs({ enable2FA: true, defaultTab: 'security' });
30
- * <Tabs value={tab} onValueChange={setTab}>...</Tabs>
31
- */
32
- export function useProfileTabs(options: UseProfileTabsOptions = {}) {
33
- const { enable2FA, enableAPIKeys, extraTabValues = [], defaultTab } = options;
34
-
35
- const allowed = useMemo(() => {
36
- const base: ProfileTabValueOrCustom[] = ['profile'];
37
- if (enable2FA) base.push('security');
38
- if (enableAPIKeys) base.push('api-keys');
39
- return [...base, ...extraTabValues];
40
- }, [enable2FA, enableAPIKeys, extraTabValues]);
41
-
42
- const [tab, setTabState] = useState<ProfileTabValueOrCustom>(
43
- defaultTab && allowed.includes(defaultTab) ? defaultTab : 'profile',
44
- );
45
-
46
- const setTab = useCallback(
47
- (value: ProfileTabValueOrCustom) => {
48
- if (allowed.includes(value)) {
49
- setTabState(value);
50
- }
51
- },
52
- [allowed],
53
- );
54
-
55
- return { tab, setTab, allowed };
56
- }
@@ -1,8 +0,0 @@
1
- export { ProfileForm, useProfileContext } from './ProfileForm';
2
- export { ProfileProvider } from './ProfileForm/context';
3
- export { useProfileTabs } from './hooks';
4
- export { ProfileDialog, useProfileDialogStore } from './ProfileDialog';
5
- export type { ProfileDialogProps, ProfileDialogContent } from './ProfileDialog';
6
- export type { ProfileLabels } from './ProfileForm/context';
7
- export type { ProfileFormProps, ProfileLayoutProps, ProfileTab, ProfileSlots } from './types';
8
- export type { ProfileTabValue, ProfileTabValueOrCustom, UseProfileTabsOptions } from './hooks';
@@ -1,48 +0,0 @@
1
- import React from 'react';
2
-
3
- import type { ProfileTabValueOrCustom } from './hooks/useProfileTabs';
4
-
5
- // ─────────────────────────────────────────────────────────────────────────────
6
- // Slot + Tab types
7
- // ─────────────────────────────────────────────────────────────────────────────
8
-
9
- export interface ProfileTab {
10
- /** Unique key, used as Tabs value */
11
- value: string;
12
- /** Trigger label */
13
- label: React.ReactNode;
14
- /** Tab panel content */
15
- content: React.ReactNode;
16
- }
17
-
18
- export interface ProfileSlots {
19
- /** Extra items inside the ⋯ dropdown, above the separator before Delete */
20
- headerMenuItems?: React.ReactNode;
21
- /** Rendered next to the user name (e.g. plan badge, role chip) */
22
- headerBadge?: React.ReactNode;
23
- /** Rendered below the avatar row, above the tabs */
24
- headerAfter?: React.ReactNode;
25
- /** Rendered below all tab content */
26
- footer?: React.ReactNode;
27
- }
28
-
29
- export interface ProfileFormProps {
30
- onUnauthenticated?: () => void;
31
- title?: string;
32
- enable2FA?: boolean;
33
- enableAPIKeys?: boolean;
34
- enableDeleteAccount?: boolean;
35
- /** Extra tabs appended after built-in Profile / Security / API Keys tabs */
36
- tabs?: ProfileTab[];
37
- /** Named slots for additional content */
38
- slots?: ProfileSlots;
39
- /**
40
- * When provided, the active tab is controlled locally (no URL sync).
41
- * Useful for dialogs where query-string pollution is undesirable.
42
- * Accepts a built-in value or a custom tab's `value`.
43
- */
44
- defaultTab?: ProfileTabValueOrCustom;
45
- }
46
-
47
- /** @deprecated Use ProfileFormProps instead */
48
- export type ProfileLayoutProps = ProfileFormProps;