create-astram-app 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +211 -38
- package/dist/add-frontend.js.map +1 -1
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/template/README.md +51 -20
- package/template/frontend/README.md +21 -11
- package/template/frontend/index.html +16 -0
- package/template/frontend/package.json +1 -1
- package/template/frontend/src/App.jsx +82 -20
- package/template/frontend/src/auth/AuthContext.jsx +139 -21
- package/template/frontend/src/auth/routeGate.js +31 -0
- package/template/frontend/src/auth/routeGate.test.mjs +59 -0
- package/template/frontend/src/auth/sessionFlow.js +27 -0
- package/template/frontend/src/auth/sessionFlow.test.mjs +63 -0
- package/template/frontend/src/components/EntityList.jsx +1 -7
- package/template/frontend/src/components/PageHeader.jsx +5 -4
- package/template/frontend/src/components/ShareDialog.jsx +3 -5
- package/template/frontend/src/components/access/CollapsibleGroup.jsx +4 -1
- package/template/frontend/src/components/ui/alert-dialog.tsx +27 -50
- package/template/frontend/src/components/ui/alert.tsx +17 -23
- package/template/frontend/src/components/ui/avatar.tsx +8 -20
- package/template/frontend/src/components/ui/badge.tsx +17 -26
- package/template/frontend/src/components/ui/button.tsx +22 -24
- package/template/frontend/src/components/ui/card.tsx +19 -36
- package/template/frontend/src/components/ui/checkbox.tsx +7 -10
- package/template/frontend/src/components/ui/date-field.tsx +26 -27
- package/template/frontend/src/components/ui/dialog.tsx +24 -40
- package/template/frontend/src/components/ui/dropdown-menu.tsx +25 -54
- package/template/frontend/src/components/ui/input-otp.tsx +1 -4
- package/template/frontend/src/components/ui/label.tsx +10 -12
- package/template/frontend/src/components/ui/searchable-select.tsx +1 -3
- package/template/frontend/src/components/ui/select.tsx +31 -43
- package/template/frontend/src/components/ui/separator.tsx +6 -6
- package/template/frontend/src/components/ui/sheet.tsx +29 -38
- package/template/frontend/src/components/ui/skeleton.tsx +3 -3
- package/template/frontend/src/components/ui/sonner.tsx +7 -7
- package/template/frontend/src/components/ui/table.tsx +56 -70
- package/template/frontend/src/components/ui/tooltip.tsx +7 -11
- package/template/frontend/src/config/branding.js +1 -4
- package/template/frontend/src/hooks/useMobile.tsx +4 -6
- package/template/frontend/src/index.css +5 -2
- package/template/frontend/src/pages/Dashboard.jsx +13 -7
- package/template/frontend/src/pages/ForgotPassword.jsx +9 -2
- package/template/frontend/src/pages/Login.jsx +85 -70
- package/template/frontend/src/pages/ResetPassword.jsx +9 -2
- package/template/frontend/src/pages/access/AccessForm.jsx +49 -15
- package/template/frontend/src/pages/access/AccessPage.jsx +10 -6
- package/template/frontend/src/pages/access/RecordPoliciesPage.jsx +9 -2
- package/template/frontend/src/pages/account/AccountLayout.jsx +11 -6
- package/template/frontend/src/pages/account/ChangePasswordPage.jsx +2 -2
- package/template/frontend/src/pages/account/ReenrollPage.jsx +3 -5
- package/template/frontend/src/pages/account/TwoFactorPage.jsx +3 -8
- package/template/frontend/src/pages/companies/CompaniesPage.jsx +7 -9
- package/template/frontend/src/pages/cross-tenant/GrantForm.jsx +41 -8
- package/template/frontend/src/pages/cross-tenant/GrantsPage.jsx +30 -7
- package/template/frontend/src/pages/cross-tenant/InboxPage.jsx +12 -3
- package/template/frontend/src/pages/roles/RolesPage.jsx +5 -9
- package/template/frontend/src/pages/service-accounts/ServiceAccountsPage.jsx +77 -18
- package/template/frontend/src/pages/service-accounts/accessModel.js +22 -0
- package/template/frontend/src/pages/service-accounts/accessModel.test.mjs +28 -0
- package/template/frontend/src/pages/users/MembershipCard.jsx +3 -1
- package/template/frontend/src/pages/users/PostingRow.jsx +8 -14
- package/template/frontend/src/pages/users/UsersPage.jsx +7 -9
- package/template/frontend/src/platform/httpClient.js +5 -0
- package/template/frontend/src/platform/sessionStore.js +55 -13
- package/template/frontend/src/platform/sessionStore.test.mjs +89 -0
- package/template/frontend/src/platform/shieldTransport.js +6 -0
- package/template/frontend/src/platform/shieldTransport.test.mjs +84 -5
- package/template/frontend/src/shell/AppShell.jsx +10 -12
- package/template/frontend/src/shell/Sidebar.jsx +15 -3
- package/template/frontend/src/shell/nav.js +1 -3
- package/template/frontend/vite.config.js +19 -1
- package/template/server/_env.example +22 -1
- package/template/server/eslint.config.mjs +194 -0
- package/template/server/package.json +11 -11
- package/template/server/scripts/dev.mjs +17 -6
- package/template/server/scripts/sync-astram-guide.mjs +45 -19
- package/template/server/src/app.module.ts +11 -5
- package/template/server/src/health/demo.controller.ts +16 -12
- package/template/server/src/main.ts +23 -1
- package/template/server/eslint.config.js +0 -95
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as React from
|
|
1
|
+
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import { cn } from
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* DateField — a styled `<input type="date">` wrapper matching the shadcn `Input`
|
|
@@ -18,30 +18,29 @@ import { cn } from "@/lib/utils";
|
|
|
18
18
|
* React 18.3: `React.forwardRef` so a forwarded ref reaches the underlying
|
|
19
19
|
* `<input>` (form libraries / focus management) and never warns.
|
|
20
20
|
*/
|
|
21
|
-
const DateField = React.forwardRef<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
DateField.displayName = "DateField";
|
|
21
|
+
const DateField = React.forwardRef<HTMLInputElement, React.ComponentPropsWithoutRef<'input'>>(
|
|
22
|
+
({ className, type = 'date', ...props }, ref) => {
|
|
23
|
+
return (
|
|
24
|
+
<input
|
|
25
|
+
ref={ref}
|
|
26
|
+
type={type}
|
|
27
|
+
data-slot="date-field"
|
|
28
|
+
className={cn(
|
|
29
|
+
'border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none tabular-nums md:text-sm',
|
|
30
|
+
'placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground',
|
|
31
|
+
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
|
32
|
+
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
|
33
|
+
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
|
34
|
+
// The native calendar-picker glyph: tint to the muted ink, brighten on
|
|
35
|
+
// hover, and invert in dark mode so it stays visible on the dark field.
|
|
36
|
+
'[&::-webkit-calendar-picker-indicator]:cursor-pointer [&::-webkit-calendar-picker-indicator]:opacity-60 [&::-webkit-calendar-picker-indicator]:hover:opacity-100 dark:[&::-webkit-calendar-picker-indicator]:invert',
|
|
37
|
+
className,
|
|
38
|
+
)}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
DateField.displayName = 'DateField';
|
|
46
45
|
|
|
47
46
|
export { DateField };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { cn } from
|
|
2
|
-
import * as DialogPrimitive from
|
|
3
|
-
import { XIcon } from
|
|
4
|
-
import * as React from
|
|
1
|
+
import { cn } from '@/lib/utils';
|
|
2
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
3
|
+
import { XIcon } from 'lucide-react';
|
|
4
|
+
import * as React from 'react';
|
|
5
5
|
|
|
6
6
|
// Context to track composition state across dialog children
|
|
7
7
|
const DialogCompositionContext = React.createContext<{
|
|
@@ -16,12 +16,9 @@ const DialogCompositionContext = React.createContext<{
|
|
|
16
16
|
markCompositionEnd: () => {},
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
export const useDialogComposition = () =>
|
|
20
|
-
React.useContext(DialogCompositionContext);
|
|
19
|
+
export const useDialogComposition = () => React.useContext(DialogCompositionContext);
|
|
21
20
|
|
|
22
|
-
function Dialog({
|
|
23
|
-
...props
|
|
24
|
-
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
21
|
+
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
25
22
|
const composingRef = React.useRef(false);
|
|
26
23
|
const justEndedRef = React.useRef(false);
|
|
27
24
|
const endTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
@@ -43,7 +40,7 @@ function Dialog({
|
|
|
43
40
|
}, 150);
|
|
44
41
|
},
|
|
45
42
|
}),
|
|
46
|
-
[]
|
|
43
|
+
[],
|
|
47
44
|
);
|
|
48
45
|
|
|
49
46
|
return (
|
|
@@ -53,21 +50,15 @@ function Dialog({
|
|
|
53
50
|
);
|
|
54
51
|
}
|
|
55
52
|
|
|
56
|
-
function DialogTrigger({
|
|
57
|
-
...props
|
|
58
|
-
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
53
|
+
function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
59
54
|
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
60
55
|
}
|
|
61
56
|
|
|
62
|
-
function DialogPortal({
|
|
63
|
-
...props
|
|
64
|
-
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
57
|
+
function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
65
58
|
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
|
66
59
|
}
|
|
67
60
|
|
|
68
|
-
function DialogClose({
|
|
69
|
-
...props
|
|
70
|
-
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
61
|
+
function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
71
62
|
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
|
72
63
|
}
|
|
73
64
|
|
|
@@ -84,15 +75,15 @@ const DialogOverlay = React.forwardRef<
|
|
|
84
75
|
ref={ref}
|
|
85
76
|
data-slot="dialog-overlay"
|
|
86
77
|
className={cn(
|
|
87
|
-
|
|
88
|
-
className
|
|
78
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
|
|
79
|
+
className,
|
|
89
80
|
)}
|
|
90
81
|
{...props}
|
|
91
82
|
/>
|
|
92
83
|
);
|
|
93
84
|
});
|
|
94
85
|
|
|
95
|
-
DialogOverlay.displayName =
|
|
86
|
+
DialogOverlay.displayName = 'DialogOverlay';
|
|
96
87
|
|
|
97
88
|
function DialogContent({
|
|
98
89
|
className,
|
|
@@ -120,7 +111,7 @@ function DialogContent({
|
|
|
120
111
|
// Call user's onEscapeKeyDown if provided
|
|
121
112
|
onEscapeKeyDown?.(e);
|
|
122
113
|
},
|
|
123
|
-
[isComposing, onEscapeKeyDown]
|
|
114
|
+
[isComposing, onEscapeKeyDown],
|
|
124
115
|
);
|
|
125
116
|
|
|
126
117
|
return (
|
|
@@ -129,8 +120,8 @@ function DialogContent({
|
|
|
129
120
|
<DialogPrimitive.Content
|
|
130
121
|
data-slot="dialog-content"
|
|
131
122
|
className={cn(
|
|
132
|
-
|
|
133
|
-
className
|
|
123
|
+
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100vw-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
|
|
124
|
+
className,
|
|
134
125
|
)}
|
|
135
126
|
onEscapeKeyDown={handleEscapeKeyDown}
|
|
136
127
|
{...props}
|
|
@@ -150,37 +141,31 @@ function DialogContent({
|
|
|
150
141
|
);
|
|
151
142
|
}
|
|
152
143
|
|
|
153
|
-
function DialogHeader({ className, ...props }: React.ComponentProps<
|
|
144
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
154
145
|
return (
|
|
155
146
|
<div
|
|
156
147
|
data-slot="dialog-header"
|
|
157
|
-
className={cn(
|
|
148
|
+
className={cn('flex flex-col gap-2 text-center sm:text-left', className)}
|
|
158
149
|
{...props}
|
|
159
150
|
/>
|
|
160
151
|
);
|
|
161
152
|
}
|
|
162
153
|
|
|
163
|
-
function DialogFooter({ className, ...props }: React.ComponentProps<
|
|
154
|
+
function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
164
155
|
return (
|
|
165
156
|
<div
|
|
166
157
|
data-slot="dialog-footer"
|
|
167
|
-
className={cn(
|
|
168
|
-
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
169
|
-
className
|
|
170
|
-
)}
|
|
158
|
+
className={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
|
|
171
159
|
{...props}
|
|
172
160
|
/>
|
|
173
161
|
);
|
|
174
162
|
}
|
|
175
163
|
|
|
176
|
-
function DialogTitle({
|
|
177
|
-
className,
|
|
178
|
-
...props
|
|
179
|
-
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
164
|
+
function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
180
165
|
return (
|
|
181
166
|
<DialogPrimitive.Title
|
|
182
167
|
data-slot="dialog-title"
|
|
183
|
-
className={cn(
|
|
168
|
+
className={cn('text-lg leading-none font-semibold', className)}
|
|
184
169
|
{...props}
|
|
185
170
|
/>
|
|
186
171
|
);
|
|
@@ -193,7 +178,7 @@ function DialogDescription({
|
|
|
193
178
|
return (
|
|
194
179
|
<DialogPrimitive.Description
|
|
195
180
|
data-slot="dialog-description"
|
|
196
|
-
className={cn(
|
|
181
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
197
182
|
{...props}
|
|
198
183
|
/>
|
|
199
184
|
);
|
|
@@ -209,6 +194,5 @@ export {
|
|
|
209
194
|
DialogOverlay,
|
|
210
195
|
DialogPortal,
|
|
211
196
|
DialogTitle,
|
|
212
|
-
DialogTrigger
|
|
197
|
+
DialogTrigger,
|
|
213
198
|
};
|
|
214
|
-
|
|
@@ -1,32 +1,23 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import * as DropdownMenuPrimitive from
|
|
3
|
-
import { CheckIcon, ChevronRightIcon, CircleIcon } from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
3
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
|
|
4
4
|
|
|
5
|
-
import { cn } from
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
6
|
|
|
7
|
-
function DropdownMenu({
|
|
8
|
-
...props
|
|
9
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
7
|
+
function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
10
8
|
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
function DropdownMenuPortal({
|
|
14
12
|
...props
|
|
15
13
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
16
|
-
return
|
|
17
|
-
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
18
|
-
);
|
|
14
|
+
return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;
|
|
19
15
|
}
|
|
20
16
|
|
|
21
17
|
function DropdownMenuTrigger({
|
|
22
18
|
...props
|
|
23
19
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
24
|
-
return
|
|
25
|
-
<DropdownMenuPrimitive.Trigger
|
|
26
|
-
data-slot="dropdown-menu-trigger"
|
|
27
|
-
{...props}
|
|
28
|
-
/>
|
|
29
|
-
);
|
|
20
|
+
return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;
|
|
30
21
|
}
|
|
31
22
|
|
|
32
23
|
function DropdownMenuContent({
|
|
@@ -40,8 +31,8 @@ function DropdownMenuContent({
|
|
|
40
31
|
data-slot="dropdown-menu-content"
|
|
41
32
|
sideOffset={sideOffset}
|
|
42
33
|
className={cn(
|
|
43
|
-
|
|
44
|
-
className
|
|
34
|
+
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
|
|
35
|
+
className,
|
|
45
36
|
)}
|
|
46
37
|
{...props}
|
|
47
38
|
/>
|
|
@@ -49,22 +40,18 @@ function DropdownMenuContent({
|
|
|
49
40
|
);
|
|
50
41
|
}
|
|
51
42
|
|
|
52
|
-
function DropdownMenuGroup({
|
|
53
|
-
...props
|
|
54
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
55
|
-
return (
|
|
56
|
-
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
57
|
-
);
|
|
43
|
+
function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
44
|
+
return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
|
|
58
45
|
}
|
|
59
46
|
|
|
60
47
|
function DropdownMenuItem({
|
|
61
48
|
className,
|
|
62
49
|
inset,
|
|
63
|
-
variant =
|
|
50
|
+
variant = 'default',
|
|
64
51
|
...props
|
|
65
52
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
66
53
|
inset?: boolean;
|
|
67
|
-
variant?:
|
|
54
|
+
variant?: 'default' | 'destructive';
|
|
68
55
|
}) {
|
|
69
56
|
return (
|
|
70
57
|
<DropdownMenuPrimitive.Item
|
|
@@ -73,7 +60,7 @@ function DropdownMenuItem({
|
|
|
73
60
|
data-variant={variant}
|
|
74
61
|
className={cn(
|
|
75
62
|
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
76
|
-
className
|
|
63
|
+
className,
|
|
77
64
|
)}
|
|
78
65
|
{...props}
|
|
79
66
|
/>
|
|
@@ -91,7 +78,7 @@ function DropdownMenuCheckboxItem({
|
|
|
91
78
|
data-slot="dropdown-menu-checkbox-item"
|
|
92
79
|
className={cn(
|
|
93
80
|
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
94
|
-
className
|
|
81
|
+
className,
|
|
95
82
|
)}
|
|
96
83
|
checked={checked}
|
|
97
84
|
{...props}
|
|
@@ -109,12 +96,7 @@ function DropdownMenuCheckboxItem({
|
|
|
109
96
|
function DropdownMenuRadioGroup({
|
|
110
97
|
...props
|
|
111
98
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
112
|
-
return
|
|
113
|
-
<DropdownMenuPrimitive.RadioGroup
|
|
114
|
-
data-slot="dropdown-menu-radio-group"
|
|
115
|
-
{...props}
|
|
116
|
-
/>
|
|
117
|
-
);
|
|
99
|
+
return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />;
|
|
118
100
|
}
|
|
119
101
|
|
|
120
102
|
function DropdownMenuRadioItem({
|
|
@@ -127,7 +109,7 @@ function DropdownMenuRadioItem({
|
|
|
127
109
|
data-slot="dropdown-menu-radio-item"
|
|
128
110
|
className={cn(
|
|
129
111
|
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
130
|
-
className
|
|
112
|
+
className,
|
|
131
113
|
)}
|
|
132
114
|
{...props}
|
|
133
115
|
>
|
|
@@ -152,10 +134,7 @@ function DropdownMenuLabel({
|
|
|
152
134
|
<DropdownMenuPrimitive.Label
|
|
153
135
|
data-slot="dropdown-menu-label"
|
|
154
136
|
data-inset={inset}
|
|
155
|
-
className={cn(
|
|
156
|
-
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
|
157
|
-
className
|
|
158
|
-
)}
|
|
137
|
+
className={cn('px-2 py-1.5 text-sm font-medium data-[inset]:pl-8', className)}
|
|
159
138
|
{...props}
|
|
160
139
|
/>
|
|
161
140
|
);
|
|
@@ -168,31 +147,23 @@ function DropdownMenuSeparator({
|
|
|
168
147
|
return (
|
|
169
148
|
<DropdownMenuPrimitive.Separator
|
|
170
149
|
data-slot="dropdown-menu-separator"
|
|
171
|
-
className={cn(
|
|
150
|
+
className={cn('bg-border -mx-1 my-1 h-px', className)}
|
|
172
151
|
{...props}
|
|
173
152
|
/>
|
|
174
153
|
);
|
|
175
154
|
}
|
|
176
155
|
|
|
177
|
-
function DropdownMenuShortcut({
|
|
178
|
-
className,
|
|
179
|
-
...props
|
|
180
|
-
}: React.ComponentProps<"span">) {
|
|
156
|
+
function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {
|
|
181
157
|
return (
|
|
182
158
|
<span
|
|
183
159
|
data-slot="dropdown-menu-shortcut"
|
|
184
|
-
className={cn(
|
|
185
|
-
"text-muted-foreground ml-auto text-xs tracking-widest",
|
|
186
|
-
className
|
|
187
|
-
)}
|
|
160
|
+
className={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
|
|
188
161
|
{...props}
|
|
189
162
|
/>
|
|
190
163
|
);
|
|
191
164
|
}
|
|
192
165
|
|
|
193
|
-
function DropdownMenuSub({
|
|
194
|
-
...props
|
|
195
|
-
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
166
|
+
function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
196
167
|
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
|
197
168
|
}
|
|
198
169
|
|
|
@@ -210,7 +181,7 @@ function DropdownMenuSubTrigger({
|
|
|
210
181
|
data-inset={inset}
|
|
211
182
|
className={cn(
|
|
212
183
|
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
213
|
-
className
|
|
184
|
+
className,
|
|
214
185
|
)}
|
|
215
186
|
{...props}
|
|
216
187
|
>
|
|
@@ -228,8 +199,8 @@ function DropdownMenuSubContent({
|
|
|
228
199
|
<DropdownMenuPrimitive.SubContent
|
|
229
200
|
data-slot="dropdown-menu-sub-content"
|
|
230
201
|
className={cn(
|
|
231
|
-
|
|
232
|
-
className
|
|
202
|
+
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
|
|
203
|
+
className,
|
|
233
204
|
)}
|
|
234
205
|
{...props}
|
|
235
206
|
/>
|
|
@@ -16,10 +16,7 @@ const InputOTP = React.forwardRef<
|
|
|
16
16
|
<OTPInput
|
|
17
17
|
ref={ref}
|
|
18
18
|
data-slot="input-otp"
|
|
19
|
-
containerClassName={cn(
|
|
20
|
-
'flex items-center gap-2 has-disabled:opacity-50',
|
|
21
|
-
containerClassName,
|
|
22
|
-
)}
|
|
19
|
+
containerClassName={cn('flex items-center gap-2 has-disabled:opacity-50', containerClassName)}
|
|
23
20
|
className={cn('disabled:cursor-not-allowed', className)}
|
|
24
21
|
{...props}
|
|
25
22
|
/>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import * as LabelPrimitive from
|
|
3
|
-
import { cva, type VariantProps } from
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
|
-
import { cn } from
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Label — default is the standard shadcn label (existing callers unchanged).
|
|
@@ -13,27 +13,25 @@ import { cn } from "@/lib/utils";
|
|
|
13
13
|
* the OCA-crisp field labels.
|
|
14
14
|
*/
|
|
15
15
|
const labelVariants = cva(
|
|
16
|
-
|
|
16
|
+
'flex items-center gap-2 leading-none select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
|
|
17
17
|
{
|
|
18
18
|
variants: {
|
|
19
19
|
variant: {
|
|
20
|
-
default:
|
|
21
|
-
field:
|
|
22
|
-
"font-mono text-[0.72rem] font-semibold tracking-[0.08em] uppercase text-primary",
|
|
20
|
+
default: 'text-sm font-medium',
|
|
21
|
+
field: 'font-mono text-[0.72rem] font-semibold tracking-[0.08em] uppercase text-primary',
|
|
23
22
|
},
|
|
24
23
|
},
|
|
25
24
|
defaultVariants: {
|
|
26
|
-
variant:
|
|
25
|
+
variant: 'default',
|
|
27
26
|
},
|
|
28
|
-
}
|
|
27
|
+
},
|
|
29
28
|
);
|
|
30
29
|
|
|
31
30
|
function Label({
|
|
32
31
|
className,
|
|
33
32
|
variant,
|
|
34
33
|
...props
|
|
35
|
-
}: React.ComponentProps<typeof LabelPrimitive.Root> &
|
|
36
|
-
VariantProps<typeof labelVariants>) {
|
|
34
|
+
}: React.ComponentProps<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>) {
|
|
37
35
|
return (
|
|
38
36
|
<LabelPrimitive.Root
|
|
39
37
|
data-slot="label"
|
|
@@ -413,9 +413,7 @@ export function SearchableSelect({
|
|
|
413
413
|
)}
|
|
414
414
|
>
|
|
415
415
|
<span className="line-clamp-1">{opt.label}</span>
|
|
416
|
-
{selected &&
|
|
417
|
-
<Check className="absolute right-2 size-4 shrink-0" />
|
|
418
|
-
)}
|
|
416
|
+
{selected && <Check className="absolute right-2 size-4 shrink-0" />}
|
|
419
417
|
</div>
|
|
420
418
|
);
|
|
421
419
|
})
|