@carlonicora/nextjs-jsonapi 1.16.0 → 1.18.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 (202) hide show
  1. package/README.md +1 -1
  2. package/dist/ApiData-DPKNfY-9.d.mts +10 -0
  3. package/dist/ApiData-DPKNfY-9.d.ts +10 -0
  4. package/dist/ApiRequestDataTypeInterface-DIEOFn9s.d.mts +40 -0
  5. package/dist/ApiRequestDataTypeInterface-DIEOFn9s.d.ts +40 -0
  6. package/dist/{ApiResponseInterface-BvWIeLkq.d.ts → ApiResponseInterface-BKyod24U.d.ts} +2 -11
  7. package/dist/{ApiResponseInterface-CAbw0sv7.d.mts → ApiResponseInterface-Dqvu09tz.d.mts} +2 -11
  8. package/dist/{BlockNoteEditor-HFX7Z5BQ.mjs → BlockNoteEditor-6TWTNHNZ.mjs} +7 -6
  9. package/dist/{BlockNoteEditor-HFX7Z5BQ.mjs.map → BlockNoteEditor-6TWTNHNZ.mjs.map} +1 -1
  10. package/dist/{BlockNoteEditor-MBFDWP7X.js → BlockNoteEditor-C3WWGGT6.js} +17 -16
  11. package/dist/BlockNoteEditor-C3WWGGT6.js.map +1 -0
  12. package/dist/JsonApiContext-Bsm_Q2oe.d.mts +41 -0
  13. package/dist/JsonApiContext-Bsm_Q2oe.d.ts +41 -0
  14. package/dist/JsonApiRequest-54ZBO7WQ.js +24 -0
  15. package/dist/{JsonApiRequest-45CLE65I.js.map → JsonApiRequest-54ZBO7WQ.js.map} +1 -1
  16. package/dist/{JsonApiRequest-6IPS3DZJ.mjs → JsonApiRequest-XWQWTFEQ.mjs} +2 -2
  17. package/dist/chunk-3EPNHTMH.js +26 -0
  18. package/dist/chunk-3EPNHTMH.js.map +1 -0
  19. package/dist/{chunk-BCKYJQ3K.mjs → chunk-3VM3WAOV.mjs} +1 -1
  20. package/dist/{chunk-ONB2DAIV.js → chunk-6U6QCSJK.js} +4224 -2775
  21. package/dist/chunk-6U6QCSJK.js.map +1 -0
  22. package/dist/{chunk-R5QSSISB.js → chunk-7DTKRMYW.js} +21 -14
  23. package/dist/chunk-7DTKRMYW.js.map +1 -0
  24. package/dist/{chunk-BCQSE3EU.mjs → chunk-KUFWHMMY.mjs} +8 -8
  25. package/dist/{chunk-POKIJ56Q.mjs → chunk-KX7YG6LY.mjs} +22 -15
  26. package/dist/chunk-KX7YG6LY.mjs.map +1 -0
  27. package/dist/{chunk-GPGJNTHP.js → chunk-LI6CPNJI.js} +1 -1
  28. package/dist/{chunk-GPGJNTHP.js.map → chunk-LI6CPNJI.js.map} +1 -1
  29. package/dist/{chunk-2AZLCF6D.js → chunk-UYY34W7R.js} +28 -28
  30. package/dist/{chunk-2AZLCF6D.js.map → chunk-UYY34W7R.js.map} +1 -1
  31. package/dist/{chunk-5RAUCUAA.mjs → chunk-UZDAPWJG.mjs} +5645 -4196
  32. package/dist/chunk-UZDAPWJG.mjs.map +1 -0
  33. package/dist/chunk-VOXD3ZLY.mjs +26 -0
  34. package/dist/chunk-VOXD3ZLY.mjs.map +1 -0
  35. package/dist/client/index.d.mts +11 -45
  36. package/dist/client/index.d.ts +11 -45
  37. package/dist/client/index.js +9 -7
  38. package/dist/client/index.js.map +1 -1
  39. package/dist/client/index.mjs +11 -9
  40. package/dist/components/index.d.mts +302 -388
  41. package/dist/components/index.d.ts +302 -388
  42. package/dist/components/index.js +31 -6
  43. package/dist/components/index.js.map +1 -1
  44. package/dist/components/index.mjs +40 -15
  45. package/dist/{config-DEaUbBqR.d.ts → config--nwiW74Z.d.ts} +1 -1
  46. package/dist/{config-CWsTwnsK.d.mts → config-BKSQmUWU.d.mts} +1 -1
  47. package/dist/{content.interface-D_4b4RQt.d.ts → content.interface-4VICFRA0.d.ts} +2 -1
  48. package/dist/{content.interface-Dk4UZcJM.d.mts → content.interface-CFc97-Cj.d.mts} +2 -1
  49. package/dist/contexts/index.d.mts +3 -2
  50. package/dist/contexts/index.d.ts +3 -2
  51. package/dist/contexts/index.js +7 -6
  52. package/dist/contexts/index.js.map +1 -1
  53. package/dist/contexts/index.mjs +6 -5
  54. package/dist/core/index.d.mts +11 -8
  55. package/dist/core/index.d.ts +11 -8
  56. package/dist/core/index.js +4 -4
  57. package/dist/core/index.js.map +1 -1
  58. package/dist/core/index.mjs +3 -3
  59. package/dist/index.d.mts +15 -11
  60. package/dist/index.d.ts +15 -11
  61. package/dist/index.js +5 -5
  62. package/dist/index.js.map +1 -1
  63. package/dist/index.mjs +6 -6
  64. package/dist/{notification.interface-BllkURRm.d.ts → notification.interface-BGaPiCUM.d.mts} +2 -40
  65. package/dist/{notification.interface-BllkURRm.d.mts → notification.interface-CqwaOIgM.d.ts} +2 -40
  66. package/dist/{s3.service-BEfGqho0.d.ts → s3.service-BYs88XEE.d.ts} +3 -2
  67. package/dist/{s3.service-DIQRYe93.d.mts → s3.service-C0BjOdvn.d.mts} +3 -2
  68. package/dist/scripts/generate-web-module/templates/components/editor.template.d.ts.map +1 -1
  69. package/dist/scripts/generate-web-module/templates/components/editor.template.js +20 -6
  70. package/dist/scripts/generate-web-module/templates/components/editor.template.js.map +1 -1
  71. package/dist/scripts/generate-web-module/templates/components/selector.template.d.ts.map +1 -1
  72. package/dist/scripts/generate-web-module/templates/components/selector.template.js +45 -48
  73. package/dist/scripts/generate-web-module/templates/components/selector.template.js.map +1 -1
  74. package/dist/server/index.d.mts +6 -4
  75. package/dist/server/index.d.ts +6 -4
  76. package/dist/server/index.js +13 -13
  77. package/dist/server/index.js.map +1 -1
  78. package/dist/server/index.mjs +3 -3
  79. package/dist/{stripe-subscription.interface-C63L6hVg.d.mts → stripe-subscription.interface-B-TM40Io.d.ts} +1 -1
  80. package/dist/{stripe-subscription.interface-CUvNDvw5.d.ts → stripe-subscription.interface-DDxnpj0F.d.mts} +1 -1
  81. package/dist/testing/index.d.mts +338 -0
  82. package/dist/testing/index.d.ts +338 -0
  83. package/dist/testing/index.js +323 -0
  84. package/dist/testing/index.js.map +1 -0
  85. package/dist/testing/index.mjs +323 -0
  86. package/dist/testing/index.mjs.map +1 -0
  87. package/dist/{useSocket-BpenBR2z.d.mts → useSocket-BNj9PrRw.d.mts} +1 -1
  88. package/dist/{useSocket-D-QYA0Sr.d.ts → useSocket-Dwt8cz1x.d.ts} +1 -1
  89. package/package.json +26 -27
  90. package/scripts/generate-web-module/templates/components/editor.template.ts +20 -6
  91. package/scripts/generate-web-module/templates/components/selector.template.ts +45 -48
  92. package/src/client/hooks/__tests__/useJsonApiGet.test.tsx +229 -0
  93. package/src/client/hooks/__tests__/useJsonApiMutation.test.tsx +348 -0
  94. package/src/client/hooks/__tests__/useRehydration.test.ts +188 -0
  95. package/src/components/forms/CommonDeleter.tsx +2 -2
  96. package/src/components/forms/CommonEditorTrigger.tsx +3 -3
  97. package/src/components/forms/DatePickerPopover.tsx +3 -1
  98. package/src/components/forms/DateRangeSelector.tsx +1 -1
  99. package/src/components/forms/FormCheckbox.tsx +1 -1
  100. package/src/components/forms/FormDate.tsx +3 -1
  101. package/src/components/forms/FormDateTime.tsx +5 -3
  102. package/src/components/forms/FormSelect.tsx +1 -1
  103. package/src/components/forms/FormSlider.tsx +4 -1
  104. package/src/components/forms/__tests__/FormCheckbox.test.tsx +242 -0
  105. package/src/components/forms/__tests__/FormDate.test.tsx +216 -0
  106. package/src/components/forms/__tests__/FormInput.test.tsx +292 -0
  107. package/src/components/forms/__tests__/FormSelect.test.tsx +177 -0
  108. package/src/components/navigations/RecentPagesNavigator.tsx +2 -2
  109. package/src/components/tables/ContentListTable.tsx +3 -3
  110. package/src/components/tables/__tests__/ContentListTable.test.tsx +411 -0
  111. package/src/core/endpoint/__tests__/EndpointCreator.test.ts +168 -0
  112. package/src/core/factories/__tests__/JsonApiDataFactory.test.ts +109 -0
  113. package/src/core/factories/__tests__/RehydrationFactory.test.ts +151 -0
  114. package/src/core/registry/__tests__/DataClassRegistry.test.ts +136 -0
  115. package/src/core/registry/__tests__/ModuleRegistrar.test.ts +159 -0
  116. package/src/features/auth/components/details/LandingComponent.tsx +14 -12
  117. package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +2 -2
  118. package/src/features/company/components/forms/CompanyConfigurationEditor.tsx +2 -2
  119. package/src/features/company/components/forms/CompanyDeleter.tsx +1 -1
  120. package/src/features/content/components/lists/ContentsList.tsx +1 -1
  121. package/src/features/notification/components/lists/NotificationsList.tsx +1 -1
  122. package/src/features/notification/components/modals/NotificationModal.tsx +2 -2
  123. package/src/features/role/components/forms/FormRoles.tsx +1 -1
  124. package/src/features/user/components/forms/UserEditor.tsx +2 -2
  125. package/src/features/user/components/forms/UserReactivator.tsx +1 -1
  126. package/src/features/user/components/forms/UserResentInvitationEmail.tsx +2 -2
  127. package/src/features/user/components/widgets/UserAvatar.tsx +37 -31
  128. package/src/features/user/components/widgets/UserSearchPopover.tsx +1 -1
  129. package/src/hooks/__tests__/useDataListRetriever.test.ts +321 -0
  130. package/src/hooks/__tests__/useDebounce.test.ts +170 -0
  131. package/src/hooks/use-mobile.ts +1 -0
  132. package/src/index.ts +4 -1
  133. package/src/lib/utils.ts +2 -0
  134. package/src/login/config.ts +27 -0
  135. package/src/login/index.ts +2 -0
  136. package/src/shadcnui/custom/multi-select.tsx +10 -21
  137. package/src/shadcnui/ui/accordion.tsx +64 -42
  138. package/src/shadcnui/ui/alert-dialog.tsx +142 -108
  139. package/src/shadcnui/ui/alert.tsx +64 -35
  140. package/src/shadcnui/ui/avatar.tsx +106 -50
  141. package/src/shadcnui/ui/badge.tsx +34 -26
  142. package/src/shadcnui/ui/breadcrumb.tsx +103 -92
  143. package/src/shadcnui/ui/button.tsx +30 -30
  144. package/src/shadcnui/ui/calendar.tsx +192 -50
  145. package/src/shadcnui/ui/card.tsx +94 -43
  146. package/src/shadcnui/ui/carousel.tsx +220 -201
  147. package/src/shadcnui/ui/chart.tsx +244 -190
  148. package/src/shadcnui/ui/checkbox.tsx +25 -25
  149. package/src/shadcnui/ui/collapsible.tsx +10 -4
  150. package/src/shadcnui/ui/combobox.tsx +292 -0
  151. package/src/shadcnui/ui/command.tsx +158 -126
  152. package/src/shadcnui/ui/context-menu.tsx +242 -164
  153. package/src/shadcnui/ui/dialog.tsx +125 -70
  154. package/src/shadcnui/ui/drawer.tsx +106 -70
  155. package/src/shadcnui/ui/dropdown-menu.tsx +231 -182
  156. package/src/shadcnui/ui/field.tsx +227 -0
  157. package/src/shadcnui/ui/hover-card.tsx +45 -23
  158. package/src/shadcnui/ui/input-group.tsx +149 -0
  159. package/src/shadcnui/ui/input-otp.tsx +19 -9
  160. package/src/shadcnui/ui/input.tsx +4 -5
  161. package/src/shadcnui/ui/label.tsx +16 -22
  162. package/src/shadcnui/ui/navigation-menu.tsx +44 -49
  163. package/src/shadcnui/ui/popover.tsx +81 -24
  164. package/src/shadcnui/ui/progress.tsx +77 -22
  165. package/src/shadcnui/ui/radio-group.tsx +30 -28
  166. package/src/shadcnui/ui/resizable.tsx +23 -17
  167. package/src/shadcnui/ui/scroll-area.tsx +50 -35
  168. package/src/shadcnui/ui/select.tsx +163 -135
  169. package/src/shadcnui/ui/separator.tsx +5 -8
  170. package/src/shadcnui/ui/sheet.tsx +40 -50
  171. package/src/shadcnui/ui/sidebar.tsx +317 -271
  172. package/src/shadcnui/ui/skeleton.tsx +2 -2
  173. package/src/shadcnui/ui/slider.tsx +60 -21
  174. package/src/shadcnui/ui/sonner.tsx +25 -1
  175. package/src/shadcnui/ui/switch.tsx +31 -24
  176. package/src/shadcnui/ui/table.tsx +84 -103
  177. package/src/shadcnui/ui/tabs.tsx +82 -55
  178. package/src/shadcnui/ui/textarea.tsx +15 -21
  179. package/src/shadcnui/ui/toggle.tsx +26 -21
  180. package/src/shadcnui/ui/tooltip.tsx +33 -24
  181. package/src/testing/factories/createMockApiData.ts +143 -0
  182. package/src/testing/factories/createMockModule.ts +32 -0
  183. package/src/testing/factories/createMockResponse.ts +88 -0
  184. package/src/testing/factories/createMockService.ts +76 -0
  185. package/src/testing/index.ts +56 -0
  186. package/src/testing/matchers/jsonApiMatchers.ts +172 -0
  187. package/src/testing/providers/MockJsonApiProvider.tsx +58 -0
  188. package/src/testing/utils/renderWithProviders.tsx +76 -0
  189. package/src/utils/__tests__/date-formatter.test.ts +161 -0
  190. package/src/utils/__tests__/exists.test.ts +100 -0
  191. package/src/utils/cn.test.ts +44 -0
  192. package/dist/BlockNoteEditor-MBFDWP7X.js.map +0 -1
  193. package/dist/JsonApiRequest-45CLE65I.js +0 -24
  194. package/dist/chunk-5RAUCUAA.mjs.map +0 -1
  195. package/dist/chunk-ONB2DAIV.js.map +0 -1
  196. package/dist/chunk-POKIJ56Q.mjs.map +0 -1
  197. package/dist/chunk-R5QSSISB.js.map +0 -1
  198. package/src/discord/config.ts +0 -15
  199. package/src/discord/index.ts +0 -1
  200. /package/dist/{JsonApiRequest-6IPS3DZJ.mjs.map → JsonApiRequest-XWQWTFEQ.mjs.map} +0 -0
  201. /package/dist/{chunk-BCKYJQ3K.mjs.map → chunk-3VM3WAOV.mjs.map} +0 -0
  202. /package/dist/{chunk-BCQSE3EU.mjs.map → chunk-KUFWHMMY.mjs.map} +0 -0
