beez-ui 2.5.0 → 2.6.1

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 (92) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/dist/components/alert-dialog.d.ts +15 -4
  4. package/dist/components/alert-dialog.js +84 -44
  5. package/dist/components/alert.d.ts +30 -9
  6. package/dist/components/alert.js +360 -39
  7. package/dist/components/avatar.d.ts +33 -10
  8. package/dist/components/avatar.js +110 -30
  9. package/dist/components/badge.d.ts +39 -7
  10. package/dist/components/badge.js +348 -24
  11. package/dist/components/calendar.d.ts +29 -2
  12. package/dist/components/calendar.js +1035 -223
  13. package/dist/components/card.d.ts +17 -1
  14. package/dist/components/card.js +34 -8
  15. package/dist/components/carousel.d.ts +29 -2
  16. package/dist/components/carousel.js +471 -90
  17. package/dist/components/checkbox.d.ts +13 -2
  18. package/dist/components/checkbox.js +301 -41
  19. package/dist/components/dialog-surface.d.ts +27 -0
  20. package/dist/components/dialog-surface.js +137 -0
  21. package/dist/components/dialog.d.ts +21 -4
  22. package/dist/components/dialog.js +163 -96
  23. package/dist/components/dropdown-menu.d.ts +30 -16
  24. package/dist/components/dropdown-menu.js +139 -83
  25. package/dist/components/hover-card.d.ts +46 -3
  26. package/dist/components/hover-card.js +423 -60
  27. package/dist/components/pagination.d.ts +32 -14
  28. package/dist/components/pagination.js +136 -59
  29. package/dist/components/popover.d.ts +14 -5
  30. package/dist/components/popover.js +78 -36
  31. package/dist/components/radio-group.d.ts +19 -3
  32. package/dist/components/radio-group.js +400 -57
  33. package/dist/components/select.d.ts +17 -6
  34. package/dist/components/select.js +83 -71
  35. package/dist/components/sheet.js +37 -26
  36. package/dist/components/sidebar.js +11 -0
  37. package/dist/components/skeleton.d.ts +19 -5
  38. package/dist/components/skeleton.js +434 -14
  39. package/dist/components/switch.d.ts +14 -4
  40. package/dist/components/switch.js +424 -40
  41. package/dist/components/tabs.d.ts +38 -5
  42. package/dist/components/tabs.js +564 -97
  43. package/dist/components/themed-toaster.d.ts +6 -2
  44. package/dist/components/themed-toaster.js +80 -50
  45. package/dist/components/tooltip.d.ts +33 -2
  46. package/dist/components/tooltip.js +197 -69
  47. package/dist/constants/alert.d.ts +12 -0
  48. package/dist/constants/alert.js +9 -0
  49. package/dist/constants/avatar.d.ts +10 -0
  50. package/dist/constants/avatar.js +7 -0
  51. package/dist/constants/badge.d.ts +6 -0
  52. package/dist/constants/badge.js +6 -0
  53. package/dist/constants/calendar.d.ts +24 -0
  54. package/dist/constants/calendar.js +22 -0
  55. package/dist/constants/carousel.d.ts +37 -0
  56. package/dist/constants/carousel.js +53 -0
  57. package/dist/constants/checkbox.d.ts +17 -0
  58. package/dist/constants/checkbox.js +17 -0
  59. package/dist/constants/dialog.d.ts +6 -0
  60. package/dist/constants/dialog.js +6 -0
  61. package/dist/constants/dropdown-menu.d.ts +5 -0
  62. package/dist/constants/dropdown-menu.js +5 -0
  63. package/dist/constants/hover-card.d.ts +37 -0
  64. package/dist/constants/hover-card.js +85 -0
  65. package/dist/constants/pagination.d.ts +9 -0
  66. package/dist/constants/pagination.js +9 -0
  67. package/dist/constants/popover.d.ts +7 -0
  68. package/dist/constants/popover.js +39 -0
  69. package/dist/constants/radio-group.d.ts +10 -0
  70. package/dist/constants/radio-group.js +10 -0
  71. package/dist/constants/select.d.ts +3 -0
  72. package/dist/constants/select.js +3 -0
  73. package/dist/constants/skeleton.d.ts +17 -0
  74. package/dist/constants/skeleton.js +17 -0
  75. package/dist/constants/switch.d.ts +44 -0
  76. package/dist/constants/switch.js +49 -0
  77. package/dist/constants/tabs.d.ts +17 -0
  78. package/dist/constants/tabs.js +17 -0
  79. package/dist/constants/toast.d.ts +3 -0
  80. package/dist/constants/toast.js +3 -0
  81. package/dist/constants/tooltip.d.ts +13 -0
  82. package/dist/constants/tooltip.js +52 -0
  83. package/dist/lib/toast-layer.d.ts +24 -0
  84. package/dist/lib/toast-layer.js +76 -0
  85. package/dist/motion/arc-floating-slot.d.ts +40 -0
  86. package/dist/motion/arc-floating-slot.js +167 -0
  87. package/dist/motion/glide-indicator.d.ts +6 -7
  88. package/dist/motion/glide-indicator.js +5 -3
  89. package/dist/motion/overlay-warmth.d.ts +24 -0
  90. package/dist/motion/overlay-warmth.js +70 -0
  91. package/dist/styles.css +1 -1
  92. package/package.json +1 -1
