@nexub/react 2.1.0 → 2.2.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.
@@ -0,0 +1,468 @@
1
+ 'use client';
2
+
3
+ // src/components/Motion/Fade.tsx
4
+ import * as React2 from "react";
5
+
6
+ // src/components/Motion/useMotion.ts
7
+ import * as React from "react";
8
+
9
+ // src/hooks/useMediaQuery.ts
10
+ import { useState, useEffect } from "react";
11
+ function useMediaQuery(query) {
12
+ const [matches, setMatches] = useState(false);
13
+ useEffect(() => {
14
+ if (typeof window === "undefined") return;
15
+ const mql = window.matchMedia(query);
16
+ const handler = (e) => setMatches(e.matches);
17
+ mql.addEventListener("change", handler);
18
+ setMatches(mql.matches);
19
+ return () => mql.removeEventListener("change", handler);
20
+ }, [query]);
21
+ return matches;
22
+ }
23
+
24
+ // src/components/Motion/useMotion.ts
25
+ var DURATION_MS = {
26
+ instant: 0,
27
+ fast: 150,
28
+ normal: 200,
29
+ slow: 300,
30
+ slower: 500
31
+ };
32
+ var SPRING_SPEED = {
33
+ fast: "fast",
34
+ normal: "default",
35
+ slow: "slow",
36
+ slower: "slow"
37
+ };
38
+ var SPRING_MS = {
39
+ spatial: { fast: 224, default: 317, slow: 484 },
40
+ effects: { fast: 150, default: 231, slow: 327 },
41
+ expressive: { fast: 364, default: 435, slow: 600 }
42
+ };
43
+ var FALLBACK_MARGIN_MS = 50;
44
+ var spring = (property, family, speed) => `${property} var(--motion-spring-${family}-${speed}-duration) var(--motion-spring-${family}-${speed}-easing)`;
45
+ function usePrefersReducedMotion() {
46
+ return useMediaQuery("(prefers-reduced-motion: reduce)");
47
+ }
48
+ function useMotion({
49
+ visible,
50
+ duration = "normal",
51
+ easing,
52
+ unmountOnExit = false
53
+ }) {
54
+ const [phase, setPhase] = React.useState(
55
+ visible ? "entered" : "exited"
56
+ );
57
+ const reduced = usePrefersReducedMotion();
58
+ const rafRef = React.useRef(null);
59
+ const isMounted = React.useRef(true);
60
+ React.useEffect(() => {
61
+ isMounted.current = true;
62
+ return () => {
63
+ isMounted.current = false;
64
+ if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
65
+ };
66
+ }, []);
67
+ const prevVisible = React.useRef(visible);
68
+ React.useEffect(() => {
69
+ if (prevVisible.current === visible) return;
70
+ prevVisible.current = visible;
71
+ if (visible) {
72
+ setPhase("entering");
73
+ rafRef.current = requestAnimationFrame(() => {
74
+ rafRef.current = requestAnimationFrame(() => {
75
+ if (isMounted.current) setPhase("entered");
76
+ });
77
+ });
78
+ } else {
79
+ setPhase("exiting");
80
+ }
81
+ }, [visible]);
82
+ const legacy = easing !== void 0;
83
+ const exitMs = duration === "instant" ? 0 : legacy ? DURATION_MS[duration] : SPRING_MS.effects.fast;
84
+ React.useEffect(() => {
85
+ if (phase !== "exiting") return;
86
+ const t = setTimeout(() => setPhase("exited"), exitMs + FALLBACK_MARGIN_MS);
87
+ return () => clearTimeout(t);
88
+ }, [phase, exitMs]);
89
+ const handleTransitionEnd = React.useCallback((e) => {
90
+ if (!isMounted.current) return;
91
+ if (e && e.target !== e.currentTarget) return;
92
+ setPhase((prev) => prev === "exiting" ? "exited" : prev);
93
+ }, []);
94
+ const mounted = unmountOnExit ? phase !== "exited" : true;
95
+ let transitionStyle;
96
+ if (duration === "instant") {
97
+ transitionStyle = { transition: "none" };
98
+ } else if (legacy) {
99
+ transitionStyle = {
100
+ transitionDuration: `var(--duration-${duration})`,
101
+ transitionTimingFunction: `var(--ease-${easing})`,
102
+ transitionProperty: "opacity, transform"
103
+ };
104
+ } else if (phase === "exiting" || phase === "exited") {
105
+ transitionStyle = {
106
+ transition: [spring("opacity", "effects", "fast"), spring("transform", "effects", "fast")].join(", ")
107
+ };
108
+ } else {
109
+ const speed = SPRING_SPEED[duration];
110
+ transitionStyle = {
111
+ transition: [spring("opacity", "effects", speed), spring("transform", "spatial", speed)].join(", ")
112
+ };
113
+ }
114
+ return { phase, mounted, reduced, transitionStyle, handleTransitionEnd };
115
+ }
116
+
117
+ // src/components/Motion/Fade.tsx
118
+ import { jsx } from "react/jsx-runtime";
119
+ var Fade = React2.forwardRef(function Fade2({
120
+ in: visible,
121
+ duration = "normal",
122
+ easing,
123
+ unmountOnExit = false,
124
+ children,
125
+ style,
126
+ as: Tag = "div",
127
+ ...rest
128
+ }, ref) {
129
+ const { phase, mounted, transitionStyle, handleTransitionEnd } = useMotion({
130
+ visible,
131
+ duration,
132
+ easing,
133
+ unmountOnExit
134
+ });
135
+ if (!mounted) return null;
136
+ const opacity = phase === "entered" ? 1 : 0;
137
+ return /* @__PURE__ */ jsx(
138
+ Tag,
139
+ {
140
+ ref,
141
+ onTransitionEnd: handleTransitionEnd,
142
+ style: {
143
+ opacity,
144
+ willChange: "opacity",
145
+ ...transitionStyle,
146
+ ...style
147
+ },
148
+ ...rest,
149
+ children
150
+ }
151
+ );
152
+ });
153
+ Fade.displayName = "Fade";
154
+
155
+ // src/components/Motion/Slide.tsx
156
+ import * as React3 from "react";
157
+ import { jsx as jsx2 } from "react/jsx-runtime";
158
+ var directionTransform = {
159
+ up: { from: "translateY(12px)", to: "translateY(0)" },
160
+ down: { from: "translateY(-12px)", to: "translateY(0)" },
161
+ left: { from: "translateX(12px)", to: "translateX(0)" },
162
+ right: { from: "translateX(-12px)", to: "translateX(0)" }
163
+ };
164
+ var Slide = React3.forwardRef(function Slide2({
165
+ in: visible,
166
+ duration = "normal",
167
+ easing,
168
+ unmountOnExit = false,
169
+ direction = "up",
170
+ distance,
171
+ children,
172
+ style,
173
+ as: Tag = "div",
174
+ ...rest
175
+ }, ref) {
176
+ const { phase, mounted, reduced, transitionStyle, handleTransitionEnd } = useMotion({
177
+ visible,
178
+ duration,
179
+ easing,
180
+ unmountOnExit
181
+ });
182
+ if (!mounted) return null;
183
+ const isEntered = phase === "entered";
184
+ const dt = directionTransform[direction];
185
+ let fromTransform = dt.from;
186
+ if (distance) {
187
+ if (direction === "up") fromTransform = `translateY(${distance})`;
188
+ if (direction === "down") fromTransform = `translateY(-${distance})`;
189
+ if (direction === "left") fromTransform = `translateX(${distance})`;
190
+ if (direction === "right") fromTransform = `translateX(-${distance})`;
191
+ }
192
+ return /* @__PURE__ */ jsx2(
193
+ Tag,
194
+ {
195
+ ref,
196
+ onTransitionEnd: handleTransitionEnd,
197
+ style: {
198
+ opacity: isEntered ? 1 : 0,
199
+ transform: isEntered || reduced ? dt.to : fromTransform,
200
+ willChange: "opacity, transform",
201
+ ...transitionStyle,
202
+ ...style
203
+ },
204
+ ...rest,
205
+ children
206
+ }
207
+ );
208
+ });
209
+ Slide.displayName = "Slide";
210
+
211
+ // src/components/Motion/Scale.tsx
212
+ import * as React4 from "react";
213
+ import { jsx as jsx3 } from "react/jsx-runtime";
214
+ var Scale = React4.forwardRef(function Scale2({
215
+ in: visible,
216
+ duration = "fast",
217
+ easing,
218
+ unmountOnExit = false,
219
+ initialScale = 0.95,
220
+ children,
221
+ style,
222
+ as: Tag = "div",
223
+ ...rest
224
+ }, ref) {
225
+ const { phase, mounted, reduced, transitionStyle, handleTransitionEnd } = useMotion({
226
+ visible,
227
+ duration,
228
+ easing,
229
+ unmountOnExit
230
+ });
231
+ if (!mounted) return null;
232
+ const isEntered = phase === "entered";
233
+ return /* @__PURE__ */ jsx3(
234
+ Tag,
235
+ {
236
+ ref,
237
+ onTransitionEnd: handleTransitionEnd,
238
+ style: {
239
+ opacity: isEntered ? 1 : 0,
240
+ transform: isEntered || reduced ? "scale(1)" : `scale(${initialScale})`,
241
+ transformOrigin: "top center",
242
+ willChange: "opacity, transform",
243
+ ...transitionStyle,
244
+ ...style
245
+ },
246
+ ...rest,
247
+ children
248
+ }
249
+ );
250
+ });
251
+ Scale.displayName = "Scale";
252
+
253
+ // src/components/Motion/Collapse.tsx
254
+ import * as React5 from "react";
255
+ import { jsx as jsx4 } from "react/jsx-runtime";
256
+ var Collapse = React5.forwardRef(function Collapse2({
257
+ in: visible,
258
+ duration = "normal",
259
+ easing,
260
+ unmountOnExit = false,
261
+ collapsedHeight = 0,
262
+ children,
263
+ style,
264
+ as: Tag = "div",
265
+ ...rest
266
+ }, ref) {
267
+ const innerRef = React5.useRef(null);
268
+ const reduced = usePrefersReducedMotion();
269
+ const legacy = easing !== void 0;
270
+ const settleMs = duration === "instant" || reduced ? 0 : legacy ? DURATION_MS[duration] : SPRING_MS.spatial[SPRING_SPEED[duration]];
271
+ const [height, setHeight] = React5.useState(visible ? "auto" : 0);
272
+ const [overflow, setOverflow] = React5.useState(
273
+ visible ? "visible" : "hidden"
274
+ );
275
+ const [mounted, setMounted] = React5.useState(unmountOnExit ? visible : true);
276
+ const prevVisible = React5.useRef(visible);
277
+ React5.useEffect(() => {
278
+ const changed = prevVisible.current !== visible;
279
+ prevVisible.current = visible;
280
+ if (!changed) return;
281
+ let raf1 = 0;
282
+ let raf2 = 0;
283
+ if (visible) {
284
+ setMounted(true);
285
+ raf1 = requestAnimationFrame(() => {
286
+ const el = innerRef.current;
287
+ if (el) {
288
+ setHeight(el.scrollHeight);
289
+ setOverflow("hidden");
290
+ }
291
+ });
292
+ } else {
293
+ const el = innerRef.current;
294
+ if (el) {
295
+ setHeight(el.scrollHeight);
296
+ setOverflow("hidden");
297
+ raf1 = requestAnimationFrame(() => {
298
+ raf2 = requestAnimationFrame(() => {
299
+ setHeight(typeof collapsedHeight === "number" ? collapsedHeight : 0);
300
+ });
301
+ });
302
+ }
303
+ }
304
+ return () => {
305
+ cancelAnimationFrame(raf1);
306
+ cancelAnimationFrame(raf2);
307
+ };
308
+ }, [visible, collapsedHeight]);
309
+ const finish = React5.useCallback(() => {
310
+ if (visible) {
311
+ setHeight("auto");
312
+ setOverflow("visible");
313
+ } else if (unmountOnExit) {
314
+ setMounted(false);
315
+ }
316
+ }, [visible, unmountOnExit]);
317
+ const handleTransitionEnd = React5.useCallback(
318
+ (e) => {
319
+ if (e.target !== e.currentTarget || e.propertyName !== "max-height") return;
320
+ finish();
321
+ },
322
+ [finish]
323
+ );
324
+ const firstRender = React5.useRef(true);
325
+ React5.useEffect(() => {
326
+ if (firstRender.current) {
327
+ firstRender.current = false;
328
+ return;
329
+ }
330
+ const t = setTimeout(finish, settleMs + 100);
331
+ return () => clearTimeout(t);
332
+ }, [visible, settleMs, finish]);
333
+ if (!mounted) return null;
334
+ const maxHeight = height === "auto" ? "none" : `${height}px`;
335
+ return /* @__PURE__ */ jsx4(
336
+ Tag,
337
+ {
338
+ ref,
339
+ style: {
340
+ maxHeight,
341
+ overflow,
342
+ transition: duration === "instant" || reduced ? "none" : legacy ? `max-height var(--duration-${duration}) var(--ease-${easing})` : spring("max-height", "spatial", SPRING_SPEED[duration]),
343
+ ...style
344
+ },
345
+ onTransitionEnd: handleTransitionEnd,
346
+ ...rest,
347
+ children: /* @__PURE__ */ jsx4("div", { ref: innerRef, children })
348
+ }
349
+ );
350
+ });
351
+ Collapse.displayName = "Collapse";
352
+
353
+ // src/components/Motion/ListTransition.tsx
354
+ import * as React6 from "react";
355
+ import { jsx as jsx5, jsxs } from "react/jsx-runtime";
356
+ var EXIT_FALLBACK_MS = SPRING_MS.effects.default + 50;
357
+ function keyed(children) {
358
+ const out = [];
359
+ React6.Children.forEach(children, (child, i) => {
360
+ const key = React6.isValidElement(child) && child.key != null ? child.key : `__nx-${i}`;
361
+ out.push({ key, node: child });
362
+ });
363
+ return out;
364
+ }
365
+ function merge(prev, next) {
366
+ const before = new Map(prev.map((p) => [p.key, p]));
367
+ const nextKeys = new Set(next.map((n) => n.key));
368
+ const result = next.map((n) => {
369
+ const old = before.get(n.key);
370
+ return { ...n, state: !old || old.state === "exit" ? "enter" : old.state };
371
+ });
372
+ prev.forEach((p, i) => {
373
+ if (nextKeys.has(p.key)) return;
374
+ let at = 0;
375
+ for (let j = i - 1; j >= 0; j--) {
376
+ const idx = result.findIndex((r) => r.key === prev[j].key);
377
+ if (idx !== -1) {
378
+ at = idx + 1;
379
+ break;
380
+ }
381
+ }
382
+ result.splice(at, 0, { ...p, state: "exit" });
383
+ });
384
+ return result;
385
+ }
386
+ var ListTransition = React6.forwardRef(function ListTransition2({ as: Tag = "div", itemAs: Item = "div", appear = false, children, ...rest }, ref) {
387
+ const next = keyed(children);
388
+ const [entries, setEntries] = React6.useState(
389
+ () => next.map((n) => ({ ...n, state: appear ? "enter" : "idle" }))
390
+ );
391
+ const [prevChildren, setPrevChildren] = React6.useState(children);
392
+ let rendered = entries;
393
+ if (children !== prevChildren) {
394
+ rendered = merge(entries, next);
395
+ setPrevChildren(children);
396
+ setEntries(rendered);
397
+ }
398
+ const remove = React6.useCallback((key) => {
399
+ setEntries((list) => list.filter((e) => !(e.key === key && e.state === "exit")));
400
+ }, []);
401
+ const settle = React6.useCallback((key) => {
402
+ setEntries((list) => list.map((e) => e.key === key && e.state === "enter" ? { ...e, state: "idle" } : e));
403
+ }, []);
404
+ const exiting = rendered.filter((e) => e.state === "exit").map((e) => e.key).join("|");
405
+ React6.useEffect(() => {
406
+ if (!exiting) return;
407
+ const keys = rendered.filter((e) => e.state === "exit").map((e) => e.key);
408
+ const t = setTimeout(() => keys.forEach(remove), EXIT_FALLBACK_MS);
409
+ return () => clearTimeout(t);
410
+ }, [exiting, remove]);
411
+ return /* @__PURE__ */ jsx5(Tag, { ref, ...rest, children: rendered.map((e) => /* @__PURE__ */ jsx5(
412
+ Item,
413
+ {
414
+ className: "nx-list-item",
415
+ "data-state": e.state === "idle" ? void 0 : e.state,
416
+ "aria-hidden": e.state === "exit" ? true : void 0,
417
+ onAnimationEnd: (ev) => {
418
+ if (ev.target !== ev.currentTarget) return;
419
+ if (e.state === "exit") remove(e.key);
420
+ else if (e.state === "enter") settle(e.key);
421
+ },
422
+ children: /* @__PURE__ */ jsx5("div", { className: "nx-list-item-inner", children: e.node })
423
+ },
424
+ e.key
425
+ )) });
426
+ });
427
+ ListTransition.displayName = "ListTransition";
428
+ var SkeletonSwap = React6.forwardRef(function SkeletonSwap2({ loading, skeleton, children, className, ...rest }, ref) {
429
+ const [phase, setPhase] = React6.useState(loading ? "loading" : "done");
430
+ const [prevLoading, setPrevLoading] = React6.useState(loading);
431
+ let current = phase;
432
+ if (loading !== prevLoading) {
433
+ current = loading ? "loading" : "out";
434
+ setPrevLoading(loading);
435
+ setPhase(current);
436
+ }
437
+ React6.useEffect(() => {
438
+ if (current !== "out") return;
439
+ const t = setTimeout(() => setPhase("done"), SPRING_MS.effects.default + 50);
440
+ return () => clearTimeout(t);
441
+ }, [current]);
442
+ return /* @__PURE__ */ jsxs("div", { ref, className: className ? `nx-swap ${className}` : "nx-swap", "aria-busy": loading || void 0, ...rest, children: [
443
+ current !== "loading" && /* @__PURE__ */ jsx5("div", { className: current === "out" ? "nx-swap-in" : void 0, children }),
444
+ current !== "done" && /* @__PURE__ */ jsx5(
445
+ "div",
446
+ {
447
+ className: current === "out" ? "nx-swap-out" : void 0,
448
+ "aria-hidden": "true",
449
+ onAnimationEnd: (e) => {
450
+ if (e.target === e.currentTarget) setPhase("done");
451
+ },
452
+ children: skeleton
453
+ }
454
+ )
455
+ ] });
456
+ });
457
+ SkeletonSwap.displayName = "SkeletonSwap";
458
+
459
+ export {
460
+ useMediaQuery,
461
+ usePrefersReducedMotion,
462
+ Fade,
463
+ Slide,
464
+ Scale,
465
+ Collapse,
466
+ ListTransition,
467
+ SkeletonSwap
468
+ };
@@ -1546,7 +1546,7 @@ var ClassLockOverlay = React2.forwardRef(
1546
1546
  var Overlay3 = React2.forwardRef(
1547
1547
  ({ className, ...props }, ref) => {
1548
1548
  const { scrollLock, open, modal } = React2.useContext(DrawerContext2);
1549
- const classes = cn("fixed inset-0 z-[var(--z-modal)]", scrim, className);
1549
+ const classes = cn("nx-drawer-overlay fixed inset-0 z-[var(--z-modal)]", scrim, className);
1550
1550
  if (scrollLock === "class") {
1551
1551
  if (!modal) return null;
1552
1552
  return /* @__PURE__ */ jsx(ClassLockOverlay, { ref, open, className: cn("pointer-events-auto", classes), ...props });
@@ -1567,7 +1567,7 @@ var Content3 = React2.forwardRef(({ className, children, side = "right", surface
1567
1567
  {
1568
1568
  ref,
1569
1569
  className: cn(
1570
- "fixed z-[var(--z-modal)] flex flex-col bg-[var(--color-surface-elevated)] text-[var(--color-on-surface)] shadow-elevation-3 focus:outline-none",
1570
+ "nx-drawer fixed z-[var(--z-modal)] flex flex-col bg-[var(--color-surface-elevated)] text-[var(--color-on-surface)] shadow-elevation-3 focus:outline-none",
1571
1571
  sideMap[side],
1572
1572
  surface === "glass" && glassSurfaceClass,
1573
1573
  className
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  Drawer,
4
4
  Sheet
5
- } from "../../chunk-UVWQPDOV.js";
5
+ } from "../../chunk-6ALDF3XF.js";
6
6
  import "../../chunk-47UGX37F.js";
7
7
  import "../../chunk-5FWJXSXT.js";
8
8
  import "../../chunk-DEIBF3P7.js";
@@ -5,8 +5,8 @@ import {
5
5
  import "../../chunk-JLUCMNVS.js";
6
6
  import "../../chunk-NHUQLIHL.js";
7
7
  import "../../chunk-F7ZA2VA2.js";
8
- import "../../chunk-R3SUPKKI.js";
9
8
  import "../../chunk-5W3AOOYS.js";
9
+ import "../../chunk-R3SUPKKI.js";
10
10
  import "../../chunk-VMSWIC3O.js";
11
11
  import "../../chunk-Q7G5WGYV.js";
12
12
  export {
@@ -2,12 +2,18 @@
2
2
  import {
3
3
  Collapse,
4
4
  Fade,
5
+ ListTransition,
5
6
  Scale,
6
- Slide
7
- } from "../../chunk-FS4XKWFA.js";
7
+ SkeletonSwap,
8
+ Slide,
9
+ usePrefersReducedMotion
10
+ } from "../../chunk-4GVGS5N4.js";
8
11
  export {
9
12
  Collapse,
10
13
  Fade,
14
+ ListTransition,
11
15
  Scale,
12
- Slide
16
+ SkeletonSwap,
17
+ Slide,
18
+ usePrefersReducedMotion
13
19
  };
package/dist/index.d.ts CHANGED
@@ -1733,13 +1733,14 @@ interface MotionBaseProps {
1733
1733
  /** Whether the component is visible / mounted. */
1734
1734
  in: boolean;
1735
1735
  /**
1736
- * Token-based duration. Maps to `--duration-{value}`.
1736
+ * Speed on the spring tokens: `fast` → fast, `normal` → default,
1737
+ * `slow`/`slower` → slow springs. `instant` turns motion off.
1737
1738
  * @default 'normal'
1738
1739
  */
1739
1740
  duration?: MotionDuration;
1740
1741
  /**
1741
- * Token-based easing. Maps to `--ease-{value}`.
1742
- * @default 'out'
1742
+ * Legacy: set it to use the old `--duration-*` + `--ease-{value}` tokens
1743
+ * instead of springs. Omit it to ride the spring tokens.
1743
1744
  */
1744
1745
  easing?: MotionEasing;
1745
1746
  /**
@@ -1776,7 +1777,8 @@ interface SlideProps extends MotionBaseProps, React.HTMLAttributes<HTMLDivElemen
1776
1777
  as?: React.ElementType;
1777
1778
  }
1778
1779
  /**
1779
- * Slide — animates opacity + translate from a given direction.
1780
+ * Slide — animates opacity + translate from a given direction on the spring
1781
+ * tokens. Reduced motion keeps the fade and drops the travel.
1780
1782
  *
1781
1783
  * ```tsx
1782
1784
  * <Slide in={isOpen} direction="up">
@@ -1796,7 +1798,8 @@ interface ScaleProps extends MotionBaseProps, React.HTMLAttributes<HTMLDivElemen
1796
1798
  as?: React.ElementType;
1797
1799
  }
1798
1800
  /**
1799
- * Scale — animates opacity + scale(x) from `initialScale` to 1.
1801
+ * Scale — animates opacity + scale(x) from `initialScale` to 1 on the spring
1802
+ * tokens. Reduced motion keeps the fade and drops the scale.
1800
1803
  *
1801
1804
  * ```tsx
1802
1805
  * <Scale in={isOpen} initialScale={0.9}>
@@ -1808,8 +1811,8 @@ declare const Scale: React.ForwardRefExoticComponent<ScaleProps & React.RefAttri
1808
1811
 
1809
1812
  interface CollapseProps extends Omit<MotionBaseProps, 'easing'>, React.HTMLAttributes<HTMLDivElement> {
1810
1813
  /**
1811
- * Easing for the height transition.
1812
- * @default 'out'
1814
+ * Legacy: set it to use `--duration-*` + `--ease-{value}` instead of the
1815
+ * spatial spring for the height transition.
1813
1816
  */
1814
1817
  easing?: MotionBaseProps['easing'];
1815
1818
  /**
@@ -1821,7 +1824,8 @@ interface CollapseProps extends Omit<MotionBaseProps, 'easing'>, React.HTMLAttri
1821
1824
  as?: React.ElementType;
1822
1825
  }
1823
1826
  /**
1824
- * Collapse — animates `max-height` to reveal / hide content.
1827
+ * Collapse — animates `max-height` to reveal / hide content on the spatial
1828
+ * spring. Reduced motion snaps the height instead of animating it.
1825
1829
  * Height is measured from the content ref so you don't need to
1826
1830
  * provide an explicit height.
1827
1831
  *
@@ -1833,4 +1837,53 @@ interface CollapseProps extends Omit<MotionBaseProps, 'easing'>, React.HTMLAttri
1833
1837
  */
1834
1838
  declare const Collapse: React.ForwardRefExoticComponent<CollapseProps & React.RefAttributes<HTMLDivElement>>;
1835
1839
 
1836
- export { Accordion, Alert, AlertDialog, type AlertProps, Amount, type AmountProps, AppShell, AspectRatio, type AspectRatioProps, Autocomplete, type AutocompleteOption, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Badge, type BadgeProps, Banner, type BannerProps, Box, type BoxProps, Breadcrumb, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonStatus, Callout, type CalloutProps, Card, CardLink, type CardLinkProps, type CardProps, CheckList, CheckListItem, type CheckListItemProps, type CheckListProps, Checkbox, CheckboxCard, type CheckboxCardProps, type CheckboxProps, Chip, type ChipProps, Citation, type CitationMessages, type CitationProps, type CitationSource, Code, type CodeProps, Collapse, type CollapseProps, Collapsible, Combobox, CommandPalette, type CommandPaletteRootProps, Container, type ContainerProps, ContextMenu, CountryBadge, type CountryBadgeProps, DataTable, type DataTableColumn, type DataTableProps, DatePicker, type DatePickerProps, DateRangePicker, type DateRangePickerProps, Dialog, Drawer, type DrawerRootProps, DropdownMenu, EmptyState, ErrorState, type ErrorStateProps, EyebrowChip, type EyebrowChipProps, Fade, type FadeProps, type Feedback, FileUpload, type FileUploadRootProps, FilterChip, type FilterChipProps, Flag, type FlagProps, Flex, type FlexProps, FormError, type FormErrorProps, FormField, type FormFieldContextValue, type FormFieldRootProps, GradientDivider, type GradientDividerProps, Grid, type GridProps, Heading, type HeadingProps, HelperText, type HelperTextProps, HoverCard, IconButton, type IconButtonProps, Input, type InputProps, Kbd, type KbdProps, KeyboardShortcut, type KeyboardShortcutProps, Label, type LabelProps, Link, type LinkProps, Logo, type LogoProps, MediaCard, type MediaCardProps, type MediaCardRatio, Menubar, MessageActions, type MessageActionsProps, MessageBubble, type MessageBubbleProps, type MessageFrom, type MessageStrings, MoneyInput, type MoneyInputProps, type MotionBaseProps, type MotionDuration, type MotionEasing, NavigationMenu, NavigationRail, type NavigationRailItemProps, type NavigationRailRootProps, NexubProvider, type NexubProviderProps, NumberInput, type NumberInputProps, NumberTicker, type NumberTickerPart, type NumberTickerProps, PageHeader, type PageHeaderProps, Pagination, type PaginationProps, PasswordInput, type PasswordInputProps, Popover, Progress, type ProgressProps, PromptInput, type PromptInputMessages, type PromptInputProps, type PromptInputStatus, RadioCard, RadioCardGroup, type RadioCardGroupProps, type RadioCardProps, RadioGroup, Rating, type RatingProps, Scale, type ScaleProps, ScrollArea, type ScrollAreaProps, SearchInput, type SearchInputProps, Section, type SectionProps, SegmentedControl, type SegmentedControlItemProps, type SegmentedControlProps, Select, Separator, type SeparatorProps, Sheet, Sidebar, type SidebarGroupProps, type SidebarHeaderProps, type SidebarItemProps, type SidebarRootProps, Skeleton, type SkeletonProps, Slide, type SlideDirection, type SlideProps, Slider, type SliderProps, SourceChip, type SourceChipProps, SourceList, type SourceListProps, Spinner, type SpinnerProps, SplitButton, type SplitButtonProps, Stack, type StackProps, StatusPill, type StatusPillProps, StreamingText, type StreamingTextProps, Switch, type SwitchProps, Table, type TableRootProps, Tabs, Tag, type TagProps, Text, TextGradient, type TextGradientProps, type TextProps, Textarea, type TextareaProps, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeScript, type ThemeScriptProps, ThinkingIndicator, type ThinkingIndicatorMessages, type ThinkingIndicatorProps, Toast, type ToastItem, Toaster, type ToasterProps, Toggle, ToggleGroup, type ToggleProps, Toolbar, type ToolbarRootProps, Tooltip, Provider$1 as TooltipProvider, TopNav, type TopNavItemProps, type TopNavRootProps, type UndoableToastOptions, addonVariants, alertVariants, avatarGroupVariants, avatarVariants, badgeVariants, bannerVariants, buttonVariants, calloutVariants, cardVariants, chipVariants, cn, containerVariants, defaultMessageStrings, headingVariants, iconButtonVariants, inputVariants, inputWrapperVariants, labelVariants, linkVariants, logoVariants, progressFillVariants, progressTrackVariants, ratingVariants, safeUrl, sectionVariants, separatorVariants, skeletonVariants, spinnerVariants, startViewTransition, statusPillVariants, tagVariants, textVariants, textareaVariants, toast, toggleVariants, useControllableState, useDisclosure, useIsomorphicLayoutEffect, useLocale, useMediaQuery, useMergedRefs, useNexubMessages, usePointerSheen, useTheme, useToastStore };
1840
+ interface ListTransitionProps extends React.HTMLAttributes<HTMLElement> {
1841
+ /** List element. @default 'div' */
1842
+ as?: React.ElementType;
1843
+ /** Element wrapping each item, e.g. `'li'` inside a `'ul'`. @default 'div' */
1844
+ itemAs?: React.ElementType;
1845
+ /** Animate the items present on first render too. @default false */
1846
+ appear?: boolean;
1847
+ /** Keyed children. Items without a key are rendered but never animated. */
1848
+ children?: React.ReactNode;
1849
+ }
1850
+ /**
1851
+ * ListTransition — animates keyed items in and out of a list.
1852
+ * New items grow in from zero height and fade in; removed items stay in place
1853
+ * while they collapse and fade out, then unmount. Uses CSS keyframes on the
1854
+ * spring tokens (`nx-list-item` in `@nexub/themes/base`); reduced motion keeps
1855
+ * only the fade.
1856
+ *
1857
+ * Space items with padding inside each item, not `gap`, so a collapsing item
1858
+ * takes its spacing with it.
1859
+ *
1860
+ * ```tsx
1861
+ * <ListTransition as="ul" itemAs="li">
1862
+ * {items.map((item) => <Row key={item.id} item={item} />)}
1863
+ * </ListTransition>
1864
+ * ```
1865
+ */
1866
+ declare const ListTransition: React.ForwardRefExoticComponent<ListTransitionProps & React.RefAttributes<HTMLElement>>;
1867
+ interface SkeletonSwapProps extends React.HTMLAttributes<HTMLDivElement> {
1868
+ /** While true the skeleton shows; flipping to false crossfades to the content. */
1869
+ loading: boolean;
1870
+ /** Placeholder shown while loading, usually `Skeleton`s shaped like the content. */
1871
+ skeleton: React.ReactNode;
1872
+ children?: React.ReactNode;
1873
+ }
1874
+ /**
1875
+ * SkeletonSwap — crossfades from a skeleton to the loaded content in place,
1876
+ * instead of popping. Sets `aria-busy` while loading.
1877
+ *
1878
+ * ```tsx
1879
+ * <SkeletonSwap loading={isLoading} skeleton={<Skeleton shape="rect" height={120} />}>
1880
+ * <Card>…</Card>
1881
+ * </SkeletonSwap>
1882
+ * ```
1883
+ */
1884
+ declare const SkeletonSwap: React.ForwardRefExoticComponent<SkeletonSwapProps & React.RefAttributes<HTMLDivElement>>;
1885
+
1886
+ /** True when the user asked the OS for reduced motion. False during SSR. */
1887
+ declare function usePrefersReducedMotion(): boolean;
1888
+
1889
+ export { Accordion, Alert, AlertDialog, type AlertProps, Amount, type AmountProps, AppShell, AspectRatio, type AspectRatioProps, Autocomplete, type AutocompleteOption, type AutocompleteProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Badge, type BadgeProps, Banner, type BannerProps, Box, type BoxProps, Breadcrumb, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonStatus, Callout, type CalloutProps, Card, CardLink, type CardLinkProps, type CardProps, CheckList, CheckListItem, type CheckListItemProps, type CheckListProps, Checkbox, CheckboxCard, type CheckboxCardProps, type CheckboxProps, Chip, type ChipProps, Citation, type CitationMessages, type CitationProps, type CitationSource, Code, type CodeProps, Collapse, type CollapseProps, Collapsible, Combobox, CommandPalette, type CommandPaletteRootProps, Container, type ContainerProps, ContextMenu, CountryBadge, type CountryBadgeProps, DataTable, type DataTableColumn, type DataTableProps, DatePicker, type DatePickerProps, DateRangePicker, type DateRangePickerProps, Dialog, Drawer, type DrawerRootProps, DropdownMenu, EmptyState, ErrorState, type ErrorStateProps, EyebrowChip, type EyebrowChipProps, Fade, type FadeProps, type Feedback, FileUpload, type FileUploadRootProps, FilterChip, type FilterChipProps, Flag, type FlagProps, Flex, type FlexProps, FormError, type FormErrorProps, FormField, type FormFieldContextValue, type FormFieldRootProps, GradientDivider, type GradientDividerProps, Grid, type GridProps, Heading, type HeadingProps, HelperText, type HelperTextProps, HoverCard, IconButton, type IconButtonProps, Input, type InputProps, Kbd, type KbdProps, KeyboardShortcut, type KeyboardShortcutProps, Label, type LabelProps, Link, type LinkProps, ListTransition, type ListTransitionProps, Logo, type LogoProps, MediaCard, type MediaCardProps, type MediaCardRatio, Menubar, MessageActions, type MessageActionsProps, MessageBubble, type MessageBubbleProps, type MessageFrom, type MessageStrings, MoneyInput, type MoneyInputProps, type MotionBaseProps, type MotionDuration, type MotionEasing, NavigationMenu, NavigationRail, type NavigationRailItemProps, type NavigationRailRootProps, NexubProvider, type NexubProviderProps, NumberInput, type NumberInputProps, NumberTicker, type NumberTickerPart, type NumberTickerProps, PageHeader, type PageHeaderProps, Pagination, type PaginationProps, PasswordInput, type PasswordInputProps, Popover, Progress, type ProgressProps, PromptInput, type PromptInputMessages, type PromptInputProps, type PromptInputStatus, RadioCard, RadioCardGroup, type RadioCardGroupProps, type RadioCardProps, RadioGroup, Rating, type RatingProps, Scale, type ScaleProps, ScrollArea, type ScrollAreaProps, SearchInput, type SearchInputProps, Section, type SectionProps, SegmentedControl, type SegmentedControlItemProps, type SegmentedControlProps, Select, Separator, type SeparatorProps, Sheet, Sidebar, type SidebarGroupProps, type SidebarHeaderProps, type SidebarItemProps, type SidebarRootProps, Skeleton, type SkeletonProps, SkeletonSwap, type SkeletonSwapProps, Slide, type SlideDirection, type SlideProps, Slider, type SliderProps, SourceChip, type SourceChipProps, SourceList, type SourceListProps, Spinner, type SpinnerProps, SplitButton, type SplitButtonProps, Stack, type StackProps, StatusPill, type StatusPillProps, StreamingText, type StreamingTextProps, Switch, type SwitchProps, Table, type TableRootProps, Tabs, Tag, type TagProps, Text, TextGradient, type TextGradientProps, type TextProps, Textarea, type TextareaProps, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeScript, type ThemeScriptProps, ThinkingIndicator, type ThinkingIndicatorMessages, type ThinkingIndicatorProps, Toast, type ToastItem, Toaster, type ToasterProps, Toggle, ToggleGroup, type ToggleProps, Toolbar, type ToolbarRootProps, Tooltip, Provider$1 as TooltipProvider, TopNav, type TopNavItemProps, type TopNavRootProps, type UndoableToastOptions, addonVariants, alertVariants, avatarGroupVariants, avatarVariants, badgeVariants, bannerVariants, buttonVariants, calloutVariants, cardVariants, chipVariants, cn, containerVariants, defaultMessageStrings, headingVariants, iconButtonVariants, inputVariants, inputWrapperVariants, labelVariants, linkVariants, logoVariants, progressFillVariants, progressTrackVariants, ratingVariants, safeUrl, sectionVariants, separatorVariants, skeletonVariants, spinnerVariants, startViewTransition, statusPillVariants, tagVariants, textVariants, textareaVariants, toast, toggleVariants, useControllableState, useDisclosure, useIsomorphicLayoutEffect, useLocale, useMediaQuery, useMergedRefs, useNexubMessages, usePointerSheen, usePrefersReducedMotion, useTheme, useToastStore };
package/dist/index.js CHANGED
@@ -1,7 +1,5 @@
1
1
  'use client';
2
- import {
3
- TopNav
4
- } from "./chunk-ZVQYAIOA.js";
2
+ import "./chunk-XYXMPHND.js";
5
3
  import {
6
4
  Root
7
5
  } from "./chunk-ZXLACKEB.js";
@@ -14,9 +12,6 @@ import {
14
12
  ThemeScript,
15
13
  useTheme
16
14
  } from "./chunk-3XX45SUC.js";
17
- import {
18
- ThinkingIndicator
19
- } from "./chunk-D7HMUIA5.js";
20
15
  import {
21
16
  Toast,
22
17
  Toaster,
@@ -24,6 +19,12 @@ import {
24
19
  useToastStore
25
20
  } from "./chunk-I6ELDWZE.js";
26
21
  import "./chunk-YJU4ZRQZ.js";
22
+ import {
23
+ ThinkingIndicator
24
+ } from "./chunk-D7HMUIA5.js";
25
+ import {
26
+ Toolbar
27
+ } from "./chunk-2ZBJOUJ7.js";
27
28
  import {
28
29
  ToggleGroup
29
30
  } from "./chunk-DYWJ7BIK.js";
@@ -32,23 +33,22 @@ import {
32
33
  toggleVariants
33
34
  } from "./chunk-3TMIZQPR.js";
34
35
  import {
35
- Toolbar
36
- } from "./chunk-2ZBJOUJ7.js";
37
- import "./chunk-XYXMPHND.js";
38
- import {
39
- StreamingText
40
- } from "./chunk-5QEARXY3.js";
36
+ TopNav
37
+ } from "./chunk-ZVQYAIOA.js";
41
38
  import {
42
39
  StatusPill,
43
40
  statusPillVariants
44
41
  } from "./chunk-77LYWSJW.js";
42
+ import {
43
+ StreamingText
44
+ } from "./chunk-5QEARXY3.js";
45
45
  import {
46
46
  Switch
47
47
  } from "./chunk-BTYDDKRQ.js";
48
+ import "./chunk-4B4XWDAH.js";
48
49
  import {
49
50
  Tabs
50
51
  } from "./chunk-CKFRMCZ7.js";
51
- import "./chunk-4B4XWDAH.js";
52
52
  import {
53
53
  Tag,
54
54
  tagVariants
@@ -87,13 +87,13 @@ import {
87
87
  import {
88
88
  Stack
89
89
  } from "./chunk-I6CAF7C5.js";
90
- import {
91
- PromptInput
92
- } from "./chunk-VMMZHSZL.js";
93
90
  import {
94
91
  RadioCard,
95
92
  RadioCardGroup
96
93
  } from "./chunk-XTATJMY6.js";
94
+ import {
95
+ PromptInput
96
+ } from "./chunk-VMMZHSZL.js";
97
97
  import {
98
98
  RadioGroup
99
99
  } from "./chunk-Z3HF6XJ3.js";
@@ -118,10 +118,10 @@ import "./chunk-6UKNUI46.js";
118
118
  import {
119
119
  useMergedRefs
120
120
  } from "./chunk-MNEXMMLM.js";
121
- import "./chunk-A3O23F2B.js";
122
121
  import {
123
122
  NumberInput
124
123
  } from "./chunk-7JXJOYM6.js";
124
+ import "./chunk-A3O23F2B.js";
125
125
  import "./chunk-WLRRMT6W.js";
126
126
  import {
127
127
  PageHeader
@@ -129,12 +129,12 @@ import {
129
129
  import {
130
130
  Pagination
131
131
  } from "./chunk-AKV4GMIY.js";
132
- import {
133
- Popover
134
- } from "./chunk-NORCPKRD.js";
135
132
  import {
136
133
  PasswordInput
137
134
  } from "./chunk-TSBBWYDO.js";
135
+ import {
136
+ Popover
137
+ } from "./chunk-NORCPKRD.js";
138
138
  import {
139
139
  Progress,
140
140
  progressFillVariants,
@@ -147,6 +147,9 @@ import {
147
147
  import {
148
148
  MediaCard
149
149
  } from "./chunk-3QD76BKT.js";
150
+ import {
151
+ Menubar
152
+ } from "./chunk-VF6RWEKX.js";
150
153
  import {
151
154
  MessageActions,
152
155
  MessageBubble,
@@ -156,9 +159,6 @@ import {
156
159
  Provider,
157
160
  Tooltip
158
161
  } from "./chunk-XQDD76EF.js";
159
- import {
160
- Menubar
161
- } from "./chunk-VF6RWEKX.js";
162
162
  import {
163
163
  MoneyInput
164
164
  } from "./chunk-6FRG6NMM.js";
@@ -171,9 +171,13 @@ import {
171
171
  import {
172
172
  Collapse,
173
173
  Fade,
174
+ ListTransition,
174
175
  Scale,
175
- Slide
176
- } from "./chunk-FS4XKWFA.js";
176
+ SkeletonSwap,
177
+ Slide,
178
+ useMediaQuery,
179
+ usePrefersReducedMotion
180
+ } from "./chunk-4GVGS5N4.js";
177
181
  import {
178
182
  NavigationMenu
179
183
  } from "./chunk-BEOHZKPQ.js";
@@ -210,10 +214,13 @@ import {
210
214
  FilterChip
211
215
  } from "./chunk-NN7SNECM.js";
212
216
  import "./chunk-BV3U3ATL.js";
213
- import "./chunk-ADO2DB6Q.js";
214
217
  import {
215
218
  Flex
216
219
  } from "./chunk-7MSIOYJZ.js";
220
+ import "./chunk-ADO2DB6Q.js";
221
+ import {
222
+ GradientDivider
223
+ } from "./chunk-ZC4MZAEX.js";
217
224
  import {
218
225
  FormField
219
226
  } from "./chunk-G4RLUGE3.js";
@@ -227,9 +234,6 @@ import {
227
234
  import {
228
235
  FormError
229
236
  } from "./chunk-QVTVDL6Y.js";
230
- import {
231
- GradientDivider
232
- } from "./chunk-ZC4MZAEX.js";
233
237
  import {
234
238
  Grid
235
239
  } from "./chunk-6JBQAJJD.js";
@@ -247,7 +251,7 @@ import {
247
251
  import {
248
252
  Drawer,
249
253
  Sheet
250
- } from "./chunk-UVWQPDOV.js";
254
+ } from "./chunk-6ALDF3XF.js";
251
255
  import "./chunk-HI7GBSW2.js";
252
256
  import {
253
257
  DropdownMenu
@@ -258,12 +262,12 @@ import {
258
262
  import {
259
263
  ErrorState
260
264
  } from "./chunk-SZNSQR2B.js";
261
- import {
262
- EyebrowChip
263
- } from "./chunk-322WR6EU.js";
264
265
  import {
265
266
  FileUpload
266
267
  } from "./chunk-D6HHYT2S.js";
268
+ import {
269
+ EyebrowChip
270
+ } from "./chunk-322WR6EU.js";
267
271
  import {
268
272
  Collapsible
269
273
  } from "./chunk-3LP2CR7F.js";
@@ -367,13 +371,6 @@ import {
367
371
  Alert,
368
372
  alertVariants
369
373
  } from "./chunk-TXIJMUD5.js";
370
- import {
371
- Amount
372
- } from "./chunk-ZYR3R36N.js";
373
- import {
374
- NumberTicker
375
- } from "./chunk-2BAXCPQF.js";
376
- import "./chunk-R3SUPKKI.js";
377
374
  import {
378
375
  AlertDialog
379
376
  } from "./chunk-TSN6HYVY.js";
@@ -384,6 +381,13 @@ import {
384
381
  } from "./chunk-22BGPRJZ.js";
385
382
  import "./chunk-5W3AOOYS.js";
386
383
  import "./chunk-DEIBF3P7.js";
384
+ import {
385
+ Amount
386
+ } from "./chunk-ZYR3R36N.js";
387
+ import {
388
+ NumberTicker
389
+ } from "./chunk-2BAXCPQF.js";
390
+ import "./chunk-R3SUPKKI.js";
387
391
  import {
388
392
  AppShell
389
393
  } from "./chunk-56FERRWW.js";
@@ -422,21 +426,6 @@ function useDisclosure(initialOpen = false) {
422
426
  const toggle = useCallback(() => setIsOpen((prev) => !prev), []);
423
427
  return { isOpen, open, close, toggle };
424
428
  }
425
-
426
- // src/hooks/useMediaQuery.ts
427
- import { useState as useState2, useEffect } from "react";
428
- function useMediaQuery(query) {
429
- const [matches, setMatches] = useState2(false);
430
- useEffect(() => {
431
- if (typeof window === "undefined") return;
432
- const mql = window.matchMedia(query);
433
- const handler = (e) => setMatches(e.matches);
434
- mql.addEventListener("change", handler);
435
- setMatches(mql.matches);
436
- return () => mql.removeEventListener("change", handler);
437
- }, [query]);
438
- return matches;
439
- }
440
429
  export {
441
430
  Accordion,
442
431
  Alert,
@@ -497,6 +486,7 @@ export {
497
486
  KeyboardShortcut,
498
487
  Label,
499
488
  Link,
489
+ ListTransition,
500
490
  Logo,
501
491
  MediaCard,
502
492
  Menubar,
@@ -528,6 +518,7 @@ export {
528
518
  Sheet,
529
519
  Sidebar,
530
520
  Skeleton,
521
+ SkeletonSwap,
531
522
  Slide,
532
523
  Slider,
533
524
  SourceChip,
@@ -600,6 +591,7 @@ export {
600
591
  useMergedRefs,
601
592
  useNexubMessages,
602
593
  usePointerSheen,
594
+ usePrefersReducedMotion,
603
595
  useTheme,
604
596
  useToastStore
605
597
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexub/react",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "React component library for Nexub Design System — 90+ accessible, themeable UI components built on Radix UI primitives.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -68,13 +68,13 @@
68
68
  "date-fns": "^4.4.0",
69
69
  "react-day-picker": "^9.14.0",
70
70
  "tailwind-merge": "^2.6.1",
71
- "@nexub/core": "2.1.0",
72
- "@nexub/icons": "2.1.0"
71
+ "@nexub/core": "2.2.0",
72
+ "@nexub/icons": "2.2.0"
73
73
  },
74
74
  "peerDependencies": {
75
75
  "react": ">=18 <20",
76
76
  "react-dom": ">=18 <20",
77
- "@nexub/tokens": "^2.1.0"
77
+ "@nexub/tokens": "^2.2.0"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@playwright/test": "1.64.0",
@@ -99,8 +99,8 @@
99
99
  "vaul": "1.1.2",
100
100
  "vite": "^7.3.7",
101
101
  "vitest": "^5.0.5",
102
- "@nexub/themes": "2.1.0",
103
- "@nexub/tokens": "2.1.0"
102
+ "@nexub/themes": "2.2.0",
103
+ "@nexub/tokens": "2.2.0"
104
104
  },
105
105
  "scripts": {
106
106
  "build": "tsup && node scripts/check-dts.mjs",
@@ -1,308 +0,0 @@
1
- 'use client';
2
-
3
- // src/components/Motion/Fade.tsx
4
- import * as React2 from "react";
5
-
6
- // src/components/Motion/useMotion.ts
7
- import * as React from "react";
8
- var DURATION_MS = {
9
- instant: 0,
10
- fast: 150,
11
- normal: 200,
12
- slow: 300,
13
- slower: 500
14
- };
15
- var FALLBACK_MARGIN_MS = 50;
16
- function useMotion({
17
- visible,
18
- duration = "normal",
19
- easing = "out",
20
- unmountOnExit = false
21
- }) {
22
- const [phase, setPhase] = React.useState(
23
- visible ? "entered" : "exited"
24
- );
25
- const rafRef = React.useRef(null);
26
- const isMounted = React.useRef(true);
27
- React.useEffect(() => {
28
- isMounted.current = true;
29
- return () => {
30
- isMounted.current = false;
31
- if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
32
- };
33
- }, []);
34
- const prevVisible = React.useRef(visible);
35
- React.useEffect(() => {
36
- if (prevVisible.current === visible) return;
37
- prevVisible.current = visible;
38
- if (visible) {
39
- setPhase("entering");
40
- rafRef.current = requestAnimationFrame(() => {
41
- rafRef.current = requestAnimationFrame(() => {
42
- if (isMounted.current) setPhase("entered");
43
- });
44
- });
45
- } else {
46
- setPhase("exiting");
47
- }
48
- }, [visible]);
49
- React.useEffect(() => {
50
- if (phase !== "exiting") return;
51
- const t = setTimeout(() => setPhase("exited"), DURATION_MS[duration] + FALLBACK_MARGIN_MS);
52
- return () => clearTimeout(t);
53
- }, [phase, duration]);
54
- const handleTransitionEnd = React.useCallback((e) => {
55
- if (!isMounted.current) return;
56
- if (e && e.target !== e.currentTarget) return;
57
- setPhase((prev) => prev === "exiting" ? "exited" : prev);
58
- }, []);
59
- const mounted = unmountOnExit ? phase !== "exited" : true;
60
- const transitionStyle = {
61
- transitionDuration: `var(--duration-${duration})`,
62
- transitionTimingFunction: `var(--ease-${easing})`,
63
- transitionProperty: "opacity, transform"
64
- };
65
- return { phase, mounted, transitionStyle, handleTransitionEnd };
66
- }
67
-
68
- // src/components/Motion/Fade.tsx
69
- import { jsx } from "react/jsx-runtime";
70
- var Fade = React2.forwardRef(function Fade2({
71
- in: visible,
72
- duration = "normal",
73
- easing = "out",
74
- unmountOnExit = false,
75
- children,
76
- style,
77
- as: Tag = "div",
78
- ...rest
79
- }, ref) {
80
- const { phase, mounted, transitionStyle, handleTransitionEnd } = useMotion({
81
- visible,
82
- duration,
83
- easing,
84
- unmountOnExit
85
- });
86
- if (!mounted) return null;
87
- const opacity = phase === "entered" ? 1 : 0;
88
- return /* @__PURE__ */ jsx(
89
- Tag,
90
- {
91
- ref,
92
- onTransitionEnd: handleTransitionEnd,
93
- style: {
94
- opacity,
95
- willChange: "opacity",
96
- ...transitionStyle,
97
- ...style
98
- },
99
- ...rest,
100
- children
101
- }
102
- );
103
- });
104
- Fade.displayName = "Fade";
105
-
106
- // src/components/Motion/Slide.tsx
107
- import * as React3 from "react";
108
- import { jsx as jsx2 } from "react/jsx-runtime";
109
- var directionTransform = {
110
- up: { from: "translateY(12px)", to: "translateY(0)" },
111
- down: { from: "translateY(-12px)", to: "translateY(0)" },
112
- left: { from: "translateX(12px)", to: "translateX(0)" },
113
- right: { from: "translateX(-12px)", to: "translateX(0)" }
114
- };
115
- var Slide = React3.forwardRef(function Slide2({
116
- in: visible,
117
- duration = "normal",
118
- easing = "out",
119
- unmountOnExit = false,
120
- direction = "up",
121
- distance,
122
- children,
123
- style,
124
- as: Tag = "div",
125
- ...rest
126
- }, ref) {
127
- const { phase, mounted, transitionStyle, handleTransitionEnd } = useMotion({
128
- visible,
129
- duration,
130
- easing,
131
- unmountOnExit
132
- });
133
- if (!mounted) return null;
134
- const isEntered = phase === "entered";
135
- const dt = directionTransform[direction];
136
- let fromTransform = dt.from;
137
- if (distance) {
138
- if (direction === "up") fromTransform = `translateY(${distance})`;
139
- if (direction === "down") fromTransform = `translateY(-${distance})`;
140
- if (direction === "left") fromTransform = `translateX(${distance})`;
141
- if (direction === "right") fromTransform = `translateX(-${distance})`;
142
- }
143
- return /* @__PURE__ */ jsx2(
144
- Tag,
145
- {
146
- ref,
147
- onTransitionEnd: handleTransitionEnd,
148
- style: {
149
- opacity: isEntered ? 1 : 0,
150
- transform: isEntered ? dt.to : fromTransform,
151
- willChange: "opacity, transform",
152
- ...transitionStyle,
153
- ...style
154
- },
155
- ...rest,
156
- children
157
- }
158
- );
159
- });
160
- Slide.displayName = "Slide";
161
-
162
- // src/components/Motion/Scale.tsx
163
- import * as React4 from "react";
164
- import { jsx as jsx3 } from "react/jsx-runtime";
165
- var Scale = React4.forwardRef(function Scale2({
166
- in: visible,
167
- duration = "fast",
168
- easing = "out-expo",
169
- unmountOnExit = false,
170
- initialScale = 0.95,
171
- children,
172
- style,
173
- as: Tag = "div",
174
- ...rest
175
- }, ref) {
176
- const { phase, mounted, transitionStyle, handleTransitionEnd } = useMotion({
177
- visible,
178
- duration,
179
- easing,
180
- unmountOnExit
181
- });
182
- if (!mounted) return null;
183
- const isEntered = phase === "entered";
184
- return /* @__PURE__ */ jsx3(
185
- Tag,
186
- {
187
- ref,
188
- onTransitionEnd: handleTransitionEnd,
189
- style: {
190
- opacity: isEntered ? 1 : 0,
191
- transform: isEntered ? "scale(1)" : `scale(${initialScale})`,
192
- transformOrigin: "top center",
193
- willChange: "opacity, transform",
194
- ...transitionStyle,
195
- ...style
196
- },
197
- ...rest,
198
- children
199
- }
200
- );
201
- });
202
- Scale.displayName = "Scale";
203
-
204
- // src/components/Motion/Collapse.tsx
205
- import * as React5 from "react";
206
- import { jsx as jsx4 } from "react/jsx-runtime";
207
- var Collapse = React5.forwardRef(function Collapse2({
208
- in: visible,
209
- duration = "normal",
210
- easing = "out",
211
- unmountOnExit = false,
212
- collapsedHeight = 0,
213
- children,
214
- style,
215
- as: Tag = "div",
216
- ...rest
217
- }, ref) {
218
- const innerRef = React5.useRef(null);
219
- const [height, setHeight] = React5.useState(visible ? "auto" : 0);
220
- const [overflow, setOverflow] = React5.useState(
221
- visible ? "visible" : "hidden"
222
- );
223
- const [mounted, setMounted] = React5.useState(unmountOnExit ? visible : true);
224
- const prevVisible = React5.useRef(visible);
225
- React5.useEffect(() => {
226
- const changed = prevVisible.current !== visible;
227
- prevVisible.current = visible;
228
- if (!changed) return;
229
- let raf1 = 0;
230
- let raf2 = 0;
231
- if (visible) {
232
- setMounted(true);
233
- raf1 = requestAnimationFrame(() => {
234
- const el = innerRef.current;
235
- if (el) {
236
- setHeight(el.scrollHeight);
237
- setOverflow("hidden");
238
- }
239
- });
240
- } else {
241
- const el = innerRef.current;
242
- if (el) {
243
- setHeight(el.scrollHeight);
244
- setOverflow("hidden");
245
- raf1 = requestAnimationFrame(() => {
246
- raf2 = requestAnimationFrame(() => {
247
- setHeight(typeof collapsedHeight === "number" ? collapsedHeight : 0);
248
- });
249
- });
250
- }
251
- }
252
- return () => {
253
- cancelAnimationFrame(raf1);
254
- cancelAnimationFrame(raf2);
255
- };
256
- }, [visible, collapsedHeight]);
257
- const finish = React5.useCallback(() => {
258
- if (visible) {
259
- setHeight("auto");
260
- setOverflow("visible");
261
- } else if (unmountOnExit) {
262
- setMounted(false);
263
- }
264
- }, [visible, unmountOnExit]);
265
- const handleTransitionEnd = React5.useCallback(
266
- (e) => {
267
- if (e.target !== e.currentTarget || e.propertyName !== "max-height") return;
268
- finish();
269
- },
270
- [finish]
271
- );
272
- const firstRender = React5.useRef(true);
273
- React5.useEffect(() => {
274
- if (firstRender.current) {
275
- firstRender.current = false;
276
- return;
277
- }
278
- const t = setTimeout(finish, DURATION_MS[duration] + 100);
279
- return () => clearTimeout(t);
280
- }, [visible, duration, finish]);
281
- if (!mounted) return null;
282
- const maxHeight = height === "auto" ? "none" : `${height}px`;
283
- return /* @__PURE__ */ jsx4(
284
- Tag,
285
- {
286
- ref,
287
- style: {
288
- maxHeight,
289
- overflow,
290
- transitionProperty: "max-height",
291
- transitionDuration: `var(--duration-${duration})`,
292
- transitionTimingFunction: `var(--ease-${easing})`,
293
- ...style
294
- },
295
- onTransitionEnd: handleTransitionEnd,
296
- ...rest,
297
- children: /* @__PURE__ */ jsx4("div", { ref: innerRef, children })
298
- }
299
- );
300
- });
301
- Collapse.displayName = "Collapse";
302
-
303
- export {
304
- Fade,
305
- Slide,
306
- Scale,
307
- Collapse
308
- };