@hexdspace/react 0.1.18 → 0.1.20

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.
@@ -143,64 +143,6 @@
143
143
  }
144
144
  }
145
145
 
146
- @keyframes dialog-overlay-in {
147
- from {
148
- opacity: 0;
149
- }
150
- to {
151
- opacity: 1;
152
- }
153
- }
154
-
155
- @keyframes dialog-overlay-out {
156
- from {
157
- opacity: 1;
158
- }
159
- to {
160
- opacity: 0;
161
- }
162
- }
163
-
164
- @keyframes dialog-fade-in {
165
- from {
166
- opacity: 0;
167
- }
168
- to {
169
- opacity: 1;
170
- }
171
- }
172
-
173
- @keyframes dialog-fade-out {
174
- from {
175
- opacity: 1;
176
- }
177
- to {
178
- opacity: 0;
179
- }
180
- }
181
-
182
- @keyframes dialog-surface-in {
183
- from {
184
- opacity: 0;
185
- transform: translateY(1.25rem);
186
- }
187
- to {
188
- opacity: 1;
189
- transform: translateY(0);
190
- }
191
- }
192
-
193
- @keyframes dialog-surface-out {
194
- from {
195
- opacity: 1;
196
- transform: translateY(0);
197
- }
198
- to {
199
- opacity: 0;
200
- transform: translateY(1.25rem);
201
- }
202
- }
203
-
204
146
  :root .prose code {
205
147
  background: rgba(0, 0, 0, 0.08);
206
148
  padding: 3px 3px 0;
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: {
@@ -1592,12 +1586,13 @@ var dialogSurfaceVariants = cva2("dialog-surface relative overflow-hidden", {
1592
1586
  }
1593
1587
  });
1594
1588
  function DialogContent({ className, ...props }) {
1595
- return /* @__PURE__ */ jsx7("div", { className: cn("DialogContent p-6", className), ...props });
1589
+ return /* @__PURE__ */ jsx7("div", { className: cn("p-6", className), ...props });
1596
1590
  }
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,
@@ -1677,11 +1695,10 @@ function Dialog({
1677
1695
  const isControlled = open2 !== void 0;
1678
1696
  const [uncontrolledOpen, setUncontrolledOpen] = React2.useState(defaultOpen ?? false);
1679
1697
  const isOpen = isControlled ? open2 : uncontrolledOpen;
1680
- const prevOpenRef = React2.useRef(false);
1681
- const [contentCycle, setContentCycle] = React2.useState(0);
1682
1698
  const [surfaceReady, setSurfaceReady] = React2.useState(false);
1683
1699
  const [overlayReady, setOverlayReady] = React2.useState(false);
1684
1700
  const Template = template;
1701
+ const motionDuration = useMotionDuration("--motion-med", 0.16);
1685
1702
  const handleOpenChange = (nextOpen) => {
1686
1703
  if (!isControlled) setUncontrolledOpen(nextOpen);
1687
1704
  onOpenChange?.(nextOpen);
@@ -1702,20 +1719,6 @@ function Dialog({
1702
1719
  },
1703
1720
  [onResolve]
1704
1721
  );
1705
- React2.useEffect(() => {
1706
- const wasOpen = prevOpenRef.current;
1707
- prevOpenRef.current = Boolean(isOpen);
1708
- if (isOpen && !wasOpen) {
1709
- setContentCycle((value) => value + 1);
1710
- setSurfaceReady(false);
1711
- setOverlayReady(false);
1712
- return;
1713
- }
1714
- if (!isOpen && wasOpen) {
1715
- setSurfaceReady(false);
1716
- setOverlayReady(false);
1717
- }
1718
- }, [isOpen]);
1719
1722
  const handleAutoHeightReady = React2.useCallback(() => {
1720
1723
  if (!isOpen) return;
1721
1724
  requestAnimationFrame(() => {
@@ -1723,35 +1726,30 @@ function Dialog({
1723
1726
  setOverlayReady(true);
1724
1727
  });
1725
1728
  }, [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
- );
1729
+ const overlayClassName = cn(dialogOverlayClass);
1730
+ const surfaceClassName = cn(dialogSurfaceVariants({ chrome }));
1737
1731
  return /* @__PURE__ */ jsxs3(DialogPrimitive.Root, { open: open2, defaultOpen, onOpenChange: handleOpenChange, modal, children: [
1738
1732
  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,
1733
+ /* @__PURE__ */ jsx7(DialogPrimitive.Portal, { forceMount: true, children: /* @__PURE__ */ jsx7(AnimatePresence, { children: isOpen ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
1734
+ modal ? /* @__PURE__ */ jsx7(DialogPrimitive.Overlay, { forceMount: true, asChild: true, children: /* @__PURE__ */ jsx7(
1735
+ motion.div,
1736
+ {
1737
+ className: overlayClassName,
1738
+ style: { zIndex: zIndex - 1 },
1739
+ variants: {
1740
+ open: { opacity: 1, pointerEvents: "auto", transition: { duration: motionDuration, ease: "easeOut" } },
1741
+ closed: { opacity: 0, pointerEvents: "none", transition: { duration: motionDuration, ease: "easeOut" } }
1742
+ },
1743
+ initial: "closed",
1744
+ animate: overlayReady ? "open" : "closed",
1745
+ exit: "closed"
1746
+ }
1747
+ ) }) : null,
1741
1748
  /* @__PURE__ */ jsx7(
1742
1749
  DialogPrimitive.Content,
1743
1750
  {
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
- },
1751
+ forceMount: true,
1752
+ asChild: true,
1755
1753
  onInteractOutside: (event) => {
1756
1754
  if (!dismissible) event.preventDefault();
1757
1755
  },
@@ -1759,22 +1757,68 @@ function Dialog({
1759
1757
  if (!dismissible) event.preventDefault();
1760
1758
  },
1761
1759
  ...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
- ] })
1760
+ children: /* @__PURE__ */ jsx7(
1761
+ motion.div,
1762
+ {
1763
+ className: cn(dialogPanelVariants(), className),
1764
+ style: {
1765
+ ...style,
1766
+ zIndex,
1767
+ "--dialog-width": `${maxWidthPx}px`
1768
+ },
1769
+ variants: {
1770
+ open: { opacity: 1, pointerEvents: "auto", transition: { duration: motionDuration, ease: "easeOut" } },
1771
+ closed: { opacity: 0, pointerEvents: "none", transition: { duration: motionDuration, ease: "easeIn" } }
1772
+ },
1773
+ initial: "open",
1774
+ animate: "open",
1775
+ exit: "closed",
1776
+ children: /* @__PURE__ */ jsxs3(
1777
+ motion.div,
1778
+ {
1779
+ className: surfaceClassName,
1780
+ style: { willChange: "transform" },
1781
+ variants: {
1782
+ open: { opacity: 1, y: 0, transition: { duration: motionDuration, ease: "easeOut" } },
1783
+ closed: { opacity: 0, y: 20, transition: { duration: motionDuration, ease: "easeIn" } }
1784
+ },
1785
+ initial: "closed",
1786
+ animate: surfaceReady ? "open" : "closed",
1787
+ exit: "closed",
1788
+ children: [
1789
+ showClose ? /* @__PURE__ */ jsx7(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx7(
1790
+ Button,
1791
+ {
1792
+ variant: "ghost",
1793
+ size: "icon",
1794
+ leftIcon: /* @__PURE__ */ jsx7(XIcon, { className: "w-5 h-5" }),
1795
+ className: "absolute right-2 top-2 z-10 rounded-full",
1796
+ "aria-label": closeLabel
1797
+ }
1798
+ ) }) : null,
1799
+ /* @__PURE__ */ jsx7(
1800
+ AutoHeight,
1801
+ {
1802
+ onReady: handleAutoHeightReady,
1803
+ durationSeconds: motionDuration,
1804
+ children: /* @__PURE__ */ jsx7(
1805
+ Template,
1806
+ {
1807
+ id: id ?? fallbackId,
1808
+ payload,
1809
+ onResolve: handleResolve
1810
+ }
1811
+ )
1812
+ }
1813
+ )
1814
+ ]
1815
+ }
1816
+ )
1817
+ }
1818
+ )
1775
1819
  }
1776
1820
  )
1777
- ] })
1821
+ ] }) : null }) })
1778
1822
  ] });