@@ -1,183 +1,650 @@
1
1
  "use client";
2
2
  import { c as _c } from "react/compiler-runtime";
3
- import * as React from "react";
3
+ /**
4
+ * Arc's Tabs (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): its segmented list on Arc's tokens, a
5
+ * highlight that glides between triggers with Arc's morph spring, a list that scrolls sideways and keeps the active
6
+ * tab in view, and panels that slide in from the side of the chosen tab while their height morphs from the previous
7
+ * panel. Radix keeps the roles, keyboard navigation and controlled or uncontrolled value.
8
+ */
9
+ import { createContext, useContext, useLayoutEffect, useRef, useState } from "react";
4
10
  import { cva } from "class-variance-authority";
5
- import { Tabs as TabsPrimitive } from "radix-ui";
6
- import { GlideSlot } from "../motion/glide-slot.js";
7
- import { MotionSlot } from "../motion/motion-slot.js";
11
+ import { Slot, Tabs as TabsPrimitive } from "radix-ui";
12
+ import { AnimatePresence, animate, motion, useIsPresent } from "motion/react";
13
+ import { TABS_DIRECTION, TABS_PANEL_HEIGHT_TOLERANCE_PX, TABS_PANEL_OFFSET_PX, TABS_PANEL_REDUCED_EXIT_DURATION_S, TABS_REVEAL_MARGIN_PX } from "../constants/tabs.js";
14
+ import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
8
15
  import { cn } from "../lib/utils.js";
16
+ import { ARC_DURATION, ARC_EASE, ARC_SPRING_SMOOTH } from "../motion/arc-tokens.js";
17
+ import { GlideSlot } from "../motion/glide-slot.js";
18
+ import { useAttachedElement } from "../motion/use-attached-element.js";
9
19
  import { jsx as _jsx } from "react/jsx-runtime";
20
+ const TabsMotionContext = createContext(null);
21
+ /** Returns the elements of a slot that belong to this Tabs instance, never to a nested one. */
22
+ function getOwnElements(root, selector) {
23
+ return Array.from(root.querySelectorAll(selector)).filter((element) => element.closest("[data-slot=\"tabs\"]") === root);
24
+ }
25
+ /**
26
+ * Reads which way the selection travels from the order of this instance's triggers.
27
+ * @param root - The tabs root, or null before it is attached.
28
+ * @param fromValue - Value of the previously active tab.
29
+ * @param toValue - Value of the newly active tab.
30
+ * @returns The travel direction, or null when either tab is not rendered.
31
+ */
32
+ function getTravelDirection(root, fromValue, toValue) {
33
+ if (!root) return null;
34
+ const order = getOwnElements(root, "[data-slot=\"tabs-trigger\"]").map((trigger) => trigger.getAttribute("data-value"));
35
+ const fromIndex = order.indexOf(fromValue);
36
+ const toIndex = order.indexOf(toValue);
37
+ if (fromIndex < 0 || toIndex < 0 || fromIndex === toIndex) return null;
38
+ return toIndex > fromIndex ? TABS_DIRECTION.forward : TABS_DIRECTION.backward;
39
+ }
40
+ /**
41
+ * Groups a tab list with its panels. Accepts Radix's `value`/`defaultValue`/`onValueChange` contract unchanged.
42
+ * @param props - Radix root props, including `orientation` and `ref`.
43
+ * @returns The tabs root.
44
+ */
10
45
  function Tabs(t0) {
11
- const $ = _c(10);
46
+ const $ = _c(28);
12
47
  let className;
48
+ let defaultValue;
49
+ let onValueChange;
13
50
  let props;
51
+ let ref;
14
52
  let t1;
53
+ let value;
15
54
  if ($[0] !== t0) {
16
- ({className, orientation: t1, ...props} = t0);
55
+ ({className, orientation: t1, value, defaultValue, onValueChange, ref, ...props} = t0);
17
56
  $[0] = t0;
18
57
  $[1] = className;
19
- $[2] = props;
20
- $[3] = t1;
58
+ $[2] = defaultValue;
59
+ $[3] = onValueChange;
60
+ $[4] = props;
61
+ $[5] = ref;
62
+ $[6] = t1;
63
+ $[7] = value;
21
64
  } else {
22
65
  className = $[1];
23
- props = $[2];
24
- t1 = $[3];
66
+ defaultValue = $[2];
67
+ onValueChange = $[3];
68
+ props = $[4];
69
+ ref = $[5];
70
+ t1 = $[6];
71
+ value = $[7];
25
72
  }
26
73
  const orientation = t1 === undefined ? "horizontal" : t1;
74
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? "");
75
+ const [direction, setDirection] = useState(TABS_DIRECTION.forward);
76
+ const [root, attachRoot] = useAttachedElement(ref);
77
+ const panelHeightRef = useRef(null);
78
+ const leavingRectRef = useRef(null);
79
+ const activeValue = value ?? uncontrolledValue;
80
+ const [renderedValue, setRenderedValue] = useState(activeValue);
81
+ if (renderedValue !== activeValue) {
82
+ setRenderedValue(activeValue);
83
+ const travelDirection = getTravelDirection(root, renderedValue, activeValue);
84
+ if (travelDirection !== null) {
85
+ setDirection(travelDirection);
86
+ }
87
+ }
27
88
  let t2;