@@ -1,39 +1,44 @@
1
- "use client";
1
+ "use client"
2
2
 
3
- import * as TogglePrimitive from "@radix-ui/react-toggle";
4
- import { cva, type VariantProps } from "class-variance-authority";
5
- import * as React from "react";
3
+ import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
4
+ import { cva, type VariantProps } from "class-variance-authority"
6
5
 
7
- import { cn } from "../../utils/cn";
6
+ import { cn } from "@/lib/utils"
8
7
 
9
8
  const toggleVariants = cva(
10
- "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
9
+ "hover:text-foreground aria-pressed:bg-muted focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[state=on]:bg-muted gap-1 rounded-md text-xs font-medium transition-all [&_svg:not([class*='size-'])]:size-3.5 group/toggle hover:bg-muted inline-flex items-center justify-center whitespace-nowrap outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
11
10
  {
12
11
  variants: {
13
12
  variant: {
14
13
  default: "bg-transparent",
15
- outline: "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
14
+ outline: "border-input hover:bg-muted border bg-transparent",
16
15
  },
17
16
  size: {
18
- default: "h-9 px-2 min-w-9",
19
- sm: "h-8 px-1.5 min-w-8",
20
- lg: "h-10 px-2.5 min-w-10",
17
+ default: "h-7 min-w-7 px-2",
18
+ sm: "h-6 min-w-6 rounded-[min(var(--radius-md),8px)] px-1.5 text-[0.625rem] [&_svg:not([class*='size-'])]:size-3",
19
+ lg: "h-8 min-w-8 px-2",
21
20
  },
22
21
  },
23
22
  defaultVariants: {
24
23
  variant: "default",
25
24
  size: "default",
26
25
  },
27
- },
28
- );
26
+ }
27
+ )
29
28
 
