@hexdspace/react 0.1.18 → 0.1.19

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 (2) hide show
  1. package/dist/index.js +139 -58
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -1542,26 +1542,20 @@ Button.displayName = "Button";
1542
1542
 
1543
1543
  // src/ui/components/dialog/Dialog.tsx
1544
1544
  import { cva as cva2 } from "class-variance-authority";
1545
+ import { AnimatePresence, motion } from "motion/react";
1545
1546
  import { XIcon } from "lucide-react";
1546
1547
  import { Dialog as DialogPrimitive } from "radix-ui";
1547
1548
  import * as React2 from "react";
1548
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1549
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1549
1550
  var dialogPanelVariants = cva2(
1550
1551
  cn(
1551
1552
  "fixed left-1/2 top-1/2",
1552
1553
  "-translate-x-1/2 -translate-y-1/2",
1553
1554
  "w-[min(92vw,var(--dialog-width))]",
1554
- "pointer-events-auto",
1555
- "data-[state=open]:transition-opacity duration-[var(--motion-med)]",
1556
- "data-[state=closed]:animate-[dialog-fade-out_var(--motion-med)]",
1557
- "data-[state=closed]:pointer-events-none"
1555
+ "pointer-events-auto"
1558
1556
  )
1559
1557
  );
1560
- var dialogOverlayClass = cn(
1561
- "fixed inset-0 bg-[color:var(--overlay)]",
1562
- "data-[state=closed]:animate-[dialog-overlay-out_var(--motion-med)_cubic-bezier(0.2,0,0.2,1)]",
1563
- "data-[state=closed]:pointer-events-none"
1564
- );
1558
+ var dialogOverlayClass = cn("fixed inset-0 bg-[color:var(--overlay)]");
1565
1559
  var dialogSurfaceVariants = cva2("dialog-surface relative overflow-hidden", {
1566
1560
  variants: {
1567
1561
  chrome: {
@@ -1597,7 +1591,8 @@ function DialogContent({ className, ...props }) {
1597
1591
  function AutoHeight({
1598
1592
  children,
1599
1593
  onReady,
1600
- resetKey
1594
+ resetKey,
1595
+ durationSeconds
1601
1596
  }) {
1602
1597
  const ref = React2.useRef(null);
1603
1598
  const [height, setHeight] = React2.useState("auto");
@@ -1638,11 +1633,12 @@ function AutoHeight({
1638
1633
  };
1639
1634
  }, [onReady]);
1640
1635
  return /* @__PURE__ */ jsx7(
1641
- "div",
1636
+ motion.div,
1642
1637
  {
1643
- className: cn("transition-[height] duration-(--motion-med) ease"),
1638
+ animate: { height: height === "auto" ? "auto" : height },
1639
+ initial: false,
1640
+ transition: { duration: durationSeconds, ease: "easeOut" },
1644
1641
  style: {
1645
- height: height === "auto" ? "auto" : height,
1646
1642
  maxHeight: "calc(100vh - 4rem)",
1647
1643
  overflow: "auto",
1648
1644
  willChange: "height"
@@ -1651,6 +1647,28 @@ function AutoHeight({
1651
1647
  }
1652
1648
  );
1653
1649
  }
1650
+ function parseCssTimeSeconds(value) {
1651
+ if (!value) return null;
1652
+ if (value.endsWith("ms")) {
1653
+ const numeric = Number.parseFloat(value);
1654
+ return Number.isFinite(numeric) ? numeric / 1e3 : null;
1655
+ }
1656
+ if (value.endsWith("s")) {
1657
+ const numeric = Number.parseFloat(value);
1658
+ return Number.isFinite(numeric) ? numeric : null;
1659
+ }
1660
+ return null;
1661
+ }
1662
+ function useMotionDuration(varName, fallbackSeconds) {
1663
+ const [duration, setDuration] = React2.useState(fallbackSeconds);
1664
+ React2.useLayoutEffect(() => {
1665
+ if (typeof window === "undefined") return;
1666
+ const value = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
1667
+ const parsed = parseCssTimeSeconds(value);
1668
+ if (parsed !== null) setDuration(parsed);
1669
+ }, [varName]);
1670
+ return duration;
1671
+ }
1654
1672
  function Dialog({
1655
1673
  id,
1656
1674
  template,
@@ -1682,6 +1700,7 @@ function Dialog({
1682
1700
  const [surfaceReady, setSurfaceReady] = React2.useState(false);
1683
1701
  const [overlayReady, setOverlayReady] = React2.useState(false);
1684
1702
  const Template = template;
1703
+ const motionDuration = useMotionDuration("--motion-fast", 0.16);
1685
1704
  const handleOpenChange = (nextOpen) => {
1686
1705
  if (!isControlled) setUncontrolledOpen(nextOpen);
1687
1706
  onOpenChange?.(nextOpen);
@@ -1711,10 +1730,6 @@ function Dialog({
1711
1730
  setOverlayReady(false);
1712
1731
  return;
1713
1732
  }
1714
- if (!isOpen && wasOpen) {
1715
- setSurfaceReady(false);
1716
- setOverlayReady(false);
1717
- }
1718
1733
  }, [isOpen]);
1719
1734
  const handleAutoHeightReady = React2.useCallback(() => {
1720
1735
  if (!isOpen) return;
@@ -1723,35 +1738,38 @@ function Dialog({
1723
1738
  setOverlayReady(true);
1724
1739
  });
1725
1740
  }, [isOpen]);
1726
- const overlayClassName = cn(
1727
- "DialogOverlay",
1728
- dialogOverlayClass,
1729
- isOpen && !overlayReady ? "opacity-0" : null,
1730
- overlayReady ? "animate-[dialog-overlay-in_var(--motion-med)_cubic-bezier(0.2,0,0.2,1)] [animation-fill-mode:both]" : null
1731
- );
1732
- const surfaceClassName = cn(
1733
- dialogSurfaceVariants({ chrome }),
1734
- isOpen && !surfaceReady ? "opacity-0 translate-y-5" : null,
1735
- surfaceReady ? "animate-[dialog-surface-in_var(--motion-med)_cubic-bezier(0.16,1,0.3,1)] [animation-fill-mode:both]" : null
1736
- );
1741
+ const overlayClassName = cn("DialogOverlay", dialogOverlayClass);
1742
+ const surfaceClassName = cn(dialogSurfaceVariants({ chrome }));
1737
1743
  return /* @__PURE__ */ jsxs3(DialogPrimitive.Root, { open: open2, defaultOpen, onOpenChange: handleOpenChange, modal, children: [
1738
1744
  trigger ? /* @__PURE__ */ jsx7(DialogPrimitive.Trigger, { asChild: true, children: trigger }) : null,
1739
- /* @__PURE__ */ jsxs3(DialogPrimitive.Portal, { children: [
1740
- modal ? /* @__PURE__ */ jsx7(DialogPrimitive.Overlay, { className: overlayClassName, style: { zIndex: zIndex - 1 } }) : null,
1745
+ /* @__PURE__ */ jsx7(DialogPrimitive.Portal, { forceMount: true, children: /* @__PURE__ */ jsx7(AnimatePresence, { children: isOpen ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
1746
+ modal ? /* @__PURE__ */ jsx7(DialogPrimitive.Overlay, { forceMount: true, asChild: true, children: /* @__PURE__ */ jsx7(
1747
+ motion.div,
1748
+ {
1749
+ className: overlayClassName,
1750
+ style: { zIndex: zIndex - 1 },
1751
+ variants: {
1752
+ open: {
1753
+ opacity: 1,
1754
+ pointerEvents: "auto",
1755
+ transition: { duration: motionDuration, ease: "easeOut" }
1756
+ },
1757
+ closed: {
1758
+ opacity: 0,
1759
+ pointerEvents: "none",
1760
+ transition: { duration: motionDuration, ease: "easeOut" }
1761
+ }
1762
+ },
1763
+ initial: "closed",
1764
+ animate: overlayReady ? "open" : "closed",
1765
+ exit: "closed"
1766
+ }
1767
+ ) }) : null,
1741
1768
  /* @__PURE__ */ jsx7(
1742
1769
  DialogPrimitive.Content,
1743
1770
  {
1744
- className: cn(
1745
- "DialogContent",
1746
- dialogPanelVariants(),
1747
- "data-[state=closed]:[&_.dialog-surface]:animate-[dialog-surface-out_var(--motion-med)_cubic-bezier(0.4,0,1,1)]",
1748
- className
1749
- ),
1750
- style: {
1751
- ...style,
1752
- zIndex,
1753
- "--dialog-width": `${maxWidthPx}px`
1754
- },
1771
+ forceMount: true,
1772
+ asChild: true,
1755
1773
  onInteractOutside: (event) => {
1756
1774
  if (!dismissible) event.preventDefault();
1757
1775
  },
@@ -1759,22 +1777,85 @@ function Dialog({
1759
1777
  if (!dismissible) event.preventDefault();
1760
1778
  },
1761
1779
  ...props,
1762
- children: /* @__PURE__ */ jsxs3("div", { className: surfaceClassName, style: { willChange: "transform" }, children: [
1763
- showClose ? /* @__PURE__ */ jsx7(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx7(
1764
- Button,
1765
- {
1766
- variant: "ghost",
1767
- size: "icon",
1768
- leftIcon: /* @__PURE__ */ jsx7(XIcon, { className: "w-5 h-5" }),
1769
- className: "absolute right-2 top-2 z-10 rounded-full",
1770
- "aria-label": closeLabel
1771
- }
1772
- ) }) : null,
1773
- /* @__PURE__ */ jsx7(AutoHeight, { onReady: handleAutoHeightReady, resetKey: contentCycle, children: /* @__PURE__ */ jsx7(Template, { id: id ?? fallbackId, payload, onResolve: handleResolve }) })
1774
- ] })
1780
+ children: /* @__PURE__ */ jsx7(
1781
+ motion.div,
1782
+ {
1783
+ className: cn("DialogContent", dialogPanelVariants(), className),
1784
+ style: {
1785
+ ...style,
1786
+ zIndex,
1787
+ "--dialog-width": `${maxWidthPx}px`
1788
+ },
1789
+ variants: {
1790
+ open: {
1791
+ opacity: 1,
1792
+ pointerEvents: "auto",
1793
+ transition: { duration: motionDuration, ease: "easeOut" }
1794
+ },
1795
+ closed: {
1796
+ opacity: 0,
1797
+ pointerEvents: "none",
1798
+ transition: { duration: motionDuration, ease: "easeIn" }
1799
+ }
1800
+ },
1801
+ initial: "open",
1802
+ animate: "open",
1803
+ exit: "closed",
1804
+ children: /* @__PURE__ */ jsxs3(
1805
+ motion.div,
1806
+ {
1807
+ className: surfaceClassName,
1808
+ style: { willChange: "transform" },
1809
+ variants: {
1810
+ open: {
1811
+ opacity: 1,
1812
+ y: 0,
1813
+ transition: { duration: motionDuration, ease: "easeOut" }
1814
+ },
1815
+ closed: {
1816
+ opacity: 0,
1817
+ y: 20,
1818
+ transition: { duration: motionDuration, ease: "easeIn" }
1819
+ }
1820
+ },
1821
+ initial: "closed",
1822
+ animate: surfaceReady ? "open" : "closed",
1823
+ exit: "closed",
1824
+ children: [
1825
+ showClose ? /* @__PURE__ */ jsx7(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx7(
1826
+ Button,
1827
+ {
1828
+ variant: "ghost",
1829
+ size: "icon",
1830
+ leftIcon: /* @__PURE__ */ jsx7(XIcon, { className: "w-5 h-5" }),
1831
+ className: "absolute right-2 top-2 z-10 rounded-full",
1832
+ "aria-label": closeLabel
1833
+ }
1834
+ ) }) : null,
1835
+ /* @__PURE__ */ jsx7(
1836
+ AutoHeight,
1837
+ {
1838
+ onReady: handleAutoHeightReady,
1839
+ resetKey: contentCycle,
1840
+ durationSeconds: motionDuration,
1841
+ children: /* @__PURE__ */ jsx7(
1842
+ Template,
1843
+ {
1844
+ id: id ?? fallbackId,
1845
+ payload,
1846
+ onResolve: handleResolve
1847
+ }
1848
+ )
1849
+ }
1850
+ )
1851
+ ]
1852
+ }
1853
+ )
1854
+ }
1855
+ )
1775
1856
  }
1776
1857
  )
1777
- ] })
1858
+ ] }) : null }) })
1778
1859
  ] });
1779
1860
  }
1780
1861
 
@@ -1987,7 +2068,7 @@ var closeTop = new CloseTopUseCase(registry);
1987
2068
  var dialogController = new DialogController(registry, open, resolve, dismiss, closeTop);
1988
2069
 
1989
2070
  // src/feature/dialog/infra/web/react/DialogHost.tsx
1990
- import { Fragment as Fragment2, jsx as jsx11 } from "react/jsx-runtime";
2071
+ import { Fragment as Fragment3, jsx as jsx11 } from "react/jsx-runtime";
1991
2072
  var DialogHost = () => {
1992
2073
  const [state, setState] = React3.useState(dialogController.handleGetRegistry().getState());
1993
2074
  const [closingIds, setClosingIds] = React3.useState(() => /* @__PURE__ */ new Set());
@@ -2029,7 +2110,7 @@ var DialogHost = () => {
2029
2110
  },
2030
2111
  [closeDelayMs, closingIds]
2031
2112
  );
2032
- return /* @__PURE__ */ jsx11(Fragment2, { children: state.stack.map((dialog, index) => {
2113
+ return /* @__PURE__ */ jsx11(Fragment3, { children: state.stack.map((dialog, index) => {
2033
2114
  const template = getDialogTemplate(dialog.templateKey);
2034
2115
  if (!template) {
2035
2116
  console.error(`Missing dialog template: ${dialog.templateKey}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexdspace/react",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,6 +29,7 @@
29
29
  "dependencies": {
30
30
  "class-variance-authority": "^0.7.1",
31
31
  "clsx": "^2.1.1",
32
+ "motion": "^12.23.26",
32
33
  "tailwind-merge": "^3.4.0",
33
34
  "uuid": "^13.0.0",
34
35
  "@hexdspace/util": "0.0.25"
@@ -37,7 +38,7 @@
37
38
  "@tanstack/react-query": "^5.90.11",
38
39
  "lucide-react": "^0.555.0",
39
40
  "radix-ui": "^1.4.3",
40
- "react": "^19.2.3",
41
+ "react": "^20.2.3",
41
42
  "react-dom": "^19.2.3",
42
43
  "react-router-dom": "^7.10.1",
43
44
  "react-toastify": "^11.0.5"