@majapisoftwares/ui 6.1.0 → 6.1.2

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 (73) hide show
  1. package/AGENTS.md +27 -27
  2. package/README.md +79 -79
  3. package/THIRD_PARTY_NOTICES.md +39 -39
  4. package/components.json +25 -25
  5. package/docs/MIGRATION-0.2.md +20 -20
  6. package/docs/MIGRATION-6.0.md +33 -33
  7. package/docs/NEXT-STARTER-VALIDATION.md +14 -14
  8. package/docs/STANDARDS.md +41 -41
  9. package/docs/VALIDATION.md +11 -11
  10. package/docs/VERSIONING.md +28 -28
  11. package/docs/validation/preference-titles.md +22 -0
  12. package/package.json +88 -84
  13. package/scripts/check-standards.mjs +41 -41
  14. package/src/components/ui/accordion.tsx +82 -82
  15. package/src/components/ui/alert-dialog.tsx +187 -187
  16. package/src/components/ui/alert.tsx +77 -77
  17. package/src/components/ui/avatar.tsx +108 -108
  18. package/src/components/ui/badge.tsx +55 -55
  19. package/src/components/ui/breadcrumb.tsx +125 -125
  20. package/src/components/ui/button-group.tsx +89 -89
  21. package/src/components/ui/button.tsx +59 -59
  22. package/src/components/ui/card.tsx +101 -101
  23. package/src/components/ui/checkbox.tsx +27 -27
  24. package/src/components/ui/collapsible.tsx +21 -21
  25. package/src/components/ui/context-menu.tsx +271 -271
  26. package/src/components/ui/dialog.tsx +161 -161
  27. package/src/components/ui/dropdown-menu.tsx +271 -271
  28. package/src/components/ui/empty.tsx +105 -105
  29. package/src/components/ui/field.tsx +238 -238
  30. package/src/components/ui/hover-card.tsx +50 -50
  31. package/src/components/ui/input-group.tsx +155 -155
  32. package/src/components/ui/input.tsx +21 -21
  33. package/src/components/ui/kbd.tsx +28 -28
  34. package/src/components/ui/label.tsx +19 -19
  35. package/src/components/ui/orb.css +1002 -1002
  36. package/src/components/ui/orb.tsx +752 -752
  37. package/src/components/ui/popover.tsx +89 -89
  38. package/src/components/ui/progress.tsx +82 -82
  39. package/src/components/ui/radio-group.tsx +37 -37
  40. package/src/components/ui/scroll-area.tsx +54 -54
  41. package/src/components/ui/select.tsx +204 -204
  42. package/src/components/ui/separator.tsx +24 -24
  43. package/src/components/ui/sheet.tsx +139 -139
  44. package/src/components/ui/sidebar.tsx +1039 -1035
  45. package/src/components/ui/skeleton.tsx +15 -15
  46. package/src/components/ui/slider.tsx +53 -53
  47. package/src/components/ui/sonner.tsx +44 -44
  48. package/src/components/ui/spinner.tsx +32 -32
  49. package/src/components/ui/switch.tsx +31 -31
  50. package/src/components/ui/table.tsx +121 -121
  51. package/src/components/ui/tabs.tsx +81 -81
  52. package/src/components/ui/textarea.tsx +19 -19
  53. package/src/components/ui/toggle-group.tsx +89 -89
  54. package/src/components/ui/toggle.tsx +44 -44
  55. package/src/components/ui/tooltip.tsx +65 -65
  56. package/src/hooks/use-mobile.ts +20 -20
  57. package/src/lib/i18n.tsx +109 -109
  58. package/src/lib/utils.ts +1 -1
  59. package/src/patterns/app-shell.tsx +177 -179
  60. package/src/patterns/data-table.tsx +2486 -2486
  61. package/src/patterns/details-sheet.tsx +54 -54
  62. package/src/patterns/filter-tabs.tsx +53 -53
  63. package/src/patterns/majapi-logo.tsx +32 -32
  64. package/src/patterns/page-header.tsx +62 -62
  65. package/src/patterns/preferences.tsx +15 -7
  66. package/src/patterns/status-badge.tsx +24 -24
  67. package/src/patterns/user-menu.tsx +218 -218
  68. package/src/patterns/workspace-switcher.tsx +176 -173
  69. package/src/styles.css +165 -165
  70. package/src/templates/admin-dashboard.tsx +44 -44
  71. package/src/templates/auth-layout.tsx +30 -30
  72. package/src/templates/login-form.tsx +129 -129
  73. package/src/templates/signup-form.tsx +177 -177
