@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.
Files changed (303) hide show
  1. package/dist/BlockNoteEditor-VFWG6LXI.js.map +1 -1
  2. package/dist/JsonApiRequest-ZZLSP26T.js.map +1 -1
  3. package/dist/atoms/index.js.map +1 -1
  4. package/dist/chunk-2K3Q24UF.js.map +1 -1
  5. package/dist/chunk-3FBCC4G3.js.map +1 -1
  6. package/dist/chunk-4HCRAOS5.js.map +1 -1
  7. package/dist/chunk-6GKHCVF6.js.map +1 -1
  8. package/dist/chunk-7QVYU63E.js.map +1 -1
  9. package/dist/chunk-A5DDIABK.js.map +1 -1
  10. package/dist/chunk-AWONBQQP.js.map +1 -1
  11. package/dist/chunk-CXQOWQSY.js.map +1 -1
  12. package/dist/chunk-DO2HLAZO.js.map +1 -1
  13. package/dist/chunk-EFJEWLRL.js.map +1 -1
  14. package/dist/chunk-FY4SXJGU.js.map +1 -1
  15. package/dist/chunk-H6FMOA6B.js.map +1 -1
  16. package/dist/chunk-I2REI7OA.js.map +1 -1
  17. package/dist/chunk-IBS6NI7D.js.map +1 -1
  18. package/dist/chunk-J4Q36PMP.js.map +1 -1
  19. package/dist/chunk-JC3WJK65.js.map +1 -1
  20. package/dist/chunk-LXKSUWAV.js.map +1 -1
  21. package/dist/chunk-RAF7PNLG.js.map +1 -1
  22. package/dist/chunk-RUR22SVM.js.map +1 -1
  23. package/dist/chunk-TEGF6ZWG.js.map +1 -1
  24. package/dist/chunk-TMVHSY3Y.js.map +1 -1
  25. package/dist/chunk-V2JJPI7N.js.map +1 -1
  26. package/dist/client/index.js.map +1 -1
  27. package/dist/components/index.js.map +1 -1
  28. package/dist/contexts/index.js.map +1 -1
  29. package/dist/core/index.js.map +1 -1
  30. package/dist/features/index.js.map +1 -1
  31. package/dist/hooks/index.js.map +1 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/interfaces/index.js.map +1 -1
  34. package/dist/permissions/index.js.map +1 -1
  35. package/dist/request-QFS7NEIE.js.map +1 -1
  36. package/dist/request-ZYY6RI5X.js.map +1 -1
  37. package/dist/roles/index.js.map +1 -1
  38. package/dist/server/index.js.map +1 -1
  39. package/dist/shadcnui/index.js.map +1 -1
  40. package/dist/token-MJMC26ON.js.map +1 -1
  41. package/dist/token-UYE7CV6X.js.map +1 -1
  42. package/dist/utils/index.js.map +1 -1
  43. package/package.json +6 -1
  44. package/src/atoms/index.ts +1 -0
  45. package/src/atoms/recentPagesAtom.ts +10 -0
  46. package/src/client/context/JsonApiContext.ts +61 -0
  47. package/src/client/context/JsonApiProvider.tsx +27 -0
  48. package/src/client/context/index.ts +2 -0
  49. package/src/client/hooks/index.ts +3 -0
  50. package/src/client/hooks/useJsonApiGet.ts +188 -0
  51. package/src/client/hooks/useJsonApiMutation.ts +193 -0
  52. package/src/client/hooks/useRehydration.ts +47 -0
  53. package/src/client/index.ts +11 -0
  54. package/src/client/request.ts +97 -0
  55. package/src/client/token.ts +10 -0
  56. package/src/components/containers/PageContainer.tsx +15 -0
  57. package/src/components/containers/ReactMarkdownContainer.tsx +119 -0
  58. package/src/components/containers/TabsContainer.tsx +93 -0
  59. package/src/components/containers/index.ts +3 -0
  60. package/src/components/contents/AttributeElement.tsx +20 -0
  61. package/src/components/contents/index.ts +1 -0
  62. package/src/components/details/AllowedUsersDetails.tsx +23 -0
  63. package/src/components/details/index.ts +1 -0
  64. package/src/components/editors/BlockNoteDiffInlineContent.tsx +152 -0
  65. package/src/components/editors/BlockNoteEditor.tsx +404 -0
  66. package/src/components/editors/BlockNoteEditorContainer.tsx +13 -0
  67. package/src/components/editors/BlockNoteEditorFormattingToolbar.tsx +38 -0
  68. package/src/components/editors/index.ts +1 -0
  69. package/src/components/errors/ErrorDetails.tsx +41 -0
  70. package/src/components/errors/errorToast.ts +9 -0
  71. package/src/components/errors/index.ts +2 -0
  72. package/src/components/forms/CommonAssociationForm.tsx +162 -0
  73. package/src/components/forms/CommonDeleter.tsx +94 -0
  74. package/src/components/forms/CommonEditorButtons.tsx +30 -0
  75. package/src/components/forms/CommonEditorHeader.tsx +35 -0
  76. package/src/components/forms/CommonEditorTrigger.tsx +26 -0
  77. package/src/components/forms/DatePickerPopover.tsx +219 -0
  78. package/src/components/forms/DateRangeSelector.tsx +110 -0
  79. package/src/components/forms/FileUploader.tsx +324 -0
  80. package/src/components/forms/FormCheckbox.tsx +66 -0
  81. package/src/components/forms/FormContainerGeneric.tsx +39 -0
  82. package/src/components/forms/FormDate.tsx +247 -0
  83. package/src/components/forms/FormDateTime.tsx +231 -0
  84. package/src/components/forms/FormInput.tsx +110 -0
  85. package/src/components/forms/FormPassword.tsx +54 -0
  86. package/src/components/forms/FormPlaceAutocomplete.tsx +286 -0
  87. package/src/components/forms/FormSelect.tsx +72 -0
  88. package/src/components/forms/FormSlider.tsx +51 -0
  89. package/src/components/forms/FormSwitch.tsx +25 -0
  90. package/src/components/forms/FormTextarea.tsx +44 -0
  91. package/src/components/forms/MultiFileUploader.tsx +107 -0
  92. package/src/components/forms/PasswordInput.tsx +47 -0
  93. package/src/components/forms/index.ts +21 -0
  94. package/src/components/index.ts +11 -0
  95. package/src/components/navigations/Breadcrumb.tsx +83 -0
  96. package/src/components/navigations/ContentTitle.tsx +39 -0
  97. package/src/components/navigations/Header.tsx +27 -0
  98. package/src/components/navigations/ModeToggleSwitch.tsx +25 -0
  99. package/src/components/navigations/PageSection.tsx +64 -0
  100. package/src/components/navigations/RecentPagesNavigator.tsx +52 -0
  101. package/src/components/navigations/index.ts +6 -0
  102. package/src/components/pages/PageContainerContentDetails.tsx +76 -0
  103. package/src/components/pages/PageContentContainer.tsx +31 -0
  104. package/src/components/pages/index.ts +2 -0
  105. package/src/components/tables/ContentListTable.tsx +165 -0
  106. package/src/components/tables/ContentTableSearch.tsx +105 -0
  107. package/src/components/tables/cells/cell.component.tsx +18 -0
  108. package/src/components/tables/cells/cell.date.tsx +16 -0
  109. package/src/components/tables/cells/cell.id.tsx +27 -0
  110. package/src/components/tables/cells/cell.link.tsx +18 -0
  111. package/src/components/tables/cells/cell.text.tsx +12 -0
  112. package/src/components/tables/cells/cell.url.tsx +13 -0
  113. package/src/components/tables/cells/index.ts +5 -0
  114. package/src/components/tables/index.ts +3 -0
  115. package/src/contexts/SharedContext.tsx +35 -0
  116. package/src/contexts/index.ts +2 -0
  117. package/src/core/abstracts/AbstractApiData.ts +138 -0
  118. package/src/core/abstracts/AbstractService.ts +263 -0
  119. package/src/core/abstracts/index.ts +2 -0
  120. package/src/core/endpoint/EndpointCreator.ts +97 -0
  121. package/src/core/endpoint/index.ts +1 -0
  122. package/src/core/factories/JsonApiDataFactory.ts +12 -0
  123. package/src/core/factories/RehydrationFactory.ts +30 -0
  124. package/src/core/factories/index.ts +2 -0
  125. package/src/core/fields/FieldSelector.ts +15 -0
  126. package/src/core/fields/index.ts +1 -0
  127. package/src/core/index.ts +20 -0
  128. package/src/core/interfaces/ApiData.ts +8 -0
  129. package/src/core/interfaces/ApiDataInterface.ts +15 -0
  130. package/src/core/interfaces/ApiRequestDataTypeInterface.ts +14 -0
  131. package/src/core/interfaces/ApiResponseInterface.ts +17 -0
  132. package/src/core/interfaces/JsonApiHydratedDataInterface.ts +5 -0
  133. package/src/core/interfaces/index.ts +5 -0
  134. package/src/core/registry/DataClassRegistry.ts +51 -0
  135. package/src/core/registry/ModuleRegistrar.ts +43 -0
  136. package/src/core/registry/ModuleRegistry.ts +64 -0
  137. package/src/core/registry/index.ts +3 -0
  138. package/src/core/utils/index.ts +2 -0
  139. package/src/core/utils/rehydrate.ts +24 -0
  140. package/src/core/utils/translateResponse.ts +125 -0
  141. package/src/features/auth/auth.module.ts +9 -0
  142. package/src/features/auth/config.ts +57 -0
  143. package/src/features/auth/data/auth.interface.ts +31 -0
  144. package/src/features/auth/data/auth.service.ts +159 -0
  145. package/src/features/auth/data/auth.ts +54 -0
  146. package/src/features/auth/data/index.ts +3 -0
  147. package/src/features/auth/index.ts +3 -0
  148. package/src/features/company/company.module.ts +10 -0
  149. package/src/features/company/data/company.fields.ts +6 -0
  150. package/src/features/company/data/company.interface.ts +28 -0
  151. package/src/features/company/data/company.service.ts +73 -0
  152. package/src/features/company/data/company.ts +104 -0
  153. package/src/features/company/data/index.ts +4 -0
  154. package/src/features/company/index.ts +2 -0
  155. package/src/features/content/content.module.ts +20 -0
  156. package/src/features/content/data/content.fields.ts +13 -0
  157. package/src/features/content/data/content.interface.ts +23 -0
  158. package/src/features/content/data/content.service.ts +75 -0
  159. package/src/features/content/data/content.ts +85 -0
  160. package/src/features/content/data/index.ts +4 -0
  161. package/src/features/content/index.ts +2 -0
  162. package/src/features/feature/components/forms/FormFeatures.tsx +149 -0
  163. package/src/features/feature/components/index.ts +1 -0
  164. package/src/features/feature/data/feature.interface.ts +9 -0
  165. package/src/features/feature/data/feature.service.ts +19 -0
  166. package/src/features/feature/data/feature.ts +33 -0
  167. package/src/features/feature/data/index.ts +3 -0
  168. package/src/features/feature/feature.module.ts +10 -0
  169. package/src/features/feature/index.ts +3 -0
  170. package/src/features/index.ts +12 -0
  171. package/src/features/module/data/index.ts +2 -0
  172. package/src/features/module/data/module.interface.ts +12 -0
  173. package/src/features/module/data/module.ts +42 -0
  174. package/src/features/module/index.ts +2 -0
  175. package/src/features/module/module.module.ts +10 -0
  176. package/src/features/notification/data/index.ts +4 -0
  177. package/src/features/notification/data/notification.fields.ts +8 -0
  178. package/src/features/notification/data/notification.interface.ts +14 -0
  179. package/src/features/notification/data/notification.service.ts +34 -0
  180. package/src/features/notification/data/notification.ts +51 -0
  181. package/src/features/notification/index.ts +2 -0
  182. package/src/features/notification/notification.module.ts +10 -0
  183. package/src/features/push/data/index.ts +3 -0
  184. package/src/features/push/data/push.interface.ts +8 -0
  185. package/src/features/push/data/push.service.ts +17 -0
  186. package/src/features/push/data/push.ts +18 -0
  187. package/src/features/push/index.ts +2 -0
  188. package/src/features/push/push.module.ts +10 -0
  189. package/src/features/role/data/index.ts +4 -0
  190. package/src/features/role/data/role.fields.ts +8 -0
  191. package/src/features/role/data/role.interface.ts +16 -0
  192. package/src/features/role/data/role.service.ts +117 -0
  193. package/src/features/role/data/role.ts +62 -0
  194. package/src/features/role/index.ts +2 -0
  195. package/src/features/role/role.module.ts +10 -0
  196. package/src/features/s3/data/index.ts +3 -0
  197. package/src/features/s3/data/s3.interface.ts +11 -0
  198. package/src/features/s3/data/s3.service.ts +30 -0
  199. package/src/features/s3/data/s3.ts +60 -0
  200. package/src/features/s3/index.ts +2 -0
  201. package/src/features/s3/s3.module.ts +10 -0
  202. package/src/features/search/index.ts +1 -0
  203. package/src/features/search/interfaces/index.ts +1 -0
  204. package/src/features/search/interfaces/search.result.interface.ts +3 -0
  205. package/src/features/user/author.module.ts +10 -0
  206. package/src/features/user/components/index.ts +2 -0
  207. package/src/features/user/components/lists/ContributorsList.tsx +41 -0
  208. package/src/features/user/components/lists/index.ts +1 -0
  209. package/src/features/user/components/widgets/UserAvatar.tsx +86 -0
  210. package/src/features/user/components/widgets/index.ts +1 -0
  211. package/src/features/user/contexts/CurrentUserContext.tsx +156 -0
  212. package/src/features/user/contexts/index.ts +1 -0
  213. package/src/features/user/data/index.ts +4 -0
  214. package/src/features/user/data/user.fields.ts +8 -0
  215. package/src/features/user/data/user.interface.ts +41 -0
  216. package/src/features/user/data/user.service.ts +246 -0
  217. package/src/features/user/data/user.ts +162 -0
  218. package/src/features/user/index.ts +4 -0
  219. package/src/features/user/user.module.ts +21 -0
  220. package/src/hooks/TableGeneratorRegistry.ts +53 -0
  221. package/src/hooks/index.ts +33 -0
  222. package/src/hooks/types.ts +35 -0
  223. package/src/hooks/url.rewriter.ts +22 -0
  224. package/src/hooks/useCustomD3Graph.tsx +705 -0
  225. package/src/hooks/useDataListRetriever.ts +349 -0
  226. package/src/hooks/useDebounce.ts +33 -0
  227. package/src/hooks/usePageUrlGenerator.ts +50 -0
  228. package/src/hooks/useTableGenerator.ts +16 -0
  229. package/src/i18n/config.ts +73 -0
  230. package/src/i18n/index.ts +18 -0
  231. package/src/index.ts +16 -0
  232. package/src/interfaces/breadcrumb.item.data.interface.ts +4 -0
  233. package/src/interfaces/d3.link.interface.ts +7 -0
  234. package/src/interfaces/d3.node.interface.ts +12 -0
  235. package/src/interfaces/index.ts +3 -0
  236. package/src/permissions/check.ts +127 -0
  237. package/src/permissions/index.ts +2 -0
  238. package/src/permissions/types.ts +109 -0
  239. package/src/roles/config.ts +46 -0
  240. package/src/roles/index.ts +1 -0
  241. package/src/server/cache.ts +28 -0
  242. package/src/server/index.ts +3 -0
  243. package/src/server/request.ts +113 -0
  244. package/src/server/token.ts +10 -0
  245. package/src/shadcnui/custom/kanban.tsx +1001 -0
  246. package/src/shadcnui/custom/link.tsx +18 -0
  247. package/src/shadcnui/custom/multi-select.tsx +382 -0
  248. package/src/shadcnui/index.ts +49 -0
  249. package/src/shadcnui/ui/accordion.tsx +52 -0
  250. package/src/shadcnui/ui/alert-dialog.tsx +141 -0
  251. package/src/shadcnui/ui/alert.tsx +43 -0
  252. package/src/shadcnui/ui/avatar.tsx +50 -0
  253. package/src/shadcnui/ui/badge.tsx +40 -0
  254. package/src/shadcnui/ui/breadcrumb.tsx +115 -0
  255. package/src/shadcnui/ui/button.tsx +51 -0
  256. package/src/shadcnui/ui/calendar.tsx +73 -0
  257. package/src/shadcnui/ui/card.tsx +43 -0
  258. package/src/shadcnui/ui/carousel.tsx +225 -0
  259. package/src/shadcnui/ui/chart.tsx +320 -0
  260. package/src/shadcnui/ui/checkbox.tsx +29 -0
  261. package/src/shadcnui/ui/collapsible.tsx +11 -0
  262. package/src/shadcnui/ui/command.tsx +155 -0
  263. package/src/shadcnui/ui/context-menu.tsx +179 -0
  264. package/src/shadcnui/ui/dialog.tsx +96 -0
  265. package/src/shadcnui/ui/drawer.tsx +89 -0
  266. package/src/shadcnui/ui/dropdown-menu.tsx +205 -0
  267. package/src/shadcnui/ui/form.tsx +138 -0
  268. package/src/shadcnui/ui/hover-card.tsx +29 -0
  269. package/src/shadcnui/ui/input.tsx +21 -0
  270. package/src/shadcnui/ui/label.tsx +26 -0
  271. package/src/shadcnui/ui/navigation-menu.tsx +168 -0
  272. package/src/shadcnui/ui/popover.tsx +33 -0
  273. package/src/shadcnui/ui/progress.tsx +25 -0
  274. package/src/shadcnui/ui/radio-group.tsx +37 -0
  275. package/src/shadcnui/ui/resizable.tsx +47 -0
  276. package/src/shadcnui/ui/scroll-area.tsx +40 -0
  277. package/src/shadcnui/ui/select.tsx +164 -0
  278. package/src/shadcnui/ui/separator.tsx +28 -0
  279. package/src/shadcnui/ui/sheet.tsx +139 -0
  280. package/src/shadcnui/ui/sidebar.tsx +677 -0
  281. package/src/shadcnui/ui/skeleton.tsx +13 -0
  282. package/src/shadcnui/ui/slider.tsx +25 -0
  283. package/src/shadcnui/ui/sonner.tsx +25 -0
  284. package/src/shadcnui/ui/switch.tsx +31 -0
  285. package/src/shadcnui/ui/table.tsx +120 -0
  286. package/src/shadcnui/ui/tabs.tsx +55 -0
  287. package/src/shadcnui/ui/textarea.tsx +24 -0
  288. package/src/shadcnui/ui/toggle.tsx +39 -0
  289. package/src/shadcnui/ui/tooltip.tsx +61 -0
  290. package/src/unified/JsonApiRequest.ts +325 -0
  291. package/src/unified/index.ts +1 -0
  292. package/src/utils/blocknote-diff.util.ts +815 -0
  293. package/src/utils/blocknote-word-diff-renderer.util.ts +413 -0
  294. package/src/utils/cn.ts +6 -0
  295. package/src/utils/compose-refs.ts +61 -0
  296. package/src/utils/date-formatter.ts +53 -0
  297. package/src/utils/exists.ts +7 -0
  298. package/src/utils/index.ts +15 -0
  299. package/src/utils/schemas/entity.object.schema.ts +8 -0
  300. package/src/utils/schemas/index.ts +2 -0
  301. package/src/utils/schemas/user.object.schema.ts +9 -0
  302. package/src/utils/table-options.ts +67 -0
  303. 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 };