@salesforce/webapp-template-app-react-sample-b2e-experimental 1.49.0 → 1.50.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 (58) hide show
  1. package/dist/CHANGELOG.md +8 -0
  2. package/dist/force-app/main/default/data/Property__c.json +2 -2
  3. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/dashboard.ts +170 -0
  4. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/maintenance.ts +221 -0
  5. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/properties.ts +157 -0
  6. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/api/utils.ts +4 -0
  7. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/appLayout.tsx +20 -8
  8. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/appliances.svg +13 -0
  9. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/dashboard.svg +4 -0
  10. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/downgraph.svg +3 -0
  11. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/electrical.svg +41 -0
  12. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/files.svg +7 -0
  13. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/hvac.svg +79 -0
  14. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/maintenance.svg +4 -0
  15. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/pest.svg +5 -0
  16. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/plumbing.svg +7 -0
  17. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/properties.svg +14 -0
  18. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/support.svg +6 -0
  19. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/upgraph.svg +3 -0
  20. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/users.svg +8 -0
  21. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/assets/icons/zen-logo.svg +5 -0
  22. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/AnalyticsTile.tsx +29 -0
  23. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ApplicationCard.tsx +43 -0
  24. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/IssuesDonutChart.tsx +66 -0
  25. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/MaintenanceRequestCard.tsx +71 -0
  26. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/MaintenanceTable.tsx +110 -0
  27. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/PriorityBadge.tsx +29 -0
  28. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/PropertyCard.tsx +61 -0
  29. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/StatCard.tsx +52 -0
  30. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/StatusBadge.tsx +37 -0
  31. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/TopBar.tsx +72 -0
  32. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/UserAvatar.tsx +35 -0
  33. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/VerticalNav.tsx +54 -0
  34. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/alert.tsx +69 -0
  35. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/button.tsx +67 -0
  36. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/card.tsx +92 -0
  37. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/dialog.tsx +143 -0
  38. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/field.tsx +222 -0
  39. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/index.ts +72 -0
  40. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/input.tsx +19 -0
  41. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/label.tsx +19 -0
  42. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/pagination.tsx +112 -0
  43. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/select.tsx +183 -0
  44. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/separator.tsx +26 -0
  45. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/skeleton.tsx +14 -0
  46. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/spinner.tsx +15 -0
  47. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/table.tsx +87 -0
  48. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components/ui/tabs.tsx +78 -0
  49. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/components.json +18 -0
  50. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/lib/types.ts +57 -0
  51. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/lib/utils.ts +6 -0
  52. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Home.tsx +163 -10
  53. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Maintenance.tsx +176 -0
  54. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/pages/Properties.tsx +94 -0
  55. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/routes.tsx +19 -7
  56. package/dist/force-app/main/default/webapplications/appreactsampleb2e/src/styles/global.css +160 -0
  57. package/dist/package.json +1 -1
  58. package/package.json +2 -2