@@ -1,218 +1,218 @@
1
- "use client";
2
-
3
- import type { ReactNode } from "react";
4
- import {
5
- ChevronsUpDownIcon,
6
- LanguagesIcon,
7
- LogOutIcon,
8
- MoonIcon,
9
- SunIcon,
10
- } from "lucide-react";
11
- import { Avatar, AvatarFallback, AvatarImage } from "../components/ui/avatar";
12
- import {
13
- DropdownMenu,
14
- DropdownMenuContent,
15
- DropdownMenuGroup,
16
- DropdownMenuItem,
17
- DropdownMenuLabel,
18
- DropdownMenuRadioGroup,
19
- DropdownMenuRadioItem,
20
- DropdownMenuSeparator,
21
- DropdownMenuSub,
22
- DropdownMenuSubContent,
23
- DropdownMenuSubTrigger,
24
- DropdownMenuTrigger,
25
- } from "../components/ui/dropdown-menu";
26
- import {
27
- SidebarMenu,
28
- SidebarMenuButton,
29
- SidebarMenuItem,
30
- useSidebar,
31
- } from "../components/ui/sidebar";
32
- import { defineMessages, locales, useMessages, type Locale } from "../lib/i18n";
33
- import { usePreferences } from "./preferences";
34
-
35
- const messages = defineMessages({
36
- en: {
37
- account: "Account menu",
38
- theme: "Theme",
39
- light: "Light",
40
- dark: "Dark",
41
- language: "Language",
42
- signOut: "Sign out",
43
- signingOut: "Signing out…",
44
- },
45
- "pt-BR": {
46
- account: "Menu da conta",
47
- theme: "Tema",
48
- light: "Claro",
49
- dark: "Escuro",
50
- language: "Idioma",
51
- signOut: "Sair",
52
- signingOut: "Saindo…",
53
- },
54
- });
55
-
56
- const localeNames: Record<Locale, string> = {
57
- en: "English",
58
- "pt-BR": "Português",
59
- };
60
-
61
- function initials(name: string) {
62
- return name
63
- .split(/\s+/)
64
- .filter(Boolean)
65
- .slice(0, 2)
66
- .map((part) => part.charAt(0).toUpperCase())
67
- .join("");
68
- }
69
-
70
- function Identity({
71
- name,
72
- email,
73
- avatarUrl,
74
- }: {
75
- name: string;
76
- email?: string;
77
- avatarUrl?: string;
78
- }) {
79
- return (
80
- <>
81
- <Avatar className="size-8">
82
- {avatarUrl ? <AvatarImage src={avatarUrl} alt="" /> : null}
83
- <AvatarFallback>{initials(name)}</AvatarFallback>
84
- </Avatar>
85
- <div className="grid flex-1 text-left text-sm leading-tight">
86
- <span className="truncate font-medium">{name}</span>
87
- {email ? (
88
- <span className="truncate text-xs text-muted-foreground">
89
- {email}
90
- </span>
91
- ) : null}
92
- </div>
93
- </>
94
- );
95
- }
96
-
97
- /**
98
- * Sidebar account menu (place it in `AppShell` `footer`). Theme and language
99
- * come from `Preferences`; account actions are passed as `items`.
100
- */
101
- export function UserMenu({
102
- name,
103
- email,
104
- avatarUrl,
105
- items,
106
- onSignOut,
107
- signingOut = false,
108
- }: {
109
- name: string;
110
- email?: string;
111
- avatarUrl?: string;
112
- /** App-specific entries, e.g. profile or settings links. */
113
- items?: ReactNode;
114
- onSignOut?: () => void;
115
- signingOut?: boolean;
116
- }) {
117
- const t = useMessages(messages);
118
- const { isMobile } = useSidebar();
119
- const { locale, setLocale, theme, setTheme } = usePreferences();
120
-
121
- return (
122
- <SidebarMenu>
123
- <SidebarMenuItem>
124
- <DropdownMenu>
125
- <DropdownMenuTrigger
126
- render={
127
- <SidebarMenuButton
128
- size="lg"
129
- aria-label={t.account}
130
- className="data-popup-open:bg-sidebar-accent data-popup-open:text-sidebar-accent-foreground"
131
- />
132
- }
133
- >
134
- <Identity name={name} email={email} avatarUrl={avatarUrl} />
135
- <ChevronsUpDownIcon className="ml-auto size-4 text-muted-foreground" />
136
- </DropdownMenuTrigger>
137
- <DropdownMenuContent
138
- className="w-(--anchor-width) min-w-60"
139
- side={isMobile ? "bottom" : "right"}
140
- align="end"
141
- sideOffset={4}
142
- >
143
- <DropdownMenuGroup>
144
- <DropdownMenuLabel className="flex items-center gap-2 font-normal text-foreground">
145
- <Identity name={name} email={email} avatarUrl={avatarUrl} />
146
- </DropdownMenuLabel>
147
- </DropdownMenuGroup>
148
- {items ? (
149
- <>
150
- <DropdownMenuSeparator />
151
- <DropdownMenuGroup>{items}</DropdownMenuGroup>
152
- </>
153
- ) : null}
154
- <DropdownMenuSeparator />
155
- <DropdownMenuGroup>
156
- <DropdownMenuSub>
157
- <DropdownMenuSubTrigger>
158
- {theme === "dark" ? <MoonIcon /> : <SunIcon />}
159
- {t.theme}
160
- </DropdownMenuSubTrigger>
161
- <DropdownMenuSubContent>
162
- <DropdownMenuRadioGroup
163
- value={theme}
164
- onValueChange={(value) =>
165
- setTheme(value as "light" | "dark")
166
- }
167
- >
168
- <DropdownMenuRadioItem value="light">
169
- <SunIcon />
170
- {t.light}
171
- </DropdownMenuRadioItem>
172
- <DropdownMenuRadioItem value="dark">
173
- <MoonIcon />
174
- {t.dark}
175
- </DropdownMenuRadioItem>
176
- </DropdownMenuRadioGroup>
177
- </DropdownMenuSubContent>
178
- </DropdownMenuSub>
179
- <DropdownMenuSub>
180
- <DropdownMenuSubTrigger>
181
- <LanguagesIcon />
182
- {t.language}
183
- </DropdownMenuSubTrigger>
184
- <DropdownMenuSubContent>
185
- <DropdownMenuRadioGroup
186
- value={locale}
187
- onValueChange={(value) => setLocale(value as Locale)}
188
- >
189
- {locales.map((value) => (
190
- <DropdownMenuRadioItem key={value} value={value}>
191
- {localeNames[value]}
192
- </DropdownMenuRadioItem>
193
- ))}
194
- </DropdownMenuRadioGroup>
195
- </DropdownMenuSubContent>
196
- </DropdownMenuSub>
197
- </DropdownMenuGroup>
198
- {onSignOut ? (
199
- <>
200
- <DropdownMenuSeparator />
201
- <DropdownMenuGroup>
202
- <DropdownMenuItem
203
- variant="destructive"
204
- disabled={signingOut}
205
- onClick={onSignOut}
206
- >
207
- <LogOutIcon />
208
- {signingOut ? t.signingOut : t.signOut}
209
- </DropdownMenuItem>
210
- </DropdownMenuGroup>
211
- </>
212
- ) : null}
213
- </DropdownMenuContent>
214
- </DropdownMenu>
215
- </SidebarMenuItem>
216
- </SidebarMenu>
217
- );
218
- }
1
+ "use client";
2
+
3
+ import type { ReactNode } from "react";
4
+ import {
5
+ ChevronsUpDownIcon,
6
+ LanguagesIcon,
7
+ LogOutIcon,
8
+ MoonIcon,
9
+ SunIcon,
10
+ } from "lucide-react";
11
+ import { Avatar, AvatarFallback, AvatarImage } from "../components/ui/avatar";
12
+ import {
13
+ DropdownMenu,
14
+ DropdownMenuContent,
15
+ DropdownMenuGroup,
16
+ DropdownMenuItem,
17
+ DropdownMenuLabel,
18
+ DropdownMenuRadioGroup,
19
+ DropdownMenuRadioItem,
20
+ DropdownMenuSeparator,
21
+ DropdownMenuSub,
22
+ DropdownMenuSubContent,
23
+ DropdownMenuSubTrigger,
24
+ DropdownMenuTrigger,
25
+ } from "../components/ui/dropdown-menu";
26
+ import {
27
+ SidebarMenu,
28
+ SidebarMenuButton,
29
+ SidebarMenuItem,
30
+ useSidebar,
31
+ } from "../components/ui/sidebar";
32
+ import { defineMessages, locales, useMessages, type Locale } from "../lib/i18n";
33
+ import { usePreferences } from "./preferences";
34
+
35
+ const messages = defineMessages({
36
+ en: {
37
+ account: "Account menu",
38
+ theme: "Theme",
39
+ light: "Light",
40
+ dark: "Dark",
41
+ language: "Language",
42
+ signOut: "Sign out",
43
+ signingOut: "Signing out…",
44
+ },
45
+ "pt-BR": {
46
+ account: "Menu da conta",
47
+ theme: "Tema",
48
+ light: "Claro",
49
+ dark: "Escuro",
50
+ language: "Idioma",
51
+ signOut: "Sair",
52
+ signingOut: "Saindo…",
53
+ },
54
+ });
55
+
56
+ const localeNames: Record<Locale, string> = {
57
+ en: "English",
58
+ "pt-BR": "Português",
59
+ };
60
+
61
+ function initials(name: string) {
62
+ return name
63
+ .split(/\s+/)
64
+ .filter(Boolean)
65
+ .slice(0, 2)
66
+ .map((part) => part.charAt(0).toUpperCase())
67
+ .join("");
68
+ }
69
+
70
+ function Identity({
71
+ name,
72
+ email,
73
+ avatarUrl,
74
+ }: {
75
+ name: string;
76
+ email?: string;
77
+ avatarUrl?: string;
78
+ }) {
79
+ return (
80
+ <>
81
+ <Avatar className="size-8">
82
+ {avatarUrl ? <AvatarImage src={avatarUrl} alt="" /> : null}
83
+ <AvatarFallback>{initials(name)}</AvatarFallback>
84
+ </Avatar>
85
+ <div className="grid flex-1 text-left text-sm leading-tight">
86
+ <span className="truncate font-medium">{name}</span>
87
+ {email ? (
88
+ <span className="truncate text-xs text-muted-foreground">
89
+ {email}
90
+ </span>
91
+ ) : null}
92
+ </div>
93
+ </>
94
+ );
95
+ }
96
+
97
+ /**
98
+ * Sidebar account menu (place it in `AppShell` `footer`). Theme and language
99
+ * come from `Preferences`; account actions are passed as `items`.
100
+ */
101
+ export function UserMenu({
102
+ name,
103
+ email,
104
+ avatarUrl,
105
+ items,
106
+ onSignOut,
107
+ signingOut = false,
108
+ }: {
109
+ name: string;
110
+ email?: string;
111
+ avatarUrl?: string;
112
+ /** App-specific entries, e.g. profile or settings links. */
113
+ items?: ReactNode;
114
+ onSignOut?: () => void;
115
+ signingOut?: boolean;
116
+ }) {
117
+ const t = useMessages(messages);
118
+ const { isMobile } = useSidebar();
119
+ const { locale, setLocale, theme, setTheme } = usePreferences();
120
+
121
+ return (
122
+ <SidebarMenu>
123
+ <SidebarMenuItem>
124
+ <DropdownMenu>
125
+ <DropdownMenuTrigger
126
+ render={
127
+ <SidebarMenuButton
128
+ size="lg"
129
+ aria-label={t.account}
130
+ className="data-popup-open:bg-sidebar-accent data-popup-open:text-sidebar-accent-foreground"
131
+ />
132
+ }
133
+ >
134
+ <Identity name={name} email={email} avatarUrl={avatarUrl} />
135
+ <ChevronsUpDownIcon className="ml-auto size-4 text-muted-foreground" />
136
+ </DropdownMenuTrigger>
137
+ <DropdownMenuContent
138
+ className="w-(--anchor-width) min-w-60"
139
+ side={isMobile ? "bottom" : "right"}
140
+ align="end"
141
+ sideOffset={4}
142
+ >
143
+ <DropdownMenuGroup>
144
+ <DropdownMenuLabel className="flex items-center gap-2 font-normal text-foreground">
145
+ <Identity name={name} email={email} avatarUrl={avatarUrl} />
146
+ </DropdownMenuLabel>
147
+ </DropdownMenuGroup>
148
+ {items ? (
149
+ <>
150
+ <DropdownMenuSeparator />
151
+ <DropdownMenuGroup>{items}</DropdownMenuGroup>
152
+ </>
153
+ ) : null}
154
+ <DropdownMenuSeparator />
155
+ <DropdownMenuGroup>
156
+ <DropdownMenuSub>
157
+ <DropdownMenuSubTrigger>
158
+ {theme === "dark" ? <MoonIcon /> : <SunIcon />}
159
+ {t.theme}
160
+ </DropdownMenuSubTrigger>
161
+ <DropdownMenuSubContent>
162
+ <DropdownMenuRadioGroup
163
+ value={theme}
164
+ onValueChange={(value) =>
165
+ setTheme(value as "light" | "dark")
166
+ }
167
+ >
168
+ <DropdownMenuRadioItem value="light">
169
+ <SunIcon />
170
+ {t.light}
171
+ </DropdownMenuRadioItem>
172
+ <DropdownMenuRadioItem value="dark">
173
+ <MoonIcon />
174
+ {t.dark}
175
+ </DropdownMenuRadioItem>
176
+ </DropdownMenuRadioGroup>
177
+ </DropdownMenuSubContent>
178
+ </DropdownMenuSub>
179
+ <DropdownMenuSub>
180
+ <DropdownMenuSubTrigger>
181
+ <LanguagesIcon />
182
+ {t.language}
183
+ </DropdownMenuSubTrigger>
184
+ <DropdownMenuSubContent>
185
+ <DropdownMenuRadioGroup
186
+ value={locale}
187
+ onValueChange={(value) => setLocale(value as Locale)}
188
+ >
189
+ {locales.map((value) => (
190
+ <DropdownMenuRadioItem key={value} value={value}>
191
+ {localeNames[value]}
192
+ </DropdownMenuRadioItem>
193
+ ))}
194
+ </DropdownMenuRadioGroup>
195
+ </DropdownMenuSubContent>
196
+ </DropdownMenuSub>
197
+ </DropdownMenuGroup>
198
+ {onSignOut ? (
199
+ <>
200
+ <DropdownMenuSeparator />
201
+ <DropdownMenuGroup>
202
+ <DropdownMenuItem
203
+ variant="destructive"
204
+ disabled={signingOut}
205
+ onClick={onSignOut}
206
+ >
207
+ <LogOutIcon />
208
+ {signingOut ? t.signingOut : t.signOut}
209
+ </DropdownMenuItem>
210
+ </DropdownMenuGroup>
211
+ </>
212
+ ) : null}
213
+ </DropdownMenuContent>
214
+ </DropdownMenu>
215
+ </SidebarMenuItem>
216
+ </SidebarMenu>
217
+ );
218
+ }