30
- const Toggle = React.forwardRef<
31
- React.ElementRef<typeof TogglePrimitive.Root>,
32
- React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>
33
- >(({ className, variant, size, ...props }, ref) => (
34
- <TogglePrimitive.Root ref={ref} className={cn(toggleVariants({ variant, size, className }))} {...props} />
35
- ));
29
+ function Toggle({
30
+ className,
31
+ variant = "default",
32
+ size = "default",
33
+ ...props
34
+ }: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {
35
+ return (
36
+ <TogglePrimitive
37
+ data-slot="toggle"
38
+ className={cn(toggleVariants({ variant, size, className }))}
39
+ {...props}
40
+ />
41
+ )
42
+ }
36
43
 
37
- Toggle.displayName = TogglePrimitive.Root.displayName;
38
-
39
- export { Toggle, toggleVariants };
44
+ export { Toggle, toggleVariants }
@@ -1,26 +1,23 @@
1
1
  "use client"
2
2
 
3
- import * as React from "react"
4
- import * as TooltipPrimitive from "@radix-ui/react-tooltip"
3
+ import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
5
4
 
6
- import { cn } from "../../utils/cn"
5
+ import { cn } from "@/lib/utils"
7
6
 
8
7
  function TooltipProvider({
9
- delayDuration = 0,
8
+ delay = 0,
10
9
  ...props
11
- }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
10
+ }: TooltipPrimitive.Provider.Props) {
12
11
  return (
13
12
  <TooltipPrimitive.Provider
14
13
  data-slot="tooltip-provider"
15
- delayDuration={delayDuration}
14
+ delay={delay}
16
15
  {...props}
17
16
  />
18
17
  )
19
18
  }
20
19
 
21
- function Tooltip({
22
- ...props
23
- }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
20
+ function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
24
21
  return (
25
22
  <TooltipProvider>
26
23
  <TooltipPrimitive.Root data-slot="tooltip" {...props} />
@@ -28,32 +25,44 @@ function Tooltip({
28
25
  )
29
26
  }
30
27
 
31
- function TooltipTrigger({
32
- ...props
33
- }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
28
+ function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
34
29
  return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
35
30
  }
36
31
 
37
32
  function TooltipContent({
38
33
  className,
39
- sideOffset = 0,
34
+ side = "top",
35
+ sideOffset = 4,
36
+ align = "center",
37
+ alignOffset = 0,
40
38
  children,
41
39
  ...props
42
- }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
40
+ }: TooltipPrimitive.Popup.Props &
41
+ Pick<
42
+ TooltipPrimitive.Positioner.Props,
43
+ "align" | "alignOffset" | "side" | "sideOffset"
44
+ >) {
43
45
  return (
44
46
  <TooltipPrimitive.Portal>
45
- <TooltipPrimitive.Content
46
- data-slot="tooltip-content"
47
+ <TooltipPrimitive.Positioner
48
+ align={align}
49
+ alignOffset={alignOffset}
50
+ side={side}
47
51
  sideOffset={sideOffset}
48
- className={cn(
49
- "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
50
- className
51
- )}
52
- {...props}
52
+ className="isolate z-50"
53
53
  >
54
- {children}
55
- <TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
56
- </TooltipPrimitive.Content>
54
+ <TooltipPrimitive.Popup
55
+ data-slot="tooltip-content"
56
+ className={cn(
57
+ "data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-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 rounded-md px-3 py-1.5 text-xs **:data-[slot=kbd]:rounded-md bg-foreground text-background z-50 w-fit max-w-xs origin-(--transform-origin)",
58
+ className
59
+ )}
60
+ {...props}
61
+ >
62
+ {children}
63
+ <TooltipPrimitive.Arrow className="size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground z-50 data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
64
+ </TooltipPrimitive.Popup>
65
+ </TooltipPrimitive.Positioner>
57
66
  </TooltipPrimitive.Portal>
58
67
  )
59
68
  }
@@ -0,0 +1,143 @@
1
+ import { ApiDataInterface } from "../../core/interfaces/ApiDataInterface";
2
+
3
+ export interface CreateMockApiDataOptions {
4
+ type: string;
5
+ id?: string;
6
+ attributes?: Record<string, any>;
7
+ relationships?: Record<string, any>;
8
+ included?: any[];
9
+ createdAt?: Date;
10
+ updatedAt?: Date;
11
+ self?: string;
12
+ }
13
+
14
+ /**
15
+ * Creates a mock ApiDataInterface object for testing.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';
20
+ *
21
+ * const mockArticle = createMockApiData({
22
+ * type: 'articles',
23
+ * id: '1',
24
+ * attributes: { title: 'Test Article', body: 'Content here' },
25
+ * });
26
+ * ```
27
+ *
28
+ * @example With relationships
29
+ * ```ts
30
+ * const mockArticle = createMockApiData({
31
+ * type: 'articles',
32
+ * id: '1',
33
+ * attributes: { title: 'Test' },
34
+ * relationships: {
35
+ * author: { data: { type: 'users', id: '42' } },
36
+ * },
37
+ * });
38
+ * ```
39
+ */
40
+ export function createMockApiData(options: CreateMockApiDataOptions): ApiDataInterface {
41
+ const {
42
+ type,
43
+ id = `mock-${type}-${Math.random().toString(36).substring(7)}`,
44
+ attributes = {},
45
+ relationships = {},
46
+ included = [],
47
+ createdAt = new Date(),
48
+ updatedAt = new Date(),
49
+ self,
50
+ } = options;
51
+
52
+ const jsonApiData = {
53
+ type,
54
+ id,
55
+ attributes: {
56
+ ...attributes,
57
+ createdAt: createdAt.toISOString(),
58
+ updatedAt: updatedAt.toISOString(),
59
+ },
60
+ relationships,
61
+ };
62
+
63
+ const mockData: ApiDataInterface = {
64
+ get included() {
65
+ return included;
66
+ },
67
+ get type() {
68
+ return type;
69
+ },
70
+ get id() {
71
+ return id;
72
+ },
73
+ get createdAt() {
74
+ return createdAt;
75
+ },
76
+ get updatedAt() {
77
+ return updatedAt;
78
+ },
79
+ get self() {
80
+ return self;
81
+ },
82
+ get jsonApi() {
83
+ return jsonApiData;
84
+ },
85
+ generateApiUrl: (params?: any) => {
86
+ const baseUrl = `/${type}/${id}`;
87
+ if (params) {
88
+ const searchParams = new URLSearchParams(params);
89
+ return `${baseUrl}?${searchParams.toString()}`;
90
+ }
91
+ return baseUrl;
92
+ },
93
+ dehydrate: () => ({
94
+ jsonApi: jsonApiData,
95
+ included,
96
+ allData: [jsonApiData],
97
+ }),
98
+ rehydrate: function (data: any) {
99
+ return this;
100
+ },
101
+ createJsonApi: (data: any) => ({
102
+ type,
103
+ id,
104
+ attributes: data,
105
+ }),
106
+ };
107
+
108
+ // Add attribute accessors to the mock object
109
+ Object.keys(attributes).forEach((key) => {
110
+ Object.defineProperty(mockData, key, {
111
+ get: () => attributes[key],
112
+ enumerable: true,
113
+ });
114
+ });
115
+
116
+ return mockData;
117
+ }
118
+
119
+ /**
120
+ * Creates an array of mock ApiDataInterface objects.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * import { createMockApiDataList } from '@carlonicora/nextjs-jsonapi/testing';
125
+ *
126
+ * const mockArticles = createMockApiDataList('articles', 5, (index) => ({
127
+ * title: `Article ${index + 1}`,
128
+ * }));
129
+ * ```
130
+ */
131
+ export function createMockApiDataList(
132
+ type: string,
133
+ count: number,
134
+ attributesFactory?: (index: number) => Record<string, any>,
135
+ ): ApiDataInterface[] {
136
+ return Array.from({ length: count }, (_, index) =>
137
+ createMockApiData({
138
+ type,
139
+ id: `${index + 1}`,
140
+ attributes: attributesFactory?.(index) ?? {},
141
+ }),
142
+ );
143
+ }
@@ -0,0 +1,32 @@
1
+ import { ApiRequestDataTypeInterface } from "../../core/interfaces/ApiRequestDataTypeInterface";
2
+
3
+ export interface CreateMockModuleOptions {
4
+ name: string;
5
+ cache?: string;
6
+ inclusions?: ApiRequestDataTypeInterface["inclusions"];
7
+ }
8
+
9
+ /**
10
+ * Creates a mock module definition for testing.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { createMockModule } from '@carlonicora/nextjs-jsonapi/testing';
15
+ *
16
+ * const mockArticleModule = createMockModule({ name: 'articles' });
17
+ * ```
18
+ */
19
+ export function createMockModule(options: CreateMockModuleOptions): ApiRequestDataTypeInterface {
20
+ // Create a mock model class
21
+ class MockModel {
22
+ id = "mock-id";
23
+ type = options.name;
24
+ }
25
+
26
+ return {
27
+ name: options.name,
28
+ cache: options.cache,
29
+ inclusions: options.inclusions,
30
+ model: MockModel,
31
+ };
32
+ }
@@ -0,0 +1,88 @@
1
+ import { ApiResponseInterface } from "../../core/interfaces/ApiResponseInterface";
2
+ import { ApiDataInterface } from "../../core/interfaces/ApiDataInterface";
3
+
4
+ export interface CreateMockResponseOptions {
5
+ data?: ApiDataInterface | ApiDataInterface[] | null;
6
+ ok?: boolean;
7
+ response?: number;
8
+ error?: string;
9
+ meta?: Record<string, any>;
10
+ self?: string;
11
+ next?: string;
12
+ prev?: string;
13
+ }
14
+
15
+ /**
16
+ * Creates a mock API response for testing.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { createMockResponse, createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';
21
+ *
22
+ * const mockData = createMockApiData({ type: 'articles', id: '1' });
23
+ * const response = createMockResponse({ data: mockData, ok: true });
24
+ * ```
25
+ *
26
+ * @example With pagination
27
+ * ```ts
28
+ * const response = createMockResponse({
29
+ * data: [mockData],
30
+ * ok: true,
31
+ * next: '/articles?page=2',
32
+ * prev: '/articles?page=0',
33
+ * });
34
+ * ```
35
+ */
36
+ export function createMockResponse(options: CreateMockResponseOptions = {}): ApiResponseInterface {
37
+ const {
38
+ data = null,
39
+ ok = true,
40
+ response = ok ? 200 : 500,
41
+ error = ok ? "" : "Error",
42
+ meta,
43
+ self,
44
+ next,
45
+ prev,
46
+ } = options;
47
+
48
+ const mockResponse: ApiResponseInterface = {
49
+ ok,
50
+ response,
51
+ data: data as ApiDataInterface | ApiDataInterface[],
52
+ error,
53
+ meta,
54
+ self,
55
+ next,
56
+ prev,
57
+ };
58
+
59
+ // Add pagination methods if next/prev provided
60
+ if (next) {
61
+ mockResponse.nextPage = async () => createMockResponse({ ...options, next: undefined, prev: self });
62
+ }
63
+
64
+ if (prev) {
65
+ mockResponse.prevPage = async () => createMockResponse({ ...options, prev: undefined, next: self });
66
+ }
67
+
68
+ return mockResponse;
69
+ }
70
+
71
+ /**
72
+ * Creates a mock error response for testing error scenarios.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * import { createMockErrorResponse } from '@carlonicora/nextjs-jsonapi/testing';
77
+ *
78
+ * const errorResponse = createMockErrorResponse(404, 'Not Found');
79
+ * ```
80
+ */
81
+ export function createMockErrorResponse(statusCode: number, errorMessage: string): ApiResponseInterface {
82
+ return createMockResponse({
83
+ ok: false,
84
+ response: statusCode,
85
+ error: errorMessage,
86
+ data: null,
87
+ });
88
+ }
@@ -0,0 +1,76 @@
1
+ import { vi, type Mock } from "vitest";
2
+ import { ApiResponseInterface } from "../../core/interfaces/ApiResponseInterface";
3
+ import { createMockResponse } from "./createMockResponse";
4
+
5
+ export type MockApiMethod = Mock<(...args: any[]) => Promise<ApiResponseInterface>>;
6
+
7
+ export interface MockService {
8
+ get: MockApiMethod;
9
+ post: MockApiMethod;
10
+ put: MockApiMethod;
11
+ patch: MockApiMethod;
12
+ delete: MockApiMethod;
13
+ }
14
+
15
+ export interface CreateMockServiceOptions {
16
+ defaultResponse?: ApiResponseInterface;
17
+ }
18
+
19
+ /**
20
+ * Creates a mock service with Vitest mock functions for all HTTP methods.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { createMockService, createMockResponse } from '@carlonicora/nextjs-jsonapi/testing';
25
+ *
26
+ * const mockService = createMockService();
27
+ * mockService.get.mockResolvedValue(createMockResponse({ data: mockData }));
28
+ *
29
+ * // Use in test
30
+ * expect(mockService.get).toHaveBeenCalled();
31
+ * ```
32
+ *
33
+ * @example With default response
34
+ * ```ts
35
+ * const mockService = createMockService({
36
+ * defaultResponse: createMockResponse({ ok: true, data: [] }),
37
+ * });
38
+ * ```
39
+ */
40
+ export function createMockService(options: CreateMockServiceOptions = {}): MockService {
41
+ const defaultResponse = options.defaultResponse ?? createMockResponse({ ok: true });
42
+
43
+ return {
44
+ get: vi.fn().mockResolvedValue(defaultResponse),
45
+ post: vi.fn().mockResolvedValue(defaultResponse),
46
+ put: vi.fn().mockResolvedValue(defaultResponse),
47
+ patch: vi.fn().mockResolvedValue(defaultResponse),
48
+ delete: vi.fn().mockResolvedValue(defaultResponse),
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Creates a mock service that returns errors for all methods.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import { createMockErrorService } from '@carlonicora/nextjs-jsonapi/testing';
58
+ *
59
+ * const errorService = createMockErrorService(500, 'Internal Server Error');
60
+ * ```
61
+ */
62
+ export function createMockErrorService(statusCode: number = 500, errorMessage: string = "Error"): MockService {
63
+ const errorResponse = createMockResponse({
64
+ ok: false,
65
+ response: statusCode,
66
+ error: errorMessage,
67
+ });
68
+
69
+ return {
70
+ get: vi.fn().mockResolvedValue(errorResponse),
71
+ post: vi.fn().mockResolvedValue(errorResponse),
72
+ put: vi.fn().mockResolvedValue(errorResponse),
73
+ patch: vi.fn().mockResolvedValue(errorResponse),
74
+ delete: vi.fn().mockResolvedValue(errorResponse),
75
+ };
76
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Test utilities for @carlonicora/nextjs-jsonapi
3
+ *
4
+ * Import from '@carlonicora/nextjs-jsonapi/testing'
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import {
9
+ * MockJsonApiProvider,
10
+ * renderWithProviders,
11
+ * createMockApiData,
12
+ * createMockResponse,
13
+ * createMockModule,
14
+ * createMockService,
15
+ * jsonApiMatchers,
16
+ * extendExpectWithJsonApiMatchers,
17
+ * } from '@carlonicora/nextjs-jsonapi/testing';
18
+ * ```
19
+ */
20
+
21
+ // Providers
22
+ export { MockJsonApiProvider, defaultMockConfig, type MockJsonApiProviderProps } from "./providers/MockJsonApiProvider";
23
+
24
+ // Factories
25
+ export { createMockModule, type CreateMockModuleOptions } from "./factories/createMockModule";
26
+
27
+ export {
28
+ createMockResponse,
29
+ createMockErrorResponse,
30
+ type CreateMockResponseOptions,
31
+ } from "./factories/createMockResponse";
32
+
33
+ export {
34
+ createMockService,
35
+ createMockErrorService,
36
+ type MockService,
37
+ type MockApiMethod,
38
+ type CreateMockServiceOptions,
39
+ } from "./factories/createMockService";
40
+
41
+ export { createMockApiData, createMockApiDataList, type CreateMockApiDataOptions } from "./factories/createMockApiData";
42
+
43
+ // Matchers
44
+ export { jsonApiMatchers, extendExpectWithJsonApiMatchers } from "./matchers/jsonApiMatchers";
45
+
46
+ // Utilities
47
+ export {
48
+ renderWithProviders,
49
+ render,
50
+ screen,
51
+ waitFor,
52
+ fireEvent,
53
+ within,
54
+ userEvent,
55
+ type RenderWithProvidersOptions,
56
+ } from "./utils/renderWithProviders";