1779
1823
  }
1780
1824
 
@@ -1801,6 +1845,7 @@ var CustomDialog = (props) => {
1801
1845
  const p = props.payload ?? { children: /* @__PURE__ */ jsx9("div", { children: "Empty custom dialog" }) };
1802
1846
  return /* @__PURE__ */ jsxs5(DialogContent, { children: [
1803
1847
  /* @__PURE__ */ jsx9(DialogPrimitive3.Title, { className: "sr-only", children: p.title ?? "Dialog" }),
1848
+ /* @__PURE__ */ jsx9(DialogPrimitive3.Description, { "aria-describedby": void 0 }),
1804
1849
  p.children
1805
1850
  ] });
1806
1851
  };
@@ -1987,7 +2032,7 @@ var closeTop = new CloseTopUseCase(registry);
1987
2032
  var dialogController = new DialogController(registry, open, resolve, dismiss, closeTop);
1988
2033
 
1989
2034
  // src/feature/dialog/infra/web/react/DialogHost.tsx
1990
- import { Fragment as Fragment2, jsx as jsx11 } from "react/jsx-runtime";
2035
+ import { Fragment as Fragment3, jsx as jsx11 } from "react/jsx-runtime";
1991
2036
  var DialogHost = () => {
1992
2037
  const [state, setState] = React3.useState(dialogController.handleGetRegistry().getState());
1993
2038
  const [closingIds, setClosingIds] = React3.useState(() => /* @__PURE__ */ new Set());
@@ -2029,7 +2074,7 @@ var DialogHost = () => {
2029
2074
  },
2030
2075
  [closeDelayMs, closingIds]
2031
2076
  );
2032
- return /* @__PURE__ */ jsx11(Fragment2, { children: state.stack.map((dialog, index) => {
2077
+ return /* @__PURE__ */ jsx11(Fragment3, { children: state.stack.map((dialog, index) => {
2033
2078
  const template = getDialogTemplate(dialog.templateKey);
2034
2079
  if (!template) {
2035
2080
  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.20",
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"