@carlonicora/nextjs-jsonapi 0.0.1 → 1.0.4
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/dist/BlockNoteEditor-VFWG6LXI.js.map +1 -1
- package/dist/JsonApiRequest-ZZLSP26T.js.map +1 -1
- package/dist/atoms/index.js.map +1 -1
- package/dist/chunk-2K3Q24UF.js.map +1 -1
- package/dist/chunk-3FBCC4G3.js.map +1 -1
- package/dist/chunk-4HCRAOS5.js.map +1 -1
- package/dist/chunk-6GKHCVF6.js.map +1 -1
- package/dist/chunk-7QVYU63E.js.map +1 -1
- package/dist/chunk-A5DDIABK.js.map +1 -1
- package/dist/chunk-AWONBQQP.js.map +1 -1
- package/dist/chunk-CXQOWQSY.js.map +1 -1
- package/dist/chunk-DO2HLAZO.js.map +1 -1
- package/dist/chunk-EFJEWLRL.js.map +1 -1
- package/dist/chunk-FY4SXJGU.js.map +1 -1
- package/dist/chunk-H6FMOA6B.js.map +1 -1
- package/dist/chunk-I2REI7OA.js.map +1 -1
- package/dist/chunk-IBS6NI7D.js.map +1 -1
- package/dist/chunk-J4Q36PMP.js.map +1 -1
- package/dist/chunk-JC3WJK65.js.map +1 -1
- package/dist/chunk-LXKSUWAV.js.map +1 -1
- package/dist/chunk-RAF7PNLG.js.map +1 -1
- package/dist/chunk-RUR22SVM.js.map +1 -1
- package/dist/chunk-TEGF6ZWG.js.map +1 -1
- package/dist/chunk-TMVHSY3Y.js.map +1 -1
- package/dist/chunk-V2JJPI7N.js.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/components/index.js.map +1 -1
- package/dist/contexts/index.js.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/features/index.js.map +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/index.js.map +1 -1
- package/dist/permissions/index.js.map +1 -1
- package/dist/request-QFS7NEIE.js.map +1 -1
- package/dist/request-ZYY6RI5X.js.map +1 -1
- package/dist/roles/index.js.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/shadcnui/index.js.map +1 -1
- package/dist/token-MJMC26ON.js.map +1 -1
- package/dist/token-UYE7CV6X.js.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +6 -1
- package/src/atoms/index.ts +1 -0
- package/src/atoms/recentPagesAtom.ts +10 -0
- package/src/client/context/JsonApiContext.ts +61 -0
- package/src/client/context/JsonApiProvider.tsx +27 -0
- package/src/client/context/index.ts +2 -0
- package/src/client/hooks/index.ts +3 -0
- package/src/client/hooks/useJsonApiGet.ts +188 -0
- package/src/client/hooks/useJsonApiMutation.ts +193 -0
- package/src/client/hooks/useRehydration.ts +47 -0
- package/src/client/index.ts +11 -0
- package/src/client/request.ts +97 -0
- package/src/client/token.ts +10 -0
- package/src/components/containers/PageContainer.tsx +15 -0
- package/src/components/containers/ReactMarkdownContainer.tsx +119 -0
- package/src/components/containers/TabsContainer.tsx +93 -0
- package/src/components/containers/index.ts +3 -0
- package/src/components/contents/AttributeElement.tsx +20 -0
- package/src/components/contents/index.ts +1 -0
- package/src/components/details/AllowedUsersDetails.tsx +23 -0
- package/src/components/details/index.ts +1 -0
- package/src/components/editors/BlockNoteDiffInlineContent.tsx +152 -0
- package/src/components/editors/BlockNoteEditor.tsx +404 -0
- package/src/components/editors/BlockNoteEditorContainer.tsx +13 -0
- package/src/components/editors/BlockNoteEditorFormattingToolbar.tsx +38 -0
- package/src/components/editors/index.ts +1 -0
- package/src/components/errors/ErrorDetails.tsx +41 -0
- package/src/components/errors/errorToast.ts +9 -0
- package/src/components/errors/index.ts +2 -0
- package/src/components/forms/CommonAssociationForm.tsx +162 -0
- package/src/components/forms/CommonDeleter.tsx +94 -0
- package/src/components/forms/CommonEditorButtons.tsx +30 -0
- package/src/components/forms/CommonEditorHeader.tsx +35 -0
- package/src/components/forms/CommonEditorTrigger.tsx +26 -0
- package/src/components/forms/DatePickerPopover.tsx +219 -0
- package/src/components/forms/DateRangeSelector.tsx +110 -0
- package/src/components/forms/FileUploader.tsx +324 -0
- package/src/components/forms/FormCheckbox.tsx +66 -0
- package/src/components/forms/FormContainerGeneric.tsx +39 -0
- package/src/components/forms/FormDate.tsx +247 -0
- package/src/components/forms/FormDateTime.tsx +231 -0
- package/src/components/forms/FormInput.tsx +110 -0
- package/src/components/forms/FormPassword.tsx +54 -0
- package/src/components/forms/FormPlaceAutocomplete.tsx +286 -0
- package/src/components/forms/FormSelect.tsx +72 -0
- package/src/components/forms/FormSlider.tsx +51 -0
- package/src/components/forms/FormSwitch.tsx +25 -0
- package/src/components/forms/FormTextarea.tsx +44 -0
- package/src/components/forms/MultiFileUploader.tsx +107 -0
- package/src/components/forms/PasswordInput.tsx +47 -0
- package/src/components/forms/index.ts +21 -0
- package/src/components/index.ts +11 -0
- package/src/components/navigations/Breadcrumb.tsx +83 -0
- package/src/components/navigations/ContentTitle.tsx +39 -0
- package/src/components/navigations/Header.tsx +27 -0
- package/src/components/navigations/ModeToggleSwitch.tsx +25 -0
- package/src/components/navigations/PageSection.tsx +64 -0
- package/src/components/navigations/RecentPagesNavigator.tsx +52 -0
- package/src/components/navigations/index.ts +6 -0
- package/src/components/pages/PageContainerContentDetails.tsx +76 -0
- package/src/components/pages/PageContentContainer.tsx +31 -0
- package/src/components/pages/index.ts +2 -0
- package/src/components/tables/ContentListTable.tsx +165 -0
- package/src/components/tables/ContentTableSearch.tsx +105 -0
- package/src/components/tables/cells/cell.component.tsx +18 -0
- package/src/components/tables/cells/cell.date.tsx +16 -0
- package/src/components/tables/cells/cell.id.tsx +27 -0
- package/src/components/tables/cells/cell.link.tsx +18 -0
- package/src/components/tables/cells/cell.text.tsx +12 -0
- package/src/components/tables/cells/cell.url.tsx +13 -0
- package/src/components/tables/cells/index.ts +5 -0
- package/src/components/tables/index.ts +3 -0
- package/src/contexts/SharedContext.tsx +35 -0
- package/src/contexts/index.ts +2 -0
- package/src/core/abstracts/AbstractApiData.ts +138 -0
- package/src/core/abstracts/AbstractService.ts +263 -0
- package/src/core/abstracts/index.ts +2 -0
- package/src/core/endpoint/EndpointCreator.ts +97 -0
- package/src/core/endpoint/index.ts +1 -0
- package/src/core/factories/JsonApiDataFactory.ts +12 -0
- package/src/core/factories/RehydrationFactory.ts +30 -0
- package/src/core/factories/index.ts +2 -0
- package/src/core/fields/FieldSelector.ts +15 -0
- package/src/core/fields/index.ts +1 -0
- package/src/core/index.ts +20 -0
- package/src/core/interfaces/ApiData.ts +8 -0
- package/src/core/interfaces/ApiDataInterface.ts +15 -0
- package/src/core/interfaces/ApiRequestDataTypeInterface.ts +14 -0
- package/src/core/interfaces/ApiResponseInterface.ts +17 -0
- package/src/core/interfaces/JsonApiHydratedDataInterface.ts +5 -0
- package/src/core/interfaces/index.ts +5 -0
- package/src/core/registry/DataClassRegistry.ts +51 -0
- package/src/core/registry/ModuleRegistrar.ts +43 -0
- package/src/core/registry/ModuleRegistry.ts +64 -0
- package/src/core/registry/index.ts +3 -0
- package/src/core/utils/index.ts +2 -0
- package/src/core/utils/rehydrate.ts +24 -0
- package/src/core/utils/translateResponse.ts +125 -0
- package/src/features/auth/auth.module.ts +9 -0
- package/src/features/auth/config.ts +57 -0
- package/src/features/auth/data/auth.interface.ts +31 -0
- package/src/features/auth/data/auth.service.ts +159 -0
- package/src/features/auth/data/auth.ts +54 -0
- package/src/features/auth/data/index.ts +3 -0
- package/src/features/auth/index.ts +3 -0
- package/src/features/company/company.module.ts +10 -0
- package/src/features/company/data/company.fields.ts +6 -0
- package/src/features/company/data/company.interface.ts +28 -0
- package/src/features/company/data/company.service.ts +73 -0
- package/src/features/company/data/company.ts +104 -0
- package/src/features/company/data/index.ts +4 -0
- package/src/features/company/index.ts +2 -0
- package/src/features/content/content.module.ts +20 -0
- package/src/features/content/data/content.fields.ts +13 -0
- package/src/features/content/data/content.interface.ts +23 -0
- package/src/features/content/data/content.service.ts +75 -0
- package/src/features/content/data/content.ts +85 -0
- package/src/features/content/data/index.ts +4 -0
- package/src/features/content/index.ts +2 -0
- package/src/features/feature/components/forms/FormFeatures.tsx +149 -0
- package/src/features/feature/components/index.ts +1 -0
- package/src/features/feature/data/feature.interface.ts +9 -0
- package/src/features/feature/data/feature.service.ts +19 -0
- package/src/features/feature/data/feature.ts +33 -0
- package/src/features/feature/data/index.ts +3 -0
- package/src/features/feature/feature.module.ts +10 -0
- package/src/features/feature/index.ts +3 -0
- package/src/features/index.ts +12 -0
- package/src/features/module/data/index.ts +2 -0
- package/src/features/module/data/module.interface.ts +12 -0
- package/src/features/module/data/module.ts +42 -0
- package/src/features/module/index.ts +2 -0
- package/src/features/module/module.module.ts +10 -0
- package/src/features/notification/data/index.ts +4 -0
- package/src/features/notification/data/notification.fields.ts +8 -0
- package/src/features/notification/data/notification.interface.ts +14 -0
- package/src/features/notification/data/notification.service.ts +34 -0
- package/src/features/notification/data/notification.ts +51 -0
- package/src/features/notification/index.ts +2 -0
- package/src/features/notification/notification.module.ts +10 -0
- package/src/features/push/data/index.ts +3 -0
- package/src/features/push/data/push.interface.ts +8 -0
- package/src/features/push/data/push.service.ts +17 -0
- package/src/features/push/data/push.ts +18 -0
- package/src/features/push/index.ts +2 -0
- package/src/features/push/push.module.ts +10 -0
- package/src/features/role/data/index.ts +4 -0
- package/src/features/role/data/role.fields.ts +8 -0
- package/src/features/role/data/role.interface.ts +16 -0
- package/src/features/role/data/role.service.ts +117 -0
- package/src/features/role/data/role.ts +62 -0
- package/src/features/role/index.ts +2 -0
- package/src/features/role/role.module.ts +10 -0
- package/src/features/s3/data/index.ts +3 -0
- package/src/features/s3/data/s3.interface.ts +11 -0
- package/src/features/s3/data/s3.service.ts +30 -0
- package/src/features/s3/data/s3.ts +60 -0
- package/src/features/s3/index.ts +2 -0
- package/src/features/s3/s3.module.ts +10 -0
- package/src/features/search/index.ts +1 -0
- package/src/features/search/interfaces/index.ts +1 -0
- package/src/features/search/interfaces/search.result.interface.ts +3 -0
- package/src/features/user/author.module.ts +10 -0
- package/src/features/user/components/index.ts +2 -0
- package/src/features/user/components/lists/ContributorsList.tsx +41 -0
- package/src/features/user/components/lists/index.ts +1 -0
- package/src/features/user/components/widgets/UserAvatar.tsx +86 -0
- package/src/features/user/components/widgets/index.ts +1 -0
- package/src/features/user/contexts/CurrentUserContext.tsx +156 -0
- package/src/features/user/contexts/index.ts +1 -0
- package/src/features/user/data/index.ts +4 -0
- package/src/features/user/data/user.fields.ts +8 -0
- package/src/features/user/data/user.interface.ts +41 -0
- package/src/features/user/data/user.service.ts +246 -0
- package/src/features/user/data/user.ts +162 -0
- package/src/features/user/index.ts +4 -0
- package/src/features/user/user.module.ts +21 -0
- package/src/hooks/TableGeneratorRegistry.ts +53 -0
- package/src/hooks/index.ts +33 -0
- package/src/hooks/types.ts +35 -0
- package/src/hooks/url.rewriter.ts +22 -0
- package/src/hooks/useCustomD3Graph.tsx +705 -0
- package/src/hooks/useDataListRetriever.ts +349 -0
- package/src/hooks/useDebounce.ts +33 -0
- package/src/hooks/usePageUrlGenerator.ts +50 -0
- package/src/hooks/useTableGenerator.ts +16 -0
- package/src/i18n/config.ts +73 -0
- package/src/i18n/index.ts +18 -0
- package/src/index.ts +16 -0
- package/src/interfaces/breadcrumb.item.data.interface.ts +4 -0
- package/src/interfaces/d3.link.interface.ts +7 -0
- package/src/interfaces/d3.node.interface.ts +12 -0
- package/src/interfaces/index.ts +3 -0
- package/src/permissions/check.ts +127 -0
- package/src/permissions/index.ts +2 -0
- package/src/permissions/types.ts +109 -0
- package/src/roles/config.ts +46 -0
- package/src/roles/index.ts +1 -0
- package/src/server/cache.ts +28 -0
- package/src/server/index.ts +3 -0
- package/src/server/request.ts +113 -0
- package/src/server/token.ts +10 -0
- package/src/shadcnui/custom/kanban.tsx +1001 -0
- package/src/shadcnui/custom/link.tsx +18 -0
- package/src/shadcnui/custom/multi-select.tsx +382 -0
- package/src/shadcnui/index.ts +49 -0
- package/src/shadcnui/ui/accordion.tsx +52 -0
- package/src/shadcnui/ui/alert-dialog.tsx +141 -0
- package/src/shadcnui/ui/alert.tsx +43 -0
- package/src/shadcnui/ui/avatar.tsx +50 -0
- package/src/shadcnui/ui/badge.tsx +40 -0
- package/src/shadcnui/ui/breadcrumb.tsx +115 -0
- package/src/shadcnui/ui/button.tsx +51 -0
- package/src/shadcnui/ui/calendar.tsx +73 -0
- package/src/shadcnui/ui/card.tsx +43 -0
- package/src/shadcnui/ui/carousel.tsx +225 -0
- package/src/shadcnui/ui/chart.tsx +320 -0
- package/src/shadcnui/ui/checkbox.tsx +29 -0
- package/src/shadcnui/ui/collapsible.tsx +11 -0
- package/src/shadcnui/ui/command.tsx +155 -0
- package/src/shadcnui/ui/context-menu.tsx +179 -0
- package/src/shadcnui/ui/dialog.tsx +96 -0
- package/src/shadcnui/ui/drawer.tsx +89 -0
- package/src/shadcnui/ui/dropdown-menu.tsx +205 -0
- package/src/shadcnui/ui/form.tsx +138 -0
- package/src/shadcnui/ui/hover-card.tsx +29 -0
- package/src/shadcnui/ui/input.tsx +21 -0
- package/src/shadcnui/ui/label.tsx +26 -0
- package/src/shadcnui/ui/navigation-menu.tsx +168 -0
- package/src/shadcnui/ui/popover.tsx +33 -0
- package/src/shadcnui/ui/progress.tsx +25 -0
- package/src/shadcnui/ui/radio-group.tsx +37 -0
- package/src/shadcnui/ui/resizable.tsx +47 -0
- package/src/shadcnui/ui/scroll-area.tsx +40 -0
- package/src/shadcnui/ui/select.tsx +164 -0
- package/src/shadcnui/ui/separator.tsx +28 -0
- package/src/shadcnui/ui/sheet.tsx +139 -0
- package/src/shadcnui/ui/sidebar.tsx +677 -0
- package/src/shadcnui/ui/skeleton.tsx +13 -0
- package/src/shadcnui/ui/slider.tsx +25 -0
- package/src/shadcnui/ui/sonner.tsx +25 -0
- package/src/shadcnui/ui/switch.tsx +31 -0
- package/src/shadcnui/ui/table.tsx +120 -0
- package/src/shadcnui/ui/tabs.tsx +55 -0
- package/src/shadcnui/ui/textarea.tsx +24 -0
- package/src/shadcnui/ui/toggle.tsx +39 -0
- package/src/shadcnui/ui/tooltip.tsx +61 -0
- package/src/unified/JsonApiRequest.ts +325 -0
- package/src/unified/index.ts +1 -0
- package/src/utils/blocknote-diff.util.ts +815 -0
- package/src/utils/blocknote-word-diff-renderer.util.ts +413 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/compose-refs.ts +61 -0
- package/src/utils/date-formatter.ts +53 -0
- package/src/utils/exists.ts +7 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/schemas/entity.object.schema.ts +8 -0
- package/src/utils/schemas/index.ts +2 -0
- package/src/utils/schemas/user.object.schema.ts +9 -0
- package/src/utils/table-options.ts +67 -0
- package/src/utils/use-mobile.tsx +21 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import NextLink from "next/link";
|
|
4
|
+
import { cn } from "../../utils/cn";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
// Create our custom Link props interface that extends Next.js Link
|
|
8
|
+
export interface LinkProps extends React.ComponentPropsWithoutRef<typeof NextLink> {
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(({ className, ...props }, ref) => {
|
|
13
|
+
return <NextLink ref={ref} className={cn(`font-medium`, className)} {...props} />;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
Link.displayName = "Link";
|
|
17
|
+
|
|
18
|
+
export { Link };
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
+
import { CheckIcon, ChevronDown, WandSparkles, XCircle, XIcon } from "lucide-react";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
import { Badge } from "../ui/badge";
|
|
8
|
+
import { Button } from "../ui/button";
|
|
9
|
+
import {
|
|
10
|
+
Command,
|
|
11
|
+
CommandEmpty,
|
|
12
|
+
CommandGroup,
|
|
13
|
+
CommandInput,
|
|
14
|
+
CommandItem,
|
|
15
|
+
CommandList,
|
|
16
|
+
CommandSeparator,
|
|
17
|
+
} from "../ui/command";
|
|
18
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
|
19
|
+
import { Separator } from "../ui/separator";
|
|
20
|
+
import { cn } from "../../utils/cn";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Variants for the multi-select component to handle different styles.
|
|
24
|
+
* Uses class-variance-authority (cva) to define different styles based on "variant" prop.
|
|
25
|
+
*/
|
|
26
|
+
const multiSelectVariants = cva(
|
|
27
|
+
"m-1 transition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 duration-300",
|
|
28
|
+
{
|
|
29
|
+
variants: {
|
|
30
|
+
variant: {
|
|
31
|
+
default: "border-foreground/10 text-foreground bg-card hover:bg-card/80",
|
|
32
|
+
secondary: "border-foreground/10 bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
33
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
34
|
+
inverted: "inverted",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: {
|
|
38
|
+
variant: "default",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Props for MultiSelect component
|
|
45
|
+
*/
|
|
46
|
+
interface MultiSelectProps
|
|
47
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
48
|
+
VariantProps<typeof multiSelectVariants> {
|
|
49
|
+
/**
|
|
50
|
+
* An array of option objects to be displayed in the multi-select component.
|
|
51
|
+
* Each option object has a label, value, and an optional icon.
|
|
52
|
+
*/
|
|
53
|
+
options: {
|
|
54
|
+
/** The text to display for the option. */
|
|
55
|
+
label: string;
|
|
56
|
+
/** The unique value associated with the option. */
|
|
57
|
+
value: string;
|
|
58
|
+
/** Optional icon component to display alongside the option. */
|
|
59
|
+
icon?: React.ComponentType<{ className?: string }>;
|
|
60
|
+
}[];
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Callback function triggered when the selected values change.
|
|
64
|
+
* Receives an array of the new selected values.
|
|
65
|
+
*/
|
|
66
|
+
onValueChange: (value: string[]) => void;
|
|
67
|
+
|
|
68
|
+
/** The default selected values when the component mounts. */
|
|
69
|
+
defaultValue?: string[];
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The controlled value for the component. When provided, the component
|
|
73
|
+
* will be controlled rather than using internal state.
|
|
74
|
+
*/
|
|
75
|
+
value?: string[];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Placeholder text to be displayed when no values are selected.
|
|
79
|
+
* Optional, defaults to "Select options".
|
|
80
|
+
*/
|
|
81
|
+
placeholder?: string;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Animation duration in seconds for the visual effects (e.g., bouncing badges).
|
|
85
|
+
* Optional, defaults to 0 (no animation).
|
|
86
|
+
*/
|
|
87
|
+
animation?: number;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Maximum number of items to display. Extra selected items will be summarized.
|
|
91
|
+
* Optional, defaults to 3.
|
|
92
|
+
*/
|
|
93
|
+
maxCount?: number;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The modality of the popover. When set to true, interaction with outside elements
|
|
97
|
+
* will be disabled and only popover content will be visible to screen readers.
|
|
98
|
+
* Optional, defaults to false.
|
|
99
|
+
*/
|
|
100
|
+
modalPopover?: boolean;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* If true, renders the multi-select component as a child of another component.
|
|
104
|
+
* Optional, defaults to false.
|
|
105
|
+
*/
|
|
106
|
+
asChild?: boolean;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Additional class names to apply custom styles to the multi-select component.
|
|
110
|
+
* Optional, can be used to add custom styles.
|
|
111
|
+
*/
|
|
112
|
+
className?: string;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Callback function triggered when the search input value changes.
|
|
116
|
+
* Optional, receives the search string.
|
|
117
|
+
*/
|
|
118
|
+
onSearchChange?: (search: string) => void;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(
|
|
122
|
+
(
|
|
123
|
+
{
|
|
124
|
+
options,
|
|
125
|
+
onValueChange,
|
|
126
|
+
variant,
|
|
127
|
+
defaultValue = [],
|
|
128
|
+
value,
|
|
129
|
+
placeholder = "Select options",
|
|
130
|
+
animation = 0,
|
|
131
|
+
maxCount = 3,
|
|
132
|
+
modalPopover = false,
|
|
133
|
+
asChild = false,
|
|
134
|
+
className,
|
|
135
|
+
onSearchChange,
|
|
136
|
+
...props
|
|
137
|
+
},
|
|
138
|
+
ref,
|
|
139
|
+
) => {
|
|
140
|
+
// Using internal state only if value prop is not provided (uncontrolled mode)
|
|
141
|
+
const [internalSelectedValues, setInternalSelectedValues] = React.useState<string[]>(defaultValue);
|
|
142
|
+
|
|
143
|
+
// If value prop is provided, use it (controlled mode), otherwise use internal state
|
|
144
|
+
const selectedValues = value !== undefined ? value : internalSelectedValues;
|
|
145
|
+
|
|
146
|
+
const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
|
|
147
|
+
const [isAnimating, setIsAnimating] = React.useState(false);
|
|
148
|
+
|
|
149
|
+
const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
150
|
+
if (event.key === "Enter") {
|
|
151
|
+
setIsPopoverOpen(true);
|
|
152
|
+
} else if (event.key === "Backspace" && !event.currentTarget.value) {
|
|
153
|
+
const newSelectedValues = [...selectedValues];
|
|
154
|
+
newSelectedValues.pop();
|
|
155
|
+
|
|
156
|
+
// If in uncontrolled mode, update internal state
|
|
157
|
+
if (value === undefined) {
|
|
158
|
+
setInternalSelectedValues(newSelectedValues);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Always call the callback
|
|
162
|
+
onValueChange(newSelectedValues);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const toggleOption = (option: string) => {
|
|
167
|
+
const newSelectedValues = selectedValues.includes(option)
|
|
168
|
+
? selectedValues.filter((value) => value !== option)
|
|
169
|
+
: [...selectedValues, option];
|
|
170
|
+
|
|
171
|
+
// If in uncontrolled mode, update internal state
|
|
172
|
+
if (value === undefined) {
|
|
173
|
+
setInternalSelectedValues(newSelectedValues);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Always call the callback
|
|
177
|
+
onValueChange(newSelectedValues);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const handleClear = () => {
|
|
181
|
+
// If in uncontrolled mode, update internal state
|
|
182
|
+
if (value === undefined) {
|
|
183
|
+
setInternalSelectedValues([]);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Always call the callback
|
|
187
|
+
onValueChange([]);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const handleTogglePopover = () => {
|
|
191
|
+
setIsPopoverOpen((prev) => !prev);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const clearExtraOptions = () => {
|
|
195
|
+
const newSelectedValues = selectedValues.slice(0, maxCount);
|
|
196
|
+
|
|
197
|
+
// If in uncontrolled mode, update internal state
|
|
198
|
+
if (value === undefined) {
|
|
199
|
+
setInternalSelectedValues(newSelectedValues);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Always call the callback
|
|
203
|
+
onValueChange(newSelectedValues);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const toggleAll = () => {
|
|
207
|
+
let newSelectedValues: string[];
|
|
208
|
+
|
|
209
|
+
if (selectedValues.length === options.length) {
|
|
210
|
+
newSelectedValues = [];
|
|
211
|
+
} else {
|
|
212
|
+
newSelectedValues = options.map((option) => option.value);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// If in uncontrolled mode, update internal state
|
|
216
|
+
if (value === undefined) {
|
|
217
|
+
setInternalSelectedValues(newSelectedValues);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Always call the callback
|
|
221
|
+
onValueChange(newSelectedValues);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal={modalPopover}>
|
|
226
|
+
<PopoverTrigger asChild>
|
|
227
|
+
<Button
|
|
228
|
+
ref={ref}
|
|
229
|
+
{...props}
|
|
230
|
+
onClick={handleTogglePopover}
|
|
231
|
+
className={cn(
|
|
232
|
+
"flex h-auto min-h-10 w-full items-center justify-between rounded-md border bg-inherit p-1 hover:bg-inherit [&_svg]:pointer-events-auto",
|
|
233
|
+
className,
|
|
234
|
+
)}
|
|
235
|
+
>
|
|
236
|
+
{selectedValues.length > 0 ? (
|
|
237
|
+
<div className="flex w-full items-center justify-between">
|
|
238
|
+
<div className="flex flex-wrap items-center">
|
|
239
|
+
{selectedValues.slice(0, maxCount).map((value) => {
|
|
240
|
+
const option = options.find((o) => o.value === value);
|
|
241
|
+
const IconComponent = option?.icon;
|
|
242
|
+
return (
|
|
243
|
+
<Badge
|
|
244
|
+
key={value}
|
|
245
|
+
className={cn(isAnimating ? "animate-bounce" : "", multiSelectVariants({ variant }))}
|
|
246
|
+
style={{ animationDuration: `${animation}s` }}
|
|
247
|
+
>
|
|
248
|
+
{IconComponent && <IconComponent className="mr-2 h-4 w-4" />}
|
|
249
|
+
{option?.label}
|
|
250
|
+
<XCircle
|
|
251
|
+
className="ml-2 h-4 w-4 cursor-pointer"
|
|
252
|
+
onClick={(event) => {
|
|
253
|
+
event.stopPropagation();
|
|
254
|
+
toggleOption(value);
|
|
255
|
+
}}
|
|
256
|
+
/>
|
|
257
|
+
</Badge>
|
|
258
|
+
);
|
|
259
|
+
})}
|
|
260
|
+
{selectedValues.length > maxCount && (
|
|
261
|
+
<Badge
|
|
262
|
+
className={cn(
|
|
263
|
+
"text-foreground border-foreground/1 bg-transparent hover:bg-transparent",
|
|
264
|
+
isAnimating ? "animate-bounce" : "",
|
|
265
|
+
multiSelectVariants({ variant }),
|
|
266
|
+
)}
|
|
267
|
+
style={{ animationDuration: `${animation}s` }}
|
|
268
|
+
>
|
|
269
|
+
{`+ ${selectedValues.length - maxCount} more`}
|
|
270
|
+
<XCircle
|
|
271
|
+
className="ml-2 h-4 w-4 cursor-pointer"
|
|
272
|
+
onClick={(event) => {
|
|
273
|
+
event.stopPropagation();
|
|
274
|
+
clearExtraOptions();
|
|
275
|
+
}}
|
|
276
|
+
/>
|
|
277
|
+
</Badge>
|
|
278
|
+
)}
|
|
279
|
+
</div>
|
|
280
|
+
<div className="flex items-center justify-between">
|
|
281
|
+
<XIcon
|
|
282
|
+
className="text-muted-foreground mx-2 h-4 cursor-pointer"
|
|
283
|
+
onClick={(event) => {
|
|
284
|
+
event.stopPropagation();
|
|
285
|
+
handleClear();
|
|
286
|
+
}}
|
|
287
|
+
/>
|
|
288
|
+
<Separator orientation="vertical" className="flex h-full min-h-6" />
|
|
289
|
+
<ChevronDown className="text-muted-foreground mx-2 h-4 cursor-pointer" />
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
) : (
|
|
293
|
+
<div className="mx-auto flex w-full items-center justify-between">
|
|
294
|
+
<span className="text-muted-foreground mx-3 text-sm">{placeholder}</span>
|
|
295
|
+
<ChevronDown className="text-muted-foreground mx-2 h-4 cursor-pointer" />
|
|
296
|
+
</div>
|
|
297
|
+
)}
|
|
298
|
+
</Button>
|
|
299
|
+
</PopoverTrigger>
|
|
300
|
+
<PopoverContent className="w-auto p-0" align="start" onEscapeKeyDown={() => setIsPopoverOpen(false)}>
|
|
301
|
+
<Command>
|
|
302
|
+
<CommandInput
|
|
303
|
+
autoFocus
|
|
304
|
+
placeholder="Search..."
|
|
305
|
+
onKeyDown={handleInputKeyDown}
|
|
306
|
+
onValueChange={onSearchChange}
|
|
307
|
+
/>
|
|
308
|
+
<CommandList>
|
|
309
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
310
|
+
<CommandGroup>
|
|
311
|
+
<CommandItem key="all" onSelect={toggleAll} className="cursor-pointer">
|
|
312
|
+
<div
|
|
313
|
+
className={cn(
|
|
314
|
+
"border-primary mr-2 flex h-4 w-4 items-center justify-center rounded-sm border",
|
|
315
|
+
selectedValues.length === options.length
|
|
316
|
+
? "bg-primary text-primary-foreground"
|
|
317
|
+
: "opacity-50 [&_svg]:invisible",
|
|
318
|
+
)}
|
|
319
|
+
>
|
|
320
|
+
<CheckIcon className="h-4 w-4" />
|
|
321
|
+
</div>
|
|
322
|
+
<span>(Select All)</span>
|
|
323
|
+
</CommandItem>
|
|
324
|
+
{options.map((option) => {
|
|
325
|
+
const isSelected = selectedValues.includes(option.value);
|
|
326
|
+
return (
|
|
327
|
+
<CommandItem
|
|
328
|
+
key={option.value}
|
|
329
|
+
onSelect={() => toggleOption(option.value)}
|
|
330
|
+
className="cursor-pointer"
|
|
331
|
+
>
|
|
332
|
+
<div
|
|
333
|
+
className={cn(
|
|
334
|
+
"border-primary mr-2 flex h-4 w-4 items-center justify-center rounded-sm border",
|
|
335
|
+
isSelected ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible",
|
|
336
|
+
)}
|
|
337
|
+
>
|
|
338
|
+
<CheckIcon className="h-4 w-4" />
|
|
339
|
+
</div>
|
|
340
|
+
{option.icon && <option.icon className="text-muted-foreground mr-2 h-4 w-4" />}
|
|
341
|
+
<span>{option.label}</span>
|
|
342
|
+
</CommandItem>
|
|
343
|
+
);
|
|
344
|
+
})}
|
|
345
|
+
</CommandGroup>
|
|
346
|
+
<CommandSeparator />
|
|
347
|
+
<CommandGroup>
|
|
348
|
+
<div className="flex items-center justify-between">
|
|
349
|
+
{selectedValues.length > 0 && (
|
|
350
|
+
<>
|
|
351
|
+
<CommandItem onSelect={handleClear} className="flex-1 cursor-pointer justify-center">
|
|
352
|
+
Clear
|
|
353
|
+
</CommandItem>
|
|
354
|
+
<Separator orientation="vertical" className="flex h-full min-h-6" />
|
|
355
|
+
</>
|
|
356
|
+
)}
|
|
357
|
+
<CommandItem
|
|
358
|
+
onSelect={() => setIsPopoverOpen(false)}
|
|
359
|
+
className="max-w-full flex-1 cursor-pointer justify-center"
|
|
360
|
+
>
|
|
361
|
+
Close
|
|
362
|
+
</CommandItem>
|
|
363
|
+
</div>
|
|
364
|
+
</CommandGroup>
|
|
365
|
+
</CommandList>
|
|
366
|
+
</Command>
|
|
367
|
+
</PopoverContent>
|
|
368
|
+
{animation > 0 && selectedValues.length > 0 && (
|
|
369
|
+
<WandSparkles
|
|
370
|
+
className={cn(
|
|
371
|
+
"text-foreground bg-background my-2 h-3 w-3 cursor-pointer",
|
|
372
|
+
isAnimating ? "" : "text-muted-foreground",
|
|
373
|
+
)}
|
|
374
|
+
onClick={() => setIsAnimating(!isAnimating)}
|
|
375
|
+
/>
|
|
376
|
+
)}
|
|
377
|
+
</Popover>
|
|
378
|
+
);
|
|
379
|
+
},
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
MultiSelect.displayName = "MultiSelect";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// UI Components
|
|
4
|
+
export * from "./ui/accordion";
|
|
5
|
+
export * from "./ui/alert";
|
|
6
|
+
export * from "./ui/alert-dialog";
|
|
7
|
+
export * from "./ui/avatar";
|
|
8
|
+
export * from "./ui/badge";
|
|
9
|
+
export * from "./ui/breadcrumb";
|
|
10
|
+
export * from "./ui/button";
|
|
11
|
+
export * from "./ui/calendar";
|
|
12
|
+
export * from "./ui/card";
|
|
13
|
+
export * from "./ui/carousel";
|
|
14
|
+
export * from "./ui/chart";
|
|
15
|
+
export * from "./ui/checkbox";
|
|
16
|
+
export * from "./ui/collapsible";
|
|
17
|
+
export * from "./ui/command";
|
|
18
|
+
export * from "./ui/context-menu";
|
|
19
|
+
export * from "./ui/dialog";
|
|
20
|
+
export * from "./ui/drawer";
|
|
21
|
+
export * from "./ui/dropdown-menu";
|
|
22
|
+
export * from "./ui/form";
|
|
23
|
+
export * from "./ui/hover-card";
|
|
24
|
+
export * from "./ui/input";
|
|
25
|
+
export * from "./ui/label";
|
|
26
|
+
export * from "./ui/navigation-menu";
|
|
27
|
+
export * from "./ui/popover";
|
|
28
|
+
export * from "./ui/progress";
|
|
29
|
+
export * from "./ui/radio-group";
|
|
30
|
+
export * from "./ui/resizable";
|
|
31
|
+
export * from "./ui/scroll-area";
|
|
32
|
+
export * from "./ui/select";
|
|
33
|
+
export * from "./ui/separator";
|
|
34
|
+
export * from "./ui/sheet";
|
|
35
|
+
export * from "./ui/sidebar";
|
|
36
|
+
export * from "./ui/skeleton";
|
|
37
|
+
export * from "./ui/slider";
|
|
38
|
+
export * from "./ui/sonner";
|
|
39
|
+
export * from "./ui/switch";
|
|
40
|
+
export * from "./ui/table";
|
|
41
|
+
export * from "./ui/tabs";
|
|
42
|
+
export * from "./ui/textarea";
|
|
43
|
+
export * from "./ui/toggle";
|
|
44
|
+
export * from "./ui/tooltip";
|
|
45
|
+
|
|
46
|
+
// Custom Components
|
|
47
|
+
export * from "./custom/kanban";
|
|
48
|
+
export * from "./custom/link";
|
|
49
|
+
export * from "./custom/multi-select";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
|
4
|
+
import { ChevronDownIcon } from "@radix-ui/react-icons";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
import { cn } from "../../utils/cn";
|
|
8
|
+
|
|
9
|
+
const Accordion = AccordionPrimitive.Root;
|
|
10
|
+
|
|
11
|
+
const AccordionItem = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof AccordionPrimitive.Item>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
|
14
|
+
>(({ className, ...props }, ref) => (
|
|
15
|
+
<AccordionPrimitive.Item ref={ref} className={cn("border-b", className)} {...props} />
|
|
16
|
+
));
|
|
17
|
+
AccordionItem.displayName = "AccordionItem";
|
|
18
|
+
|
|
19
|
+
const AccordionTrigger = React.forwardRef<
|
|
20
|
+
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
|
21
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
|
22
|
+
>(({ className, children, ...props }, ref) => (
|
|
23
|
+
<AccordionPrimitive.Header className="flex" asChild>
|
|
24
|
+
<AccordionPrimitive.Trigger
|
|
25
|
+
ref={ref}
|
|
26
|
+
className={cn("flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all", className)}
|
|
27
|
+
{...props}
|
|
28
|
+
>
|
|
29
|
+
<div className="flex items-center">
|
|
30
|
+
{children}
|
|
31
|
+
<ChevronDownIcon className="h-4 w-4 shrink-0 bg-transparent text-muted-foreground transition-transform duration-200 [&[data-state=open]>svg]:rotate-180" />
|
|
32
|
+
</div>
|
|
33
|
+
</AccordionPrimitive.Trigger>
|
|
34
|
+
</AccordionPrimitive.Header>
|
|
35
|
+
));
|
|
36
|
+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
|
|
37
|
+
|
|
38
|
+
const AccordionContent = React.forwardRef<
|
|
39
|
+
React.ElementRef<typeof AccordionPrimitive.Content>,
|
|
40
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
|
41
|
+
>(({ className, children, ...props }, ref) => (
|
|
42
|
+
<AccordionPrimitive.Content
|
|
43
|
+
ref={ref}
|
|
44
|
+
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
|
48
|
+
</AccordionPrimitive.Content>
|
|
49
|
+
));
|
|
50
|
+
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
|
51
|
+
|
|
52
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
import { buttonVariants } from "./button";
|
|
7
|
+
import { cn } from "../../utils/cn";
|
|
8
|
+
|
|
9
|
+
const AlertDialog = AlertDialogPrimitive.Root;
|
|
10
|
+
|
|
11
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
|
12
|
+
|
|
13
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal;
|
|
14
|
+
|
|
15
|
+
const AlertDialogOverlay = React.forwardRef<
|
|
16
|
+
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
|
17
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
|
18
|
+
>(({ className, ...props }, ref) => (
|
|
19
|
+
<AlertDialogPrimitive.Overlay
|
|
20
|
+
className={cn(
|
|
21
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
24
|
+
{...props}
|
|
25
|
+
ref={ref}
|
|
26
|
+
/>
|
|
27
|
+
));
|
|
28
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
|
|
29
|
+
|
|
30
|
+
const AlertDialogContent = React.forwardRef<
|
|
31
|
+
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
32
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<AlertDialogPortal>
|
|
35
|
+
<AlertDialogOverlay />
|
|
36
|
+
<AlertDialogPrimitive.Content
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
|
40
|
+
className,
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
</AlertDialogPortal>
|
|
45
|
+
));
|
|
46
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
|
|
47
|
+
|
|
48
|
+
const AlertDialogHeader = ({
|
|
49
|
+
className,
|
|
50
|
+
...props
|
|
51
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
52
|
+
<div
|
|
53
|
+
className={cn(
|
|
54
|
+
"flex flex-col space-y-2 text-center sm:text-left",
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
AlertDialogHeader.displayName = "AlertDialogHeader";
|
|
61
|
+
|
|
62
|
+
const AlertDialogFooter = ({
|
|
63
|
+
className,
|
|
64
|
+
...props
|
|
65
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
66
|
+
<div
|
|
67
|
+
className={cn(
|
|
68
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
69
|
+
className,
|
|
70
|
+
)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
AlertDialogFooter.displayName = "AlertDialogFooter";
|
|
75
|
+
|
|
76
|
+
const AlertDialogTitle = React.forwardRef<
|
|
77
|
+
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
|
78
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
|
79
|
+
>(({ className, ...props }, ref) => (
|
|
80
|
+
<AlertDialogPrimitive.Title
|
|
81
|
+
ref={ref}
|
|
82
|
+
className={cn("text-lg font-semibold", className)}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
));
|
|
86
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
|
|
87
|
+
|
|
88
|
+
const AlertDialogDescription = React.forwardRef<
|
|
89
|
+
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
|
90
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
|
91
|
+
>(({ className, ...props }, ref) => (
|
|
92
|
+
<AlertDialogPrimitive.Description
|
|
93
|
+
ref={ref}
|
|
94
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
95
|
+
{...props}
|
|
96
|
+
/>
|
|
97
|
+
));
|
|
98
|
+
AlertDialogDescription.displayName =
|
|
99
|
+
AlertDialogPrimitive.Description.displayName;
|
|
100
|
+
|
|
101
|
+
const AlertDialogAction = React.forwardRef<
|
|
102
|
+
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
|
103
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
|
104
|
+
>(({ className, ...props }, ref) => (
|
|
105
|
+
<AlertDialogPrimitive.Action
|
|
106
|
+
ref={ref}
|
|
107
|
+
className={cn(buttonVariants(), className)}
|
|
108
|
+
{...props}
|
|
109
|
+
/>
|
|
110
|
+
));
|
|
111
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
|
|
112
|
+
|
|
113
|
+
const AlertDialogCancel = React.forwardRef<
|
|
114
|
+
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
|
115
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
|
116
|
+
>(({ className, ...props }, ref) => (
|
|
117
|
+
<AlertDialogPrimitive.Cancel
|
|
118
|
+
ref={ref}
|
|
119
|
+
className={cn(
|
|
120
|
+
buttonVariants({ variant: "outline" }),
|
|
121
|
+
"mt-2 sm:mt-0",
|
|
122
|
+
className,
|
|
123
|
+
)}
|
|
124
|
+
{...props}
|
|
125
|
+
/>
|
|
126
|
+
));
|
|
127
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
|
|
128
|
+
|
|
129
|
+
export {
|
|
130
|
+
AlertDialog,
|
|
131
|
+
AlertDialogAction,
|
|
132
|
+
AlertDialogCancel,
|
|
133
|
+
AlertDialogContent,
|
|
134
|
+
AlertDialogDescription,
|
|
135
|
+
AlertDialogFooter,
|
|
136
|
+
AlertDialogHeader,
|
|
137
|
+
AlertDialogOverlay,
|
|
138
|
+
AlertDialogPortal,
|
|
139
|
+
AlertDialogTitle,
|
|
140
|
+
AlertDialogTrigger,
|
|
141
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../../utils/cn";
|
|
5
|
+
|
|
6
|
+
const alertVariants = cva(
|
|
7
|
+
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-background text-foreground",
|
|
12
|
+
destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
variant: "default",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const Alert = React.forwardRef<
|
|
22
|
+
HTMLDivElement,
|
|
23
|
+
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
|
24
|
+
>(({ className, variant, ...props }, ref) => (
|
|
25
|
+
<div ref={ref} role="alert" className={cn(alertVariants({ variant }), className)} {...props} />
|
|
26
|
+
));
|
|
27
|
+
Alert.displayName = "Alert";
|
|
28
|
+
|
|
29
|
+
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
|
30
|
+
({ className, ...props }, ref) => (
|
|
31
|
+
<h5 ref={ref} className={cn("mb-1 font-medium leading-none tracking-tight", className)} {...props} />
|
|
32
|
+
),
|
|
33
|
+
);
|
|
34
|
+
AlertTitle.displayName = "AlertTitle";
|
|
35
|
+
|
|
36
|
+
const AlertDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
|
37
|
+
({ className, ...props }, ref) => (
|
|
38
|
+
<div ref={ref} className={cn("text-sm [&_p]:leading-relaxed", className)} {...props} />
|
|
39
|
+
),
|
|
40
|
+
);
|
|
41
|
+
AlertDescription.displayName = "AlertDescription";
|
|
42
|
+
|
|
43
|
+
export { Alert, AlertDescription, AlertTitle };
|