@@ -0,0 +1,222 @@
1
+ import { useMemo } from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+
4
+ import { cn } from "../../lib/utils";
5
+ import { Label } from "./label";
6
+ import { Separator } from "./separator";
7
+
8
+ function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
9
+ return (
10
+ <fieldset
11
+ data-slot="field-set"
12
+ className={cn(
13
+ "gap-4 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3 flex flex-col",
14
+ className,
15
+ )}
16
+ {...props}
17
+ />
18
+ );
19
+ }
20
+
21
+ function FieldLegend({
22
+ className,
23
+ variant = "legend",
24
+ ...props
25
+ }: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) {
26
+ return (
27
+ <legend
28
+ data-slot="field-legend"
29
+ data-variant={variant}
30
+ className={cn(
31
+ "mb-1.5 font-medium data-[variant=label]:text-sm data-[variant=legend]:text-base",
32
+ className,
33
+ )}
34
+ {...props}
35
+ />
36
+ );
37
+ }
38
+
39
+ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
40
+ return (
41
+ <div
42
+ data-slot="field-group"
43
+ className={cn(
44
+ "gap-5 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4 group/field-group @container/field-group flex w-full flex-col",
45
+ className,
46
+ )}
47
+ {...props}
48
+ />
49
+ );
50
+ }
51
+
52
+ const fieldVariants = cva("data-[invalid=true]:text-destructive gap-2 group/field flex w-full", {
53
+ variants: {
54
+ orientation: {
55
+ vertical: "flex-col *:w-full [&>.sr-only]:w-auto",
56
+ horizontal:
57
+ "flex-row items-center *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
58
+ responsive:
59
+ "flex-col *:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:*:data-[slot=field-label]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
60
+ },
61
+ },
62
+ defaultVariants: {
63
+ orientation: "vertical",
64
+ },
65
+ });
66
+
67
+ function Field({
68
+ className,
69
+ orientation = "vertical",
70
+ ...props
71
+ }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) {
72
+ return (
73
+ <div
74
+ role="group"
75
+ data-slot="field"
76
+ data-orientation={orientation}
77
+ className={cn(fieldVariants({ orientation }), className)}
78
+ {...props}
79
+ />
80
+ );
81
+ }
82
+
83
+ function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
84
+ return (
85
+ <div
86
+ data-slot="field-content"
87
+ className={cn("gap-0.5 group/field-content flex flex-1 flex-col leading-snug", className)}
88
+ {...props}
89
+ />
90
+ );
91
+ }
92
+
93
+ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>) {
94
+ return (
95
+ <Label
96
+ data-slot="field-label"
97
+ className={cn(
98
+ "has-data-checked:bg-primary/5 has-data-checked:border-primary/30 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10 gap-2 group-data-[disabled=true]/field:opacity-50 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border *:data-[slot=field]:p-2.5 group/field-label peer/field-label flex w-fit leading-snug",
99
+ "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col",
100
+ className,
101
+ )}
102
+ {...props}
103
+ />
104
+ );
105
+ }
106
+
107
+ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
108
+ return (
109
+ <div
110
+ data-slot="field-label"
111
+ className={cn(
112
+ "gap-2 text-sm font-medium group-data-[disabled=true]/field:opacity-50 flex w-fit items-center leading-snug",
113
+ className,
114
+ )}
115
+ {...props}
116
+ />
117
+ );
118
+ }
119
+
120
+ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
121
+ return (
122
+ <p
123
+ data-slot="field-description"
124
+ className={cn(
125
+ "text-muted-foreground text-left text-sm [[data-variant=legend]+&]:-mt-1.5 leading-normal font-normal group-has-data-horizontal/field:text-balance",
126
+ "last:mt-0 nth-last-2:-mt-1",
127
+ "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
128
+ className,
129
+ )}
130
+ {...props}
131
+ />
132
+ );
133
+ }
134
+
135
+ function FieldSeparator({
136
+ children,
137
+ className,
138
+ ...props
139
+ }: React.ComponentProps<"div"> & {
140
+ children?: React.ReactNode;
141
+ }) {
142
+ return (
143
+ <div
144
+ data-slot="field-separator"
145
+ data-content={!!children}
146
+ className={cn(
147
+ "-my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2 relative",
148
+ className,
149
+ )}
150
+ {...props}
151
+ >
152
+ <Separator className="absolute inset-0 top-1/2" />
153
+ {children && (
154
+ <span
155
+ className="text-muted-foreground px-2 bg-background relative mx-auto block w-fit"
156
+ data-slot="field-separator-content"
157
+ >
158
+ {children}
159
+ </span>
160
+ )}
161
+ </div>
162
+ );
163
+ }
164
+
165
+ function FieldError({
166
+ className,
167
+ children,
168
+ errors,
169
+ ...props
170
+ }: React.ComponentProps<"div"> & {
171
+ errors?: Array<{ message?: string } | undefined>;
172
+ }) {
173
+ const content = useMemo(() => {
174
+ if (children) {
175
+ return children;
176
+ }
177
+
178
+ if (!errors?.length) {
179
+ return null;
180
+ }
181
+
182
+ const uniqueErrors = [...new Map(errors.map((error) => [error?.message, error])).values()];
183
+
184
+ if (uniqueErrors?.length == 1) {
185
+ return uniqueErrors[0]?.message;
186
+ }
187
+
188
+ return (
189
+ <ul className="ml-4 flex list-disc flex-col gap-1">
190
+ {uniqueErrors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)}
191
+ </ul>
192
+ );
193
+ }, [children, errors]);
194
+
195
+ if (!content) {
196
+ return null;
197
+ }
198
+
199
+ return (
200
+ <div
201
+ role="alert"
202
+ data-slot="field-error"
203
+ className={cn("text-destructive text-sm font-normal", className)}
204
+ {...props}
205
+ >
206
+ {content}
207
+ </div>
208
+ );
209
+ }
210
+
211
+ export {
212
+ Field,
213
+ FieldLabel,
214
+ FieldDescription,
215
+ FieldError,
216
+ FieldGroup,
217
+ FieldLegend,
218
+ FieldSeparator,
219
+ FieldSet,
220
+ FieldContent,
221
+ FieldTitle,
222
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * UI Components Index
3
+ *
4
+ * Re-exports all UI components for easier imports.
5
+ *
6
+ * Usage:
7
+ * import { Button, Input, Tabs } from "@/components/ui"
8
+ *
9
+ * Instead of:
10
+ * import { Button } from "@/components/ui/button"
11
+ * import { Input } from "@/components/ui/input"
12
+ * import { Tabs } from "@/components/ui/tabs"
13
+ */
14
+
15
+ export { Alert, AlertTitle, AlertDescription } from "./alert";
16
+ export { Button, buttonVariants } from "./button";
17
+ export {
18
+ Card,
19
+ CardHeader,
20
+ CardFooter,
21
+ CardTitle,
22
+ CardAction,
23
+ CardDescription,
24
+ CardContent,
25
+ } from "./card";
26
+ export {
27
+ Field,
28
+ FieldDescription,
29
+ FieldError,
30
+ FieldGroup,
31
+ FieldLabel,
32
+ FieldLegend,
33
+ FieldSeparator,
34
+ FieldSet,
35
+ } from "./field";
36
+ export { Input } from "./input";
37
+ export { Label } from "./label";
38
+ export {
39
+ Select,
40
+ SelectGroup,
41
+ SelectValue,
42
+ SelectTrigger,
43
+ SelectContent,
44
+ SelectLabel,
45
+ SelectItem,
46
+ SelectSeparator,
47
+ SelectScrollUpButton,
48
+ SelectScrollDownButton,
49
+ } from "./select";
50
+ export { Spinner } from "./spinner";
51
+ export { Skeleton } from "./skeleton";
52
+ export {
53
+ Table,
54
+ TableHeader,
55
+ TableBody,
56
+ TableFooter,
57
+ TableHead,
58
+ TableRow,
59
+ TableCell,
60
+ TableCaption,
61
+ } from "./table";
62
+ export { Tabs, TabsList, TabsTrigger, TabsContent } from "./tabs";
63
+ export {
64
+ Pagination,
65
+ PaginationContent,
66
+ PaginationEllipsis,
67
+ PaginationItem,
68
+ PaginationLink,
69
+ PaginationNext,
70
+ PaginationPrevious,
71
+ } from "./pagination";
72
+ export { Separator } from "./separator";
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6
+ return (
7
+ <input
8
+ type={type}
9
+ data-slot="input"
10
+ className={cn(
11
+ "dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
12
+ className,
13
+ )}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+
19
+ export { Input };
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ import { Label as LabelPrimitive } from "radix-ui";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {
7
+ return (
8
+ <LabelPrimitive.Root
9
+ data-slot="label"
10
+ className={cn(
11
+ "gap-2 text-sm leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed",
12
+ className,
13
+ )}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+
19
+ export { Label };
@@ -0,0 +1,112 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+ import { Button } from "./button";
5
+ import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
6
+
7
+ function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
8
+ return (
9
+ <nav
10
+ role="navigation"
11
+ aria-label="pagination"
12
+ data-slot="pagination"
13
+ className={cn("mx-auto flex w-full justify-center", className)}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+
19
+ function PaginationContent({ className, ...props }: React.ComponentProps<"ul">) {
20
+ return (
21
+ <ul
22
+ data-slot="pagination-content"
23
+ className={cn("gap-0.5 flex items-center", className)}
24
+ {...props}
25
+ />
26
+ );
27
+ }
28
+
29
+ function PaginationItem({ ...props }: React.ComponentProps<"li">) {
30
+ return <li data-slot="pagination-item" {...props} />;
31
+ }
32
+
33
+ type PaginationLinkProps = {
34
+ isActive?: boolean;
35
+ } & Pick<React.ComponentProps<typeof Button>, "size"> &
36
+ React.ComponentProps<"a">;
37
+
38
+ function PaginationLink({ className, isActive, size = "icon", ...props }: PaginationLinkProps) {
39
+ return (
40
+ <Button asChild variant={isActive ? "outline" : "ghost"} size={size} className={cn(className)}>
41
+ <a
42
+ aria-current={isActive ? "page" : undefined}
43
+ data-slot="pagination-link"
44
+ data-active={isActive}
45
+ {...props}
46
+ />
47
+ </Button>
48
+ );
49
+ }
50
+
51
+ function PaginationPrevious({
52
+ className,
53
+ text = "Previous",
54
+ ...props
55
+ }: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
56
+ return (
57
+ <PaginationLink
58
+ aria-label="Go to previous page"
59
+ size="default"
60
+ className={cn("pl-1.5!", className)}
61
+ {...props}
62
+ >
63
+ <ChevronLeftIcon data-icon="inline-start" className="cn-rtl-flip" />
64
+ <span className="hidden sm:block">{text}</span>
65
+ </PaginationLink>
66
+ );
67
+ }
68
+
69
+ function PaginationNext({
70
+ className,
71
+ text = "Next",
72
+ ...props
73
+ }: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
74
+ return (
75
+ <PaginationLink
76
+ aria-label="Go to next page"
77
+ size="default"
78
+ className={cn("pr-1.5!", className)}
79
+ {...props}
80
+ >
81
+ <span className="hidden sm:block">{text}</span>
82
+ <ChevronRightIcon data-icon="inline-end" className="cn-rtl-flip" />
83
+ </PaginationLink>
84
+ );
85
+ }
86
+
87
+ function PaginationEllipsis({ className, ...props }: React.ComponentProps<"span">) {
88
+ return (
89
+ <span
90
+ aria-hidden
91
+ data-slot="pagination-ellipsis"
92
+ className={cn(
93
+ "size-8 [&_svg:not([class*='size-'])]:size-4 flex items-center justify-center",
94
+ className,
95
+ )}
96
+ {...props}
97
+ >
98
+ <MoreHorizontalIcon />
99
+ <span className="sr-only">More pages</span>
100
+ </span>
101
+ );
102
+ }
103
+
104
+ export {
105
+ Pagination,
106
+ PaginationContent,
107
+ PaginationEllipsis,
108
+ PaginationItem,
109
+ PaginationLink,
110
+ PaginationNext,
111
+ PaginationPrevious,
112
+ };
@@ -0,0 +1,183 @@
1
+ import * as React from "react";
2
+ import { Select as SelectPrimitive } from "radix-ui";
3
+
4
+ import { cn } from "../../lib/utils";
5
+ import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react";
6
+
7
+ function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {
8
+ return <SelectPrimitive.Root data-slot="select" {...props} />;
9
+ }
10
+
11
+ function SelectGroup({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Group>) {
12
+ return (
13
+ <SelectPrimitive.Group
14
+ data-slot="select-group"
15
+ className={cn("scroll-my-1 p-1", className)}
16
+ {...props}
17
+ />
18
+ );
19
+ }
20
+
21
+ function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>) {
22
+ return <SelectPrimitive.Value data-slot="select-value" {...props} />;
23
+ }
24
+
25
+ function SelectTrigger({
26
+ className,
27
+ size = "default",
28
+ children,
29
+ ...props
30
+ }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
31
+ size?: "sm" | "default";
32
+ }) {
33
+ return (
34
+ <SelectPrimitive.Trigger
35
+ data-slot="select-trigger"
36
+ data-size={size}
37
+ className={cn(
38
+ "border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-lg border bg-transparent py-2 pr-2 pl-2.5 text-sm transition-colors select-none focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
39
+ className,
40
+ )}
41
+ {...props}
42
+ >
43
+ {children}
44
+ <SelectPrimitive.Icon asChild>
45
+ <ChevronDownIcon className="text-muted-foreground size-4 pointer-events-none" />
46
+ </SelectPrimitive.Icon>
47
+ </SelectPrimitive.Trigger>
48
+ );
49
+ }
50
+
51
+ function SelectContent({
52
+ className,
53
+ children,
54
+ position = "item-aligned",
55
+ align = "center",
56
+ ...props
57
+ }: React.ComponentProps<typeof SelectPrimitive.Content>) {
58
+ return (
59
+ <SelectPrimitive.Portal>
60
+ <SelectPrimitive.Content
61
+ data-slot="select-content"
62
+ data-align-trigger={position === "item-aligned"}
63
+ className={cn(
64
+ "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 ring-foreground/10 min-w-36 rounded-lg shadow-md ring-1 duration-100 relative z-50 max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none",
65
+ position === "popper" &&
66
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
67
+ className,
68
+ )}
69
+ position={position}
70
+ align={align}
71
+ {...props}
72
+ >
73
+ <SelectScrollUpButton />
74
+ <SelectPrimitive.Viewport
75
+ data-position={position}
76
+ className={cn(
77
+ "data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)",
78
+ position === "popper" && "",
79
+ )}
80
+ >
81
+ {children}
82
+ </SelectPrimitive.Viewport>
83
+ <SelectScrollDownButton />
84
+ </SelectPrimitive.Content>
85
+ </SelectPrimitive.Portal>
86
+ );
87
+ }
88
+
89
+ function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>) {
90
+ return (
91
+ <SelectPrimitive.Label
92
+ data-slot="select-label"
93
+ className={cn("text-muted-foreground px-1.5 py-1 text-xs", className)}
94
+ {...props}
95
+ />
96
+ );
97
+ }
98
+
99
+ function SelectItem({
100
+ className,
101
+ children,
102
+ ...props
103
+ }: React.ComponentProps<typeof SelectPrimitive.Item>) {
104
+ return (
105
+ <SelectPrimitive.Item
106
+ data-slot="select-item"
107
+ className={cn(
108
+ "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
109
+ className,
110
+ )}
111
+ {...props}
112
+ >
113
+ <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center">
114
+ <SelectPrimitive.ItemIndicator>
115
+ <CheckIcon className="pointer-events-none" />
116
+ </SelectPrimitive.ItemIndicator>
117
+ </span>
118
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
119
+ </SelectPrimitive.Item>
120
+ );
121
+ }
122
+
123
+ function SelectSeparator({
124
+ className,
125
+ ...props
126
+ }: React.ComponentProps<typeof SelectPrimitive.Separator>) {
127
+ return (
128
+ <SelectPrimitive.Separator
129
+ data-slot="select-separator"
130
+ className={cn("bg-border -mx-1 my-1 h-px pointer-events-none", className)}
131
+ {...props}
132
+ />
133
+ );
134
+ }
135
+
136
+ function SelectScrollUpButton({
137
+ className,
138
+ ...props
139
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
140
+ return (
141
+ <SelectPrimitive.ScrollUpButton
142
+ data-slot="select-scroll-up-button"
143
+ className={cn(
144
+ "bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4",
145
+ className,
146
+ )}
147
+ {...props}
148
+ >
149
+ <ChevronUpIcon />
150
+ </SelectPrimitive.ScrollUpButton>
151
+ );
152
+ }
153
+
154
+ function SelectScrollDownButton({
155
+ className,
156
+ ...props
157
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
158
+ return (
159
+ <SelectPrimitive.ScrollDownButton
160
+ data-slot="select-scroll-down-button"
161
+ className={cn(
162
+ "bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4",
163
+ className,
164
+ )}
165
+ {...props}
166
+ >
167
+ <ChevronDownIcon />
168
+ </SelectPrimitive.ScrollDownButton>
169
+ );
170
+ }
171
+
172
+ export {
173
+ Select,
174
+ SelectContent,
175
+ SelectGroup,
176
+ SelectItem,
177
+ SelectLabel,
178
+ SelectScrollDownButton,
179
+ SelectScrollUpButton,
180
+ SelectSeparator,
181
+ SelectTrigger,
182
+ SelectValue,
183
+ };
@@ -0,0 +1,26 @@
1
+ import * as React from "react";
2
+ import { Separator as SeparatorPrimitive } from "radix-ui";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ function Separator({
7
+ className,
8
+ orientation = "horizontal",
9
+ decorative = true,
10
+ ...props
11
+ }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
12
+ return (
13
+ <SeparatorPrimitive.Root
14
+ data-slot="separator"
15
+ decorative={decorative}
16
+ orientation={orientation}
17
+ className={cn(
18
+ "bg-border shrink-0 data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
19
+ className,
20
+ )}
21
+ {...props}
22
+ />
23
+ );
24
+ }
25
+
26
+ export { Separator };
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import { cn } from "../../lib/utils";
3
+
4
+ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
5
+ return (
6
+ <div
7
+ data-slot="skeleton"
8
+ className={cn("bg-accent animate-pulse rounded-md", className)}
9
+ {...props}
10
+ />
11
+ );
12
+ }
13
+
14
+ export { Skeleton };
@@ -0,0 +1,15 @@
1
+ import { cn } from "../../lib/utils";
2
+ import { Loader2Icon } from "lucide-react";
3
+
4
+ function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
5
+ return (
6
+ <Loader2Icon
7
+ role="status"
8
+ aria-label="Loading"
9
+ className={cn("size-4 animate-spin", className)}
10
+ {...(props as any)}
11
+ />
12
+ );
13
+ }
14
+
15
+ export { Spinner };