28
- if ($[4] !== className) {
29
- t2 = cn("group/tabs flex gap-2 data-horizontal:flex-col", className);
30
- $[4] = className;
31
- $[5] = t2;
89
+ if ($[8] !== onValueChange || $[9] !== root || $[10] !== value) {
90
+ t2 = function handleValueChange(nextValue) {
91
+ const activePanel = root ? getOwnElements(root, "[data-slot=\"tabs-content\"][data-state=\"active\"]")[0] : undefined;
92
+ leavingRectRef.current = activePanel ? {
93
+ value: nextValue,
94
+ rect: activePanel.getBoundingClientRect()
95
+ } : null;
96
+ if (value === undefined) {
97
+ setUncontrolledValue(nextValue);
98
+ }
99
+ onValueChange?.(nextValue);
100
+ };
101
+ $[8] = onValueChange;
102
+ $[9] = root;
103
+ $[10] = value;
104
+ $[11] = t2;
32
105
  } else {
33
- t2 = $[5];
106
+ t2 = $[11];
34
107
  }
108
+ const handleValueChange = t2;
35
109
  let t3;
36
- if ($[6] !== orientation || $[7] !== props || $[8] !== t2) {
37
- t3 = /* @__PURE__ */ _jsx(TabsPrimitive.Root, {
110
+ if ($[12] !== activeValue || $[13] !== direction || $[14] !== orientation) {
111
+ t3 = {
112
+ activeValue,
113
+ direction,
114
+ orientation,
115
+ panelHeightRef,
116
+ leavingRectRef
117
+ };
118
+ $[12] = activeValue;
119
+ $[13] = direction;
120
+ $[14] = orientation;
121
+ $[15] = t3;
122
+ } else {
123
+ t3 = $[15];
124
+ }
125
+ let t4;
126
+ if ($[16] !== className) {
127
+ t4 = cn("group/tabs relative flex gap-(--space-4) data-horizontal:flex-col", className);
128
+ $[16] = className;
129
+ $[17] = t4;
130
+ } else {
131
+ t4 = $[17];
132
+ }
133
+ let t5;
134
+ if ($[18] !== activeValue || $[19] !== attachRoot || $[20] !== handleValueChange || $[21] !== orientation || $[22] !== props || $[23] !== t4) {
135
+ t5 = /* @__PURE__ */ _jsx(TabsPrimitive.Root, {
136
+ ref: attachRoot,
38
137
  "data-slot": "tabs",
39
138
  "data-orientation": orientation,
40
- className: t2,
41
- ...props
139
+ orientation,
140
+ className: t4,
141
+ ...props,
142
+ value: activeValue,
143
+ onValueChange: handleValueChange
42
144
  });
43
- $[6] = orientation;
44
- $[7] = props;
45
- $[8] = t2;
46
- $[9] = t3;
145
+ $[18] = activeValue;
146
+ $[19] = attachRoot;
147
+ $[20] = handleValueChange;
148
+ $[21] = orientation;
149
+ $[22] = props;
150
+ $[23] = t4;
151
+ $[24] = t5;
47
152
  } else {
48
- t3 = $[9];
153
+ t5 = $[24];
49
154
  }
50
- return t3;
155
+ let t6;
156
+ if ($[25] !== t3 || $[26] !== t5) {
157
+ t6 = /* @__PURE__ */ _jsx(TabsMotionContext.Provider, {
158
+ value: t3,
159
+ children: t5
160
+ });
161
+ $[25] = t3;
162
+ $[26] = t5;
163
+ $[27] = t6;
164
+ } else {
165
+ t6 = $[27];
166
+ }
167
+ return t6;
51
168
  }
52
- const tabsListVariants = cva("group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none", {
169
+ /**
170
+ * Arc's segmented list (`default`): a muted track whose active trigger is a raised surface. `line` keeps the
171
+ * underline variant on the same tokens. Horizontal lists scroll sideways without a visible scrollbar.
172
+ */
173
+ const tabsListVariants = cva("group/tabs-list inline-flex w-fit max-w-full min-w-0 items-center text-text-muted group-data-horizontal/tabs:overflow-x-auto group-data-horizontal/tabs:[scrollbar-width:none] group-data-horizontal/tabs:[&::-webkit-scrollbar]:hidden group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col", {
53
174
  variants: { variant: {
54
- default: "bg-muted",
55
- line: "gap-1 bg-transparent"
175
+ default: "gap-(--space-1) rounded-(--radius-control) border border-border bg-surface-muted p-(--space-1)",
176
+ line: "gap-(--space-1) bg-transparent"
56
177
  } },
57
178
  defaultVariants: { variant: "default" }
58
179
  });
180
+ /**
181
+ * Scrolls a horizontally overflowing list just enough to show the trigger, never the page around it. The target is an
182
+ * absolute offset, so a second call while a smooth scroll is still running (focus and selection both reveal the
183
+ * trigger on the same key press) aims at the same place instead of adding its delta to a moving position.
184
+ * @param list - The scrolling tab list.
185
+ * @param trigger - The trigger to reveal.
186
+ * @param reduceMotion - True jumps instead of scrolling smoothly.
187
+ */
188
+ function revealTrigger(list, trigger, reduceMotion) {
189
+ if (!trigger || list.scrollWidth <= list.clientWidth || typeof list.scrollTo !== "function") return;
190
+ const frame = list.getBoundingClientRect();
191
+ const item = trigger.getBoundingClientRect();
192
+ const itemStart = item.left - frame.left + list.scrollLeft;
193
+ const itemEnd = itemStart + item.width;
194
+ const visibleStart = list.scrollLeft;
195
+ const visibleEnd = visibleStart + list.clientWidth;
196
+ const target = itemStart < visibleStart + TABS_REVEAL_MARGIN_PX ? itemStart - TABS_REVEAL_MARGIN_PX : itemEnd > visibleEnd - TABS_REVEAL_MARGIN_PX ? itemEnd - list.clientWidth + TABS_REVEAL_MARGIN_PX : visibleStart;
197
+ if (target !== visibleStart) list.scrollTo({
198
+ left: target,
199
+ behavior: reduceMotion ? "instant" : "smooth"
200
+ });
201
+ }
202
+ /**
203
+ * Holds the triggers. The active highlight glides to the newly selected trigger and the list scrolls to keep the
204
+ * active or focused trigger visible.
205
+ * @param props - Radix list props, the `variant` and `ref`.
206
+ * @returns The tab list.
207
+ */
59
208
  function TabsList(t0) {
60
- const $ = _c(11);
209
+ const $ = _c(31);
61
210
  let className;
211
+ let onFocusCapture;
62
212
  let props;
213
+ let ref;
63
214
  let t1;
64
215
  if ($[0] !== t0) {
65
- ({className, variant: t1, ...props} = t0);
216
+ ({className, variant: t1, ref, onFocusCapture, ...props} = t0);
66
217
  $[0] = t0;
67
218
  $[1] = className;
68
- $[2] = props;
69
- $[3] = t1;
219
+ $[2] = onFocusCapture;
220
+ $[3] = props;
221
+ $[4] = ref;
222
+ $[5] = t1;
70
223
  } else {
71
224
  className = $[1];
72
- props = $[2];
73
- t1 = $[3];
225
+ onFocusCapture = $[2];
226
+ props = $[3];
227
+ ref = $[4];
228
+ t1 = $[5];
74
229
  }
75
230
  const variant = t1 === undefined ? "default" : t1;
231
+ const motionState = useContext(TabsMotionContext);
232
+ const reduceMotion = usePrefersReducedMotion();
233
+ const [list, attachList] = useAttachedElement(ref);
234
+ const activeValue = motionState?.activeValue;
76
235
  let t2;
77
- if ($[4] !== className || $[5] !== variant) {
78
- t2 = cn(tabsListVariants({ variant }), className);
79
- $[4] = className;
80
- $[5] = variant;
81
- $[6] = t2;
236
+ if ($[6] !== list || $[7] !== motionState?.orientation || $[8] !== reduceMotion) {
237
+ t2 = () => {
238
+ if (!list || motionState?.orientation === "vertical") {
239
+ return;
240
+ }
241
+ const revealActiveTrigger = () => revealTrigger(list, list.querySelector("[data-slot=\"tabs-trigger\"][data-state=\"active\"]"), reduceMotion);
242
+ revealActiveTrigger();
243
+ const observer = new ResizeObserver(revealActiveTrigger);
244
+ for (const trigger of list.querySelectorAll("[data-slot=\"tabs-trigger\"]")) {
245
+ observer.observe(trigger);
246
+ }
247
+ return () => observer.disconnect();
248
+ };
249
+ $[6] = list;
250
+ $[7] = motionState?.orientation;
251
+ $[8] = reduceMotion;
252
+ $[9] = t2;
82
253
  } else {
83
- t2 = $[6];
254
+ t2 = $[9];
84
255
  }
85
- let t3;
86
- if ($[7] !== props || $[8] !== t2 || $[9] !== variant) {
87
- t3 = /* @__PURE__ */ _jsx(GlideSlot, {
256
+ const t3 = motionState?.orientation;
257
+ let t4;
258
+ if ($[10] !== activeValue || $[11] !== list || $[12] !== reduceMotion || $[13] !== t3) {
259
+ t4 = [
260
+ list,
261
+ activeValue,
262
+ t3,
263
+ reduceMotion
264
+ ];
265
+ $[10] = activeValue;
266
+ $[11] = list;
267
+ $[12] = reduceMotion;
268
+ $[13] = t3;
269
+ $[14] = t4;
270
+ } else {
271
+ t4 = $[14];
272
+ }
273
+ useLayoutEffect(t2, t4);
274
+ let t5;
275
+ if ($[15] !== list || $[16] !== motionState?.orientation || $[17] !== onFocusCapture || $[18] !== reduceMotion) {
276
+ t5 = function handleFocusCapture(event) {
277
+ onFocusCapture?.(event);
278
+ if (!list || motionState?.orientation === "vertical") {
279
+ return;
280
+ }
281
+ if (event.target instanceof HTMLElement && event.target.getAttribute("role") === "tab") {
282
+ revealTrigger(list, event.target, reduceMotion);
283
+ }
284
+ };
285
+ $[15] = list;
286
+ $[16] = motionState?.orientation;
287
+ $[17] = onFocusCapture;
288
+ $[18] = reduceMotion;
289
+ $[19] = t5;
290
+ } else {
291
+ t5 = $[19];
292
+ }
293
+ const handleFocusCapture = t5;
294
+ let t6;
295
+ if ($[20] !== className || $[21] !== variant) {
296
+ t6 = cn(tabsListVariants({ variant }), className);
297
+ $[20] = className;
298
+ $[21] = variant;
299
+ $[22] = t6;
300
+ } else {
301
+ t6 = $[22];
302
+ }
303
+ let t7;
304
+ if ($[23] !== handleFocusCapture || $[24] !== props || $[25] !== t6 || $[26] !== variant) {
305
+ t7 = /* @__PURE__ */ _jsx(TabsPrimitive.List, {
306
+ "data-slot": "tabs-list",
307
+ "data-variant": variant,
308
+ className: t6,
309
+ onFocusCapture: handleFocusCapture,
310
+ ...props
311
+ });
312
+ $[23] = handleFocusCapture;
313
+ $[24] = props;
314
+ $[25] = t6;
315
+ $[26] = variant;
316
+ $[27] = t7;
317
+ } else {
318
+ t7 = $[27];
319
+ }
320
+ let t8;
321
+ if ($[28] !== attachList || $[29] !== t7) {
322
+ t8 = /* @__PURE__ */ _jsx(GlideSlot, {
88
323
  preset: "tabs",
89
- children: /* @__PURE__ */ _jsx(TabsPrimitive.List, {
90
- "data-slot": "tabs-list",
91
- "data-variant": variant,
92
- className: t2,
93
- ...props
94
- })
324
+ ref: attachList,
325
+ children: t7
95
326
  });
96
- $[7] = props;
97
- $[8] = t2;
98
- $[9] = variant;
99
- $[10] = t3;
327
+ $[28] = attachList;
328
+ $[29] = t7;
329
+ $[30] = t8;
100
330
  } else {
101
- t3 = $[10];
331
+ t8 = $[30];
102
332
  }
103
- return t3;
333
+ return t8;
104
334
  }
335
+ /**
336
+ * Selects a panel. Arc's trigger: muted label, accent label once active, hover only on fine pointers and the
337
+ * shared keyboard focus outline.
338
+ * @param props - Radix trigger props, including `value`.
339
+ * @returns The tab.
340
+ */
105
341
  function TabsTrigger(t0) {
106
- const $ = _c(8);
342
+ const $ = _c(10);
107
343
  let className;
108
344
  let props;
345
+ let value;
109
346
  if ($[0] !== t0) {
110
- ({className, ...props} = t0);
347
+ ({className, value, ...props} = t0);
111
348
  $[0] = t0;
112
349
  $[1] = className;
113
350
  $[2] = props;
351
+ $[3] = value;
114
352
  } else {
115
353
  className = $[1];
116
354
  props = $[2];
355
+ value = $[3];
117
356
  }
118
357
  let t1;
119
- if ($[3] !== className) {
120
- t1 = cn("relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent", "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground", "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100 data-glide-target:after:opacity-0! data-glide-freeze:after:transition-none", className);
121
- $[3] = className;
122
- $[4] = t1;
358
+ if ($[4] !== className) {
359
+ t1 = cn("relative inline-flex min-h-(--control-height-sm) min-w-[5.5rem] flex-[1_0_auto] cursor-pointer items-center justify-center gap-1.5 rounded-[calc(var(--radius-control)-3px)] border border-transparent bg-transparent px-(--space-3) font-sans text-sm font-medium whitespace-nowrap text-text-muted [-webkit-tap-highlight-color:transparent] transition-[color,background-color,border-color,box-shadow] duration-(--duration-fast) ease-(--ease-standard) select-none motion-reduce:transition-none hover-fine:text-foreground active:text-foreground disabled:cursor-not-allowed disabled:opacity-50 data-active:text-(--accent-strong) group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "group-data-[variant=default]/tabs-list:data-active:border-border group-data-[variant=default]/tabs-list:data-active:bg-surface group-data-[variant=default]/tabs-list:data-active:shadow-(--shadow-resting)", "after:absolute after:rounded-full after:bg-(--accent-strong) after:opacity-0 after:transition-opacity after:duration-(--duration-fast) group-data-horizontal/tabs:after:inset-x-(--space-2) group-data-horizontal/tabs:after:-bottom-px group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-(--space-2) group-data-vertical/tabs:after:-right-px group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100 data-glide-target:after:opacity-0! data-glide-freeze:after:transition-none motion-reduce:after:transition-none", className);
360
+ $[4] = className;
361
+ $[5] = t1;
123
362
  } else {
124
- t1 = $[4];
363
+ t1 = $[5];
125
364
  }
126
365
  let t2;
127
- if ($[5] !== props || $[6] !== t1) {
128
- t2 = /* @__PURE__ */ _jsx(MotionSlot, {
129
- kind: "subtle-press",
130
- children: /* @__PURE__ */ _jsx(TabsPrimitive.Trigger, {
131
- "data-slot": "tabs-trigger",
132
- className: t1,
133
- ...props
134
- })
366
+ if ($[6] !== props || $[7] !== t1 || $[8] !== value) {
367
+ t2 = /* @__PURE__ */ _jsx(TabsPrimitive.Trigger, {
368
+ "data-slot": "tabs-trigger",
369
+ "data-value": value,
370
+ value,
371
+ className: t1,
372
+ ...props
135
373
  });
136
- $[5] = props;
137
- $[6] = t1;
138
- $[7] = t2;
374
+ $[6] = props;
375
+ $[7] = t1;
376
+ $[8] = value;
377
+ $[9] = t2;
139
378
  } else {
140
- t2 = $[7];
379
+ t2 = $[9];
141
380
  }
142
381
  return t2;
143
382
  }
383
+ /** Panel classes: Arc's body text rhythm and a rounded keyboard focus outline. */
384
+ const tabsContentClassName = "flex-1 text-sm leading-(--leading-body) [--focus-outline-offset:3px] focus-visible:rounded-(--radius-control) data-[state=inactive]:pointer-events-none";
385
+ /** Places a slide offset on the axis the list runs along. */
386
+ function slideOffset({ orientation }, distance) {
387
+ return orientation === "vertical" ? {
388
+ x: 0,
389
+ y: distance
390
+ } : {
391
+ x: distance,
392
+ y: 0
393
+ };
394
+ }
395
+ /** Arc's panel motion: slides in from the side of the chosen tab and leaves quickly the opposite way. */
396
+ const panelVariants = {
397
+ enter: (custom) => ({
398
+ opacity: 0,
399
+ ...slideOffset(custom, custom.direction * TABS_PANEL_OFFSET_PX.enter)
400
+ }),
401
+ center: {
402
+ opacity: 1,
403
+ x: 0,
404
+ y: 0,
405
+ transition: {
406
+ opacity: {
407
+ duration: ARC_DURATION.standard,
408
+ ease: [...ARC_EASE.enter]
409
+ },
410
+ x: ARC_SPRING_SMOOTH,
411
+ y: ARC_SPRING_SMOOTH
412
+ }
413
+ },
414
+ exit: (custom) => ({
415
+ opacity: 0,
416
+ ...slideOffset(custom, custom.direction * -TABS_PANEL_OFFSET_PX.exit),
417
+ transition: {
418
+ duration: ARC_DURATION.instant,
419
+ ease: [...ARC_EASE.standard]
420
+ }
421
+ })
422
+ };
423
+ /** Reduced motion: a short crossfade in place. Keys match `panelVariants`, so server and client styles agree. */
424
+ const reducedPanelVariants = {
425
+ enter: {
426
+ opacity: 0,
427
+ x: 0,
428
+ y: 0
429
+ },
430
+ center: {
431
+ opacity: 1,
432
+ x: 0,
433
+ y: 0,
434
+ transition: { duration: ARC_DURATION.instant }
435
+ },
436
+ exit: {
437
+ opacity: 0,
438
+ x: 0,
439
+ y: 0,
440
+ transition: { duration: TABS_PANEL_REDUCED_EXIT_DURATION_S }
441
+ }
442
+ };
443
+ /** Inline properties the height morph overrides on the panel and restores when it settles. */
444
+ const MORPH_STYLE_PROPERTIES = [
445
+ "height",
446
+ "overflow",
447
+ "flex",
448
+ "min-height"
449
+ ];
450
+ /** Animates the consumer's own element when `TabsContent` is used with `asChild`. */
451
+ const MotionPanelSlot = motion.create(Slot.Root);
452
+ /**
453
+ * The animated element behind an active panel. While present it morphs from the previous panel's height to its
454
+ * own; once leaving it stays pinned where it was, inert and hidden from assistive technology, until it fades out.
455
+ */
456
+ function TabsPanel({ motionState, reduceMotion, asChild, ref, ...props }) {
457
+ const isPresent = useIsPresent();
458
+ const [panel, attachPanel] = useAttachedElement(ref);
459
+ const { panelHeightRef, leavingRectRef, direction, orientation } = motionState;
460
+ const activeValue = useContext(TabsMotionContext)?.activeValue ?? motionState.activeValue;
461
+ const PanelElement = asChild ? MotionPanelSlot : motion.div;
462
+ useLayoutEffect(() => {
463
+ if (!panel) return;
464
+ if (!isPresent) {
465
+ const leaving = leavingRectRef.current;
466
+ const before = leaving?.value === activeValue ? leaving.rect : null;
467
+ const now = panel.getBoundingClientRect();
468
+ if (before) panel.style.translate = `${before.left - now.left}px ${before.top - now.top}px`;
469
+ return;
470
+ }
471
+ panel.style.translate = "";
472
+ const fromHeight = panelHeightRef.current;
473
+ const toHeight = panel.offsetHeight;
474
+ let controls;
475
+ const inlineStyle = MORPH_STYLE_PROPERTIES.map((property) => ({
476
+ property,
477
+ value: panel.style.getPropertyValue(property),
478
+ priority: panel.style.getPropertyPriority(property)
479
+ }));
480
+ const release = () => {
481
+ for (const { property, value, priority } of inlineStyle) panel.style.setProperty(property, value, priority);
482
+ };
483
+ if (fromHeight !== null && Math.abs(fromHeight - toHeight) > TABS_PANEL_HEIGHT_TOLERANCE_PX && !reduceMotion) {
484
+ panel.style.flex = "none";
485
+ panel.style.minHeight = "0";
486
+ if (toHeight > fromHeight) panel.style.overflow = "clip";
487
+ panel.style.height = `${fromHeight}px`;
488
+ controls = animate(panel, { height: [fromHeight, toHeight] }, {
489
+ ...ARC_SPRING_SMOOTH,
490
+ onComplete: release
491
+ });
492
+ }
493
+ panelHeightRef.current = controls && fromHeight !== null ? fromHeight : toHeight;
494
+ const observer = new ResizeObserver(() => {
495
+ panelHeightRef.current = panel.offsetHeight;
496
+ });
497
+ observer.observe(panel);
498
+ return () => {
499
+ observer.disconnect();
500
+ controls?.stop();
501
+ release();
502
+ };
503
+ }, [
504
+ panel,
505
+ isPresent,
506
+ reduceMotion,
507
+ panelHeightRef,
508
+ leavingRectRef,
509
+ activeValue
510
+ ]);
511
+ return /* @__PURE__ */ _jsx(PanelElement, {
512
+ ref: attachPanel,
513
+ ...props,
514
+ custom: {
515
+ direction,
516
+ orientation
517
+ },
518
+ variants: reduceMotion ? reducedPanelVariants : panelVariants,
519
+ initial: "enter",
520
+ animate: "center",
521
+ exit: "exit",
522
+ inert: !isPresent || undefined,
523
+ "aria-hidden": !isPresent || undefined
524
+ });
525
+ }
526
+ /**
527
+ * Content of one tab. Inside `Tabs` it animates between panels; with `forceMount` it stays mounted and switches
528
+ * without motion, as Radix renders it. With `asChild` the consumer's element is the panel in both cases.
529
+ * @param props - Radix content props, including `value` and `forceMount`.
530
+ * @returns The tab panel, or nothing while another tab is active.
531
+ */
144
532
  function TabsContent(t0) {
145
- const $ = _c(8);
533
+ const $ = _c(31);
534
+ let asChild;
535
+ let children;
146
536
  let className;
537
+ let forceMount;
147
538
  let props;
539
+ let value;
148
540
  if ($[0] !== t0) {
149
- ({className, ...props} = t0);
541
+ ({className, value, forceMount, asChild, children, ...props} = t0);
150
542
  $[0] = t0;
151
- $[1] = className;
152
- $[2] = props;
543
+ $[1] = asChild;
544
+ $[2] = children;
545
+ $[3] = className;
546
+ $[4] = forceMount;
547
+ $[5] = props;
548
+ $[6] = value;
153
549
  } else {
154
- className = $[1];
155
- props = $[2];
550
+ asChild = $[1];
551
+ children = $[2];
552
+ className = $[3];
553
+ forceMount = $[4];
554
+ props = $[5];
555
+ value = $[6];
156
556
  }
557
+ const motionState = useContext(TabsMotionContext);
558
+ const reduceMotion = usePrefersReducedMotion();
157
559
  let t1;
158
- if ($[3] !== className) {
159
- t1 = cn("flex-1 text-sm outline-none", className);
160
- $[3] = className;
161
- $[4] = t1;
560
+ if ($[7] !== className) {
561
+ t1 = cn(tabsContentClassName, className);
562
+ $[7] = className;
563
+ $[8] = t1;
162
564
  } else {
163
- t1 = $[4];
565
+ t1 = $[8];
164
566
  }
165
- let t2;
166
- if ($[5] !== props || $[6] !== t1) {
167
- t2 = /* @__PURE__ */ _jsx(MotionSlot, {
168
- kind: "content",
169
- children: /* @__PURE__ */ _jsx(TabsPrimitive.Content, {
567
+ const classes = t1;
568
+ if (forceMount || !motionState) {
569
+ let t2;
570
+ if ($[9] !== asChild || $[10] !== children || $[11] !== classes || $[12] !== forceMount || $[13] !== props || $[14] !== value) {
571
+ t2 = /* @__PURE__ */ _jsx(TabsPrimitive.Content, {
170
572
  "data-slot": "tabs-content",
171
- className: t1,
172
- ...props
573
+ value,
574
+ forceMount,
575
+ asChild,
576
+ className: classes,
577
+ ...props,
578
+ children
579
+ });
580
+ $[9] = asChild;
581
+ $[10] = children;
582
+ $[11] = classes;
583
+ $[12] = forceMount;
584
+ $[13] = props;
585
+ $[14] = value;
586
+ $[15] = t2;
587
+ } else {
588
+ t2 = $[15];
589
+ }
590
+ return t2;
591
+ }
592
+ const isSelected = motionState.activeValue === value;
593
+ let t2;
594
+ if ($[16] !== motionState.direction || $[17] !== motionState.orientation) {
595
+ t2 = {
596
+ direction: motionState.direction,
597
+ orientation: motionState.orientation
598
+ };
599
+ $[16] = motionState.direction;
600
+ $[17] = motionState.orientation;
601
+ $[18] = t2;
602
+ } else {
603
+ t2 = $[18];
604
+ }
605
+ const t3 = t2;
606
+ let t4;
607
+ if ($[19] !== asChild || $[20] !== children || $[21] !== classes || $[22] !== isSelected || $[23] !== motionState || $[24] !== props || $[25] !== reduceMotion || $[26] !== value) {
608
+ t4 = isSelected && /* @__PURE__ */ _jsx(TabsPrimitive.Content, {
609
+ "data-slot": "tabs-content",
610
+ ...props,
611
+ value,
612
+ forceMount: true,
613
+ asChild: true,
614
+ children: /* @__PURE__ */ _jsx(TabsPanel, {
615
+ className: classes,
616
+ motionState,
617
+ reduceMotion,
618
+ asChild,
619
+ children
173
620
  })
621
+ }, value);
622
+ $[19] = asChild;
623
+ $[20] = children;
624
+ $[21] = classes;
625
+ $[22] = isSelected;
626
+ $[23] = motionState;
627
+ $[24] = props;
628
+ $[25] = reduceMotion;
629
+ $[26] = value;
630
+ $[27] = t4;
631
+ } else {
632
+ t4 = $[27];
633
+ }
634
+ let t5;
635
+ if ($[28] !== t3 || $[29] !== t4) {
636
+ t5 = /* @__PURE__ */ _jsx(AnimatePresence, {
637
+ initial: false,
638
+ mode: "popLayout",
639
+ custom: t3,
640
+ children: t4
174
641
  });
175
- $[5] = props;
176
- $[6] = t1;
177
- $[7] = t2;
642
+ $[28] = t3;
643
+ $[29] = t4;
644
+ $[30] = t5;
178
645
  } else {
179
- t2 = $[7];
646
+ t5 = $[30];
180
647
  }
181
- return t2;
648
+ return t5;
182
649
  }
183
650
  export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };