@hexdspace/react 0.1.20 → 0.1.22

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.
@@ -121,28 +121,6 @@
121
121
  }
122
122
  }
123
123
 
124
- @keyframes tooltip-in {
125
- 0% {
126
- opacity: 0;
127
- transform: translate(var(--tooltip-x, 0px), var(--tooltip-y, 4px)) scale(0.98);
128
- }
129
- 100% {
130
- opacity: 1;
131
- transform: translate(0, 0) scale(1);
132
- }
133
- }
134
-
135
- @keyframes tooltip-out {
136
- 0% {
137
- opacity: 1;
138
- transform: translate(0, 0) scale(1);
139
- }
140
- 100% {
141
- opacity: 0;
142
- transform: translate(var(--tooltip-x, 0px), var(--tooltip-y, 4px)) scale(0.98);
143
- }
144
- }
145
-
146
124
  :root .prose code {
147
125
  background: rgba(0, 0, 0, 0.08);
148
126
  padding: 3px 3px 0;
package/dist/index.js CHANGED
@@ -1545,7 +1545,34 @@ import { cva as cva2 } from "class-variance-authority";
1545
1545
  import { AnimatePresence, motion } from "motion/react";
1546
1546
  import { XIcon } from "lucide-react";
1547
1547
  import { Dialog as DialogPrimitive } from "radix-ui";
1548
+ import * as React3 from "react";
1549
+
1550
+ // src/ui/utils/motion.ts
1548
1551
  import * as React2 from "react";
1552
+ function parseCssTimeSeconds(value) {
1553
+ if (!value) return null;
1554
+ if (value.endsWith("ms")) {
1555
+ const numeric = Number.parseFloat(value);
1556
+ return Number.isFinite(numeric) ? numeric / 1e3 : null;
1557
+ }
1558
+ if (value.endsWith("s")) {
1559
+ const numeric = Number.parseFloat(value);
1560
+ return Number.isFinite(numeric) ? numeric : null;
1561
+ }
1562
+ return null;
1563
+ }
1564
+ function useMotionDuration(varName, fallbackSeconds) {
1565
+ const [duration, setDuration] = React2.useState(fallbackSeconds);
1566
+ React2.useLayoutEffect(() => {
1567
+ if (typeof window === "undefined") return;
1568
+ const value = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
1569
+ const parsed = parseCssTimeSeconds(value);
1570
+ if (parsed !== null) setDuration(parsed);
1571
+ }, [varName]);
1572
+ return duration;
1573
+ }
1574
+
1575
+ // src/ui/components/dialog/Dialog.tsx
1549
1576
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1550
1577
  var dialogPanelVariants = cva2(
1551
1578
  cn(
@@ -1594,16 +1621,16 @@ function AutoHeight({
1594
1621
  resetKey,
1595
1622
  durationSeconds
1596
1623
  }) {
1597
- const ref = React2.useRef(null);
1598
- const [height, setHeight] = React2.useState("auto");
1599
- const readyRef = React2.useRef(false);
1600
- const resetKeyRef = React2.useRef(resetKey);
1601
- React2.useEffect(() => {
1624
+ const ref = React3.useRef(null);
1625
+ const [height, setHeight] = React3.useState("auto");
1626
+ const readyRef = React3.useRef(false);
1627
+ const resetKeyRef = React3.useRef(resetKey);
1628
+ React3.useEffect(() => {
1602
1629
  if (resetKeyRef.current === resetKey) return;
1603
1630
  resetKeyRef.current = resetKey;
1604
1631
  readyRef.current = false;
1605
1632
  });
1606
- React2.useLayoutEffect(() => {
1633
+ React3.useLayoutEffect(() => {
1607
1634
  const el = ref.current;
1608
1635
  if (!el) return;
1609
1636
  const dpr = Math.max(1, Math.round(window.devicePixelRatio || 1));
@@ -1640,35 +1667,12 @@ function AutoHeight({
1640
1667
  transition: { duration: durationSeconds, ease: "easeOut" },
1641
1668
  style: {
1642
1669
  maxHeight: "calc(100vh - 4rem)",
1643
- overflow: "auto",
1644
- willChange: "height"
1670
+ overflow: "auto"
1645
1671
  },
1646
1672
  children: /* @__PURE__ */ jsx7("div", { ref, style: { boxSizing: "border-box" }, children })
1647
1673
  }
1648
1674
  );
1649
1675
  }
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
- }
1672
1676
  function Dialog({
1673
1677
  id,
1674
1678
  template,
@@ -1690,13 +1694,13 @@ function Dialog({
1690
1694
  style,
1691
1695
  ...props
1692
1696
  }) {
1693
- const fallbackId = React2.useId();
1694
- const resolvedRef = React2.useRef(false);
1697
+ const fallbackId = React3.useId();
1698
+ const resolvedRef = React3.useRef(false);
1695
1699
  const isControlled = open2 !== void 0;
1696
- const [uncontrolledOpen, setUncontrolledOpen] = React2.useState(defaultOpen ?? false);
1700
+ const [uncontrolledOpen, setUncontrolledOpen] = React3.useState(defaultOpen ?? false);
1697
1701
  const isOpen = isControlled ? open2 : uncontrolledOpen;
1698
- const [surfaceReady, setSurfaceReady] = React2.useState(false);
1699
- const [overlayReady, setOverlayReady] = React2.useState(false);
1702
+ const [surfaceReady, setSurfaceReady] = React3.useState(false);
1703
+ const [overlayReady, setOverlayReady] = React3.useState(false);
1700
1704
  const Template = template;
1701
1705
  const motionDuration = useMotionDuration("--motion-med", 0.16);
1702
1706
  const handleOpenChange = (nextOpen) => {
@@ -1712,14 +1716,14 @@ function Dialog({
1712
1716
  }
1713
1717
  onDismiss?.();
1714
1718
  };
1715
- const handleResolve = React2.useCallback(
1719
+ const handleResolve = React3.useCallback(
1716
1720
  (result) => {
1717
1721
  resolvedRef.current = true;
1718
1722
  onResolve?.(result);
1719
1723
  },
1720
1724
  [onResolve]
1721
1725
  );
1722
- const handleAutoHeightReady = React2.useCallback(() => {
1726
+ const handleAutoHeightReady = React3.useCallback(() => {
1723
1727
  if (!isOpen) return;
1724
1728
  requestAnimationFrame(() => {
1725
1729
  setSurfaceReady(true);
@@ -1728,6 +1732,7 @@ function Dialog({
1728
1732
  }, [isOpen]);
1729
1733
  const overlayClassName = cn(dialogOverlayClass);
1730
1734
  const surfaceClassName = cn(dialogSurfaceVariants({ chrome }));
1735
+ const panelRef = React3.useRef(null);
1731
1736
  return /* @__PURE__ */ jsxs3(DialogPrimitive.Root, { open: open2, defaultOpen, onOpenChange: handleOpenChange, modal, children: [
1732
1737
  trigger ? /* @__PURE__ */ jsx7(DialogPrimitive.Trigger, { asChild: true, children: trigger }) : null,
1733
1738
  /* @__PURE__ */ jsx7(DialogPrimitive.Portal, { forceMount: true, children: /* @__PURE__ */ jsx7(AnimatePresence, { children: isOpen ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
@@ -1750,6 +1755,10 @@ function Dialog({
1750
1755
  {
1751
1756
  forceMount: true,
1752
1757
  asChild: true,
1758
+ onOpenAutoFocus: (event) => {
1759
+ event.preventDefault();
1760
+ panelRef.current?.focus();
1761
+ },
1753
1762
  onInteractOutside: (event) => {
1754
1763
  if (!dismissible) event.preventDefault();
1755
1764
  },
@@ -1761,6 +1770,8 @@ function Dialog({
1761
1770
  motion.div,
1762
1771
  {
1763
1772
  className: cn(dialogPanelVariants(), className),
1773
+ ref: panelRef,
1774
+ tabIndex: -1,
1764
1775
  style: {
1765
1776
  ...style,
1766
1777
  zIndex,
@@ -1777,7 +1788,6 @@ function Dialog({
1777
1788
  motion.div,
1778
1789
  {
1779
1790
  className: surfaceClassName,
1780
- style: { willChange: "transform" },
1781
1791
  variants: {
1782
1792
  open: { opacity: 1, y: 0, transition: { duration: motionDuration, ease: "easeOut" } },
1783
1793
  closed: { opacity: 0, y: 20, transition: { duration: motionDuration, ease: "easeIn" } }
@@ -1883,7 +1893,7 @@ function registerDefaultDialogs() {
1883
1893
  var DefaultDialogTemplateKeys = ["custom", "confirm", "info"];
1884
1894
 
1885
1895
  // src/feature/dialog/infra/web/react/DialogHost.tsx
1886
- import * as React3 from "react";
1896
+ import * as React4 from "react";
1887
1897
 
1888
1898
  // src/feature/dialog/application/use-case/close-top-dialog-use-case.ts
1889
1899
  var CloseTopUseCase = class {
@@ -2034,18 +2044,18 @@ var dialogController = new DialogController(registry, open, resolve, dismiss, cl
2034
2044
  // src/feature/dialog/infra/web/react/DialogHost.tsx
2035
2045
  import { Fragment as Fragment3, jsx as jsx11 } from "react/jsx-runtime";
2036
2046
  var DialogHost = () => {
2037
- const [state, setState] = React3.useState(dialogController.handleGetRegistry().getState());
2038
- const [closingIds, setClosingIds] = React3.useState(() => /* @__PURE__ */ new Set());
2039
- const closeTimers = React3.useRef(/* @__PURE__ */ new Map());
2040
- const [closeDelayMs, setCloseDelayMs] = React3.useState(160);
2041
- React3.useEffect(() => dialogController.handleGetRegistry().subscribe(setState), []);
2042
- React3.useEffect(() => {
2047
+ const [state, setState] = React4.useState(dialogController.handleGetRegistry().getState());
2048
+ const [closingIds, setClosingIds] = React4.useState(() => /* @__PURE__ */ new Set());
2049
+ const closeTimers = React4.useRef(/* @__PURE__ */ new Map());
2050
+ const [closeDelayMs, setCloseDelayMs] = React4.useState(160);
2051
+ React4.useEffect(() => dialogController.handleGetRegistry().subscribe(setState), []);
2052
+ React4.useEffect(() => {
2043
2053
  if (typeof window === "undefined") return;
2044
2054
  const raw = getComputedStyle(document.documentElement).getPropertyValue("--motion-fast").trim();
2045
2055
  const parsed = parseDurationMs(raw);
2046
2056
  if (parsed) setCloseDelayMs(parsed);
2047
2057
  }, []);
2048
- React3.useEffect(() => {
2058
+ React4.useEffect(() => {
2049
2059
  return () => {
2050
2060
  for (const timer of closeTimers.current.values()) {
2051
2061
  window.clearTimeout(timer);
@@ -2053,7 +2063,7 @@ var DialogHost = () => {
2053
2063
  closeTimers.current.clear();
2054
2064
  };
2055
2065
  }, []);
2056
- const scheduleClose = React3.useCallback(
2066
+ const scheduleClose = React4.useCallback(
2057
2067
  (id, action, result) => {
2058
2068
  if (closingIds.has(id)) return;
2059
2069
  setClosingIds((prev) => new Set(prev).add(id));
@@ -2124,12 +2134,12 @@ function useDialog() {
2124
2134
  }
2125
2135
 
2126
2136
  // src/ui/components/Field.tsx
2127
- import * as React5 from "react";
2137
+ import * as React6 from "react";
2128
2138
 
2129
2139
  // src/ui/components/Label.tsx
2130
- import * as React4 from "react";
2140
+ import * as React5 from "react";
2131
2141
  import { jsx as jsx12 } from "react/jsx-runtime";
2132
- var Label = React4.forwardRef(
2142
+ var Label = React5.forwardRef(
2133
2143
  ({ className, htmlFor, children, ...props }, ref) => /* @__PURE__ */ jsx12(
2134
2144
  "label",
2135
2145
  {
@@ -2146,7 +2156,7 @@ Label.displayName = "Label";
2146
2156
  // src/ui/components/Field.tsx
2147
2157
  import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
2148
2158
  function Field({ label, hint, error, required, disabled, id, children, className, ...props }) {
2149
- const reactId = React5.useId();
2159
+ const reactId = React6.useId();
2150
2160
  const controlId = id ?? `field-${reactId}`;
2151
2161
  const hintId = hint ? `${controlId}-hint` : void 0;
2152
2162
  const errorId = error ? `${controlId}-error` : void 0;
@@ -2156,7 +2166,7 @@ function Field({ label, hint, error, required, disabled, id, children, className
2156
2166
  const ariaDescribedBy = describedByParts.length ? describedByParts.join(" ") : void 0;
2157
2167
  const resolvedDisabled = disabled ?? children.props.disabled;
2158
2168
  const resolvedRequired = required ?? children.props.required;
2159
- const control = React5.cloneElement(children, {
2169
+ const control = React6.cloneElement(children, {
2160
2170
  id: controlId,
2161
2171
  disabled: resolvedDisabled,
2162
2172
  required: resolvedRequired,
@@ -2179,7 +2189,7 @@ function Field({ label, hint, error, required, disabled, id, children, className
2179
2189
 
2180
2190
  // src/ui/components/Input.tsx
2181
2191
  import { cva as cva3 } from "class-variance-authority";
2182
- import * as React6 from "react";
2192
+ import * as React7 from "react";
2183
2193
  import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
2184
2194
  var controlShellBase = cn(
2185
2195
  "relative inline-flex items-center gap-2",
@@ -2235,7 +2245,7 @@ var slotBase = cn(
2235
2245
  "data-[disabled]:text-[color:var(--disabled-fg)]"
2236
2246
  );
2237
2247
  var slotReserve = "min-w-[var(--input-slot-size)]";
2238
- var Input = React6.forwardRef(
2248
+ var Input = React7.forwardRef(
2239
2249
  ({
2240
2250
  variant,
2241
2251
  size,
@@ -2296,7 +2306,7 @@ Input.displayName = "Input";
2296
2306
  // src/ui/components/Skeleton.tsx
2297
2307
  import { cva as cva4 } from "class-variance-authority";
2298
2308
  import { Slot as Slot2 } from "radix-ui";
2299
- import * as React7 from "react";
2309
+ import * as React8 from "react";
2300
2310
  import { jsx as jsx15 } from "react/jsx-runtime";
2301
2311
  var skeletonBase = cn(
2302
2312
  "relative isolate inline-flex overflow-hidden",
@@ -2351,7 +2361,7 @@ var skeletonVariants = cva4(skeletonBase, {
2351
2361
  preset: "none"
2352
2362
  }
2353
2363
  });
2354
- var Skeleton = React7.forwardRef(
2364
+ var Skeleton = React8.forwardRef(
2355
2365
  ({ variant, size, radius, fullWidth, animation, preset, animate, asChild, className, children, ...props }, ref) => {
2356
2366
  const resolvedAnimation = animation ?? (animate === false ? "none" : animate ? "pulse" : void 0);
2357
2367
  const Component = asChild ? Slot2.Root : "div";
@@ -2381,7 +2391,7 @@ Skeleton.displayName = "Skeleton";
2381
2391
 
2382
2392
  // src/ui/components/Textarea.tsx
2383
2393
  import { cva as cva5 } from "class-variance-authority";
2384
- import * as React8 from "react";
2394
+ import * as React9 from "react";
2385
2395
  import { jsx as jsx16 } from "react/jsx-runtime";
2386
2396
  var controlShellBase2 = cn(
2387
2397
  "relative inline-flex w-full",
@@ -2444,7 +2454,7 @@ function mergeRefs(...refs) {
2444
2454
  }
2445
2455
  };
2446
2456
  }
2447
- var Textarea = React8.forwardRef(
2457
+ var Textarea = React9.forwardRef(
2448
2458
  ({
2449
2459
  variant,
2450
2460
  size,
@@ -2461,8 +2471,8 @@ var Textarea = React8.forwardRef(
2461
2471
  ...props
2462
2472
  }, ref) => {
2463
2473
  const isDisabled = Boolean(disabled);
2464
- const innerRef = React8.useRef(null);
2465
- const resize = React8.useCallback(() => {
2474
+ const innerRef = React9.useRef(null);
2475
+ const resize = React9.useCallback(() => {
2466
2476
  if (!autoResize) return;
2467
2477
  const el = innerRef.current;
2468
2478
  if (!el) return;
@@ -2474,7 +2484,7 @@ var Textarea = React8.forwardRef(
2474
2484
  resize();
2475
2485
  onInput?.(e);
2476
2486
  };
2477
- React8.useLayoutEffect(() => {
2487
+ React9.useLayoutEffect(() => {
2478
2488
  resize();
2479
2489
  }, [resize, value]);
2480
2490
  return /* @__PURE__ */ jsx16(
@@ -2507,18 +2517,17 @@ var Textarea = React8.forwardRef(
2507
2517
  Textarea.displayName = "Textarea";
2508
2518
 
2509
2519
  // src/ui/components/Tooltip.tsx
2520
+ import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion/react";
2510
2521
  import { Tooltip as TooltipPrimitive } from "radix-ui";
2522
+ import * as React10 from "react";
2511
2523
  import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
2512
2524
  var tooltipContentBase = cn(
2513
2525
  "panel shadow-none px-4 py-2.5 text-xs z-5000 select-none",
2514
- "origin-center will-change-[transform,opacity]",
2526
+ "origin-center",
2515
2527
  "[--tooltip-x:0px] [--tooltip-y:4px]",
2516
2528
  "data-[side=bottom]:[--tooltip-y:-4px]",
2517
2529
  "data-[side=left]:[--tooltip-x:4px] data-[side=left]:[--tooltip-y:0px]",
2518
- "data-[side=right]:[--tooltip-x:-4px] data-[side=right]:[--tooltip-y:0px]",
2519
- "data-[state=delayed-open]:animate-[tooltip-in_140ms_ease-out]",
2520
- "data-[state=instant-open]:animate-[tooltip-in_140ms_ease-out]",
2521
- "data-[state=closed]:animate-[tooltip-out_120ms_ease-in]"
2530
+ "data-[side=right]:[--tooltip-x:-4px] data-[side=right]:[--tooltip-y:0px]"
2522
2531
  );
2523
2532
  function Tooltip({
2524
2533
  children,
@@ -2529,27 +2538,51 @@ function Tooltip({
2529
2538
  maxWidthPx = 240,
2530
2539
  preserveWhitespace = false
2531
2540
  }) {
2532
- return /* @__PURE__ */ jsx17(TooltipPrimitive.Provider, { delayDuration: delayMs, children: /* @__PURE__ */ jsxs9(TooltipPrimitive.Root, { children: [
2541
+ const [open2, setOpen] = React10.useState(false);
2542
+ const motionDuration = useMotionDuration("--motion-fast", 0.14);
2543
+ return /* @__PURE__ */ jsx17(TooltipPrimitive.Provider, { delayDuration: delayMs, children: /* @__PURE__ */ jsxs9(TooltipPrimitive.Root, { onOpenChange: setOpen, children: [
2533
2544
  /* @__PURE__ */ jsx17(TooltipPrimitive.Trigger, { asChild: true, children }),
2534
- /* @__PURE__ */ jsx17(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs9(
2545
+ /* @__PURE__ */ jsx17(TooltipPrimitive.Portal, { forceMount: true, children: /* @__PURE__ */ jsx17(AnimatePresence2, { children: open2 ? /* @__PURE__ */ jsx17(
2535
2546
  TooltipPrimitive.Content,
2536
2547
  {
2548
+ asChild: true,
2549
+ forceMount: true,
2537
2550
  side,
2538
2551
  sideOffset,
2539
- className: tooltipContentBase,
2540
- style: {
2541
- width: "max-content",
2542
- maxWidth: `min(${maxWidthPx}px, 90vw)`,
2543
- whiteSpace: preserveWhitespace ? "pre-line" : "normal",
2544
- overflowWrap: "break-word",
2545
- hyphens: "auto"
2546
- },
2547
- children: [
2548
- content,
2549
- /* @__PURE__ */ jsx17(TooltipPrimitive.Arrow, { style: { fill: "var(--surface-2)" } })
2550
- ]
2552
+ children: /* @__PURE__ */ jsxs9(
2553
+ motion2.div,
2554
+ {
2555
+ className: tooltipContentBase,
2556
+ initial: {
2557
+ opacity: 0,
2558
+ scale: 0.98,
2559
+ x: "var(--tooltip-x)",
2560
+ y: "var(--tooltip-y)"
2561
+ },
2562
+ animate: { opacity: 1, scale: 1, x: 0, y: 0 },
2563
+ exit: {
2564
+ opacity: 0,
2565
+ scale: 0.98,
2566
+ x: "var(--tooltip-x)",
2567
+ y: "var(--tooltip-y)",
2568
+ transition: { duration: motionDuration, ease: "easeIn" }
2569
+ },
2570
+ transition: { duration: motionDuration, ease: "easeOut" },
2571
+ style: {
2572
+ width: "max-content",
2573
+ maxWidth: `min(${maxWidthPx}px, 90vw)`,
2574
+ whiteSpace: preserveWhitespace ? "pre-line" : "normal",
2575
+ overflowWrap: "break-word",
2576
+ hyphens: "auto"
2577
+ },
2578
+ children: [
2579
+ content,
2580
+ /* @__PURE__ */ jsx17(TooltipPrimitive.Arrow, { style: { fill: "var(--surface-2)" } })
2581
+ ]
2582
+ }
2583
+ )
2551
2584
  }
2552
- ) })
2585
+ ) : null }) })
2553
2586
  ] }) });
2554
2587
  }
2555
2588
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexdspace/react",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,7 +38,7 @@
38
38
  "@tanstack/react-query": "^5.90.11",
39
39
  "lucide-react": "^0.555.0",
40
40
  "radix-ui": "^1.4.3",
41
- "react": "^20.2.3",
41
+ "react": "^19.2.3",
42
42
  "react-dom": "^19.2.3",
43
43
  "react-router-dom": "^7.10.1",
44
44
  "react-toastify": "^11.0.5"