@carlonicora/nextjs-jsonapi 1.121.0 → 1.123.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.
@@ -2,17 +2,40 @@
2
2
 
3
3
  import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
4
4
  import { cva, type VariantProps } from "class-variance-authority";
5
+ import { createContext, useContext, useState } from "react";
5
6
 
6
7
  import { cn } from "@/lib/utils";
7
8
 
8
- function Tabs({ className, orientation = "horizontal", ...props }: TabsPrimitive.Root.Props) {
9
+ // Tracks the active tab value so keepMounted panels can lazy-mount on first
10
+ // activation. undefined = untracked (Tabs given neither value nor defaultValue).
11
+ const TabsActiveValueContext = createContext<unknown>(undefined);
12
+
13
+ function Tabs({
14
+ className,
15
+ orientation = "horizontal",
16
+ value,
17
+ defaultValue,
18
+ onValueChange,
19
+ ...props
20
+ }: TabsPrimitive.Root.Props) {
21
+ const [uncontrolledValue, setUncontrolledValue] = useState<unknown>(defaultValue);
22
+ const activeValue = value !== undefined ? value : uncontrolledValue;
23
+
9
24
  return (
10
- <TabsPrimitive.Root
11
- data-slot="tabs"
12
- data-orientation={orientation}
13
- className={cn("gap-2 group/tabs flex data-[orientation=horizontal]:flex-col", className)}
14
- {...props}
15
- />
25
+ <TabsActiveValueContext.Provider value={activeValue}>
26
+ <TabsPrimitive.Root
27
+ data-slot="tabs"
28
+ data-orientation={orientation}
29
+ className={cn("gap-2 group/tabs flex data-[orientation=horizontal]:flex-col", className)}
30
+ value={value}
31
+ defaultValue={defaultValue}
32
+ onValueChange={(newValue, eventDetails) => {
33
+ setUncontrolledValue(newValue);
34
+ onValueChange?.(newValue, eventDetails);
35
+ }}
36
+ {...props}
37
+ />
38
+ </TabsActiveValueContext.Provider>
16
39
  );
17
40
  }
18
41
 
@@ -62,14 +85,29 @@ function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
62
85
  );
63
86
  }
64
87
 
65
- function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
88
+ function TabsContent({ className, value, keepMounted, children, ...props }: TabsPrimitive.Panel.Props) {
89
+ const activeValue = useContext(TabsActiveValueContext);
90
+ const isActive = activeValue !== undefined && activeValue === value;
91
+ const [hasBeenActive, setHasBeenActive] = useState(isActive);
92
+ if (isActive && !hasBeenActive) setHasBeenActive(true);
93
+
94
+ // Lazy-mount-once: a keepMounted panel renders its children only after its
95
+ // tab has been active at least once, then keeps them mounted so state and
96
+ // data survive tab switches (hidden panels no longer fetch on page load).
97
+ // Falls back to eager rendering when the active value is untracked.
98
+ const shouldRenderChildren = !keepMounted || activeValue === undefined || hasBeenActive;
99
+
66
100
  return (
67
101
  <TabsPrimitive.Panel
68
102
  data-slot="tabs-content"
103
+ value={value}
104
+ keepMounted={keepMounted}
69
105
  className={cn("text-xs/relaxed flex-1 outline-none", className)}
70
106
  {...props}
71
- />
107
+ >
108
+ {shouldRenderChildren ? children : null}
109
+ </TabsPrimitive.Panel>
72
110
  );
73
111
  }
74
112
 
75
- export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
113
+ export { Tabs, TabsContent, TabsList, tabsListVariants, TabsTrigger };