@n3wth/ui 0.8.0 → 0.9.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.
Files changed (229) hide show
  1. package/dist/atoms/AnimatedText/AnimatedText.js +65 -0
  2. package/dist/atoms/AnimatedText/AnimatedText.js.map +1 -0
  3. package/dist/atoms/Avatar/Avatar.js +55 -0
  4. package/dist/atoms/Avatar/Avatar.js.map +1 -0
  5. package/dist/atoms/Badge/Badge.js +57 -0
  6. package/dist/atoms/Badge/Badge.js.map +1 -0
  7. package/dist/atoms/Button/Button.js +92 -0
  8. package/dist/atoms/Button/Button.js.map +1 -0
  9. package/dist/atoms/Character/Character.js +155 -0
  10. package/dist/atoms/Character/Character.js.map +1 -0
  11. package/dist/atoms/CodeBlock/CodeBlock.js +75 -0
  12. package/dist/atoms/CodeBlock/CodeBlock.js.map +1 -0
  13. package/dist/atoms/HamburgerIcon/HamburgerIcon.js +50 -0
  14. package/dist/atoms/HamburgerIcon/HamburgerIcon.js.map +1 -0
  15. package/dist/atoms/Icon/Icon.js +199 -0
  16. package/dist/atoms/Icon/Icon.js.map +1 -0
  17. package/dist/atoms/Input/Input.js +80 -0
  18. package/dist/atoms/Input/Input.js.map +1 -0
  19. package/dist/atoms/Label/Label.js +32 -0
  20. package/dist/atoms/Label/Label.js.map +1 -0
  21. package/dist/atoms/NoiseOverlay/NoiseOverlay.js +32 -0
  22. package/dist/atoms/NoiseOverlay/NoiseOverlay.js.map +1 -0
  23. package/dist/atoms/Progress/Progress.js +63 -0
  24. package/dist/atoms/Progress/Progress.js.map +1 -0
  25. package/dist/atoms/ScrollIndicator/ScrollIndicator.js +51 -0
  26. package/dist/atoms/ScrollIndicator/ScrollIndicator.js.map +1 -0
  27. package/dist/atoms/Separator/Separator.js +28 -0
  28. package/dist/atoms/Separator/Separator.js.map +1 -0
  29. package/dist/atoms/Shape/Shape.js +110 -0
  30. package/dist/atoms/Shape/Shape.js.map +1 -0
  31. package/dist/atoms/Shape/patterns.js +66 -0
  32. package/dist/atoms/Shape/patterns.js.map +1 -0
  33. package/dist/atoms/Skeleton/Skeleton.js +77 -0
  34. package/dist/atoms/Skeleton/Skeleton.js.map +1 -0
  35. package/dist/atoms/SpeechBubble/SpeechBubble.js +98 -0
  36. package/dist/atoms/SpeechBubble/SpeechBubble.js.map +1 -0
  37. package/dist/atoms/Switch/Switch.js +78 -0
  38. package/dist/atoms/Switch/Switch.js.map +1 -0
  39. package/dist/atoms/Textarea/Textarea.js +40 -0
  40. package/dist/atoms/Textarea/Textarea.js.map +1 -0
  41. package/dist/atoms/Tooltip/Tooltip.js +153 -0
  42. package/dist/atoms/Tooltip/Tooltip.js.map +1 -0
  43. package/dist/hooks/useButtonPulse.js +43 -0
  44. package/dist/hooks/useButtonPulse.js.map +1 -0
  45. package/dist/hooks/useCountUp.js +52 -0
  46. package/dist/hooks/useCountUp.js.map +1 -0
  47. package/dist/hooks/useKeyboardShortcuts.js +37 -0
  48. package/dist/hooks/useKeyboardShortcuts.js.map +1 -0
  49. package/dist/hooks/useMediaQuery.js +59 -0
  50. package/dist/hooks/useMediaQuery.js.map +1 -0
  51. package/dist/hooks/usePageTransition.js +39 -0
  52. package/dist/hooks/usePageTransition.js.map +1 -0
  53. package/dist/hooks/useReducedMotion.js +57 -0
  54. package/dist/hooks/useReducedMotion.js.map +1 -0
  55. package/dist/hooks/useScrollReveal.js +61 -0
  56. package/dist/hooks/useScrollReveal.js.map +1 -0
  57. package/dist/hooks/useStaggerList.js +54 -0
  58. package/dist/hooks/useStaggerList.js.map +1 -0
  59. package/dist/hooks/useTextReveal.js +59 -0
  60. package/dist/hooks/useTextReveal.js.map +1 -0
  61. package/dist/hooks/useTheme.js +37 -0
  62. package/dist/hooks/useTheme.js.map +1 -0
  63. package/dist/hooks/useToast.js +84 -0
  64. package/dist/hooks/useToast.js.map +1 -0
  65. package/dist/index.js +147 -7925
  66. package/dist/index.js.map +1 -1
  67. package/dist/molecules/Accordion/Accordion.js +178 -0
  68. package/dist/molecules/Accordion/Accordion.js.map +1 -0
  69. package/dist/molecules/Card/Card.js +104 -0
  70. package/dist/molecules/Card/Card.js.map +1 -0
  71. package/dist/molecules/CommandBox/CommandBox.js +65 -0
  72. package/dist/molecules/CommandBox/CommandBox.js.map +1 -0
  73. package/dist/molecules/CompositeShape/CompositeShape.js +69 -0
  74. package/dist/molecules/CompositeShape/CompositeShape.js.map +1 -0
  75. package/dist/molecules/CompositeShape/presets.js +71 -0
  76. package/dist/molecules/CompositeShape/presets.js.map +1 -0
  77. package/dist/molecules/Dropdown/Dropdown.d.ts.map +1 -1
  78. package/dist/molecules/Dropdown/Dropdown.js +530 -0
  79. package/dist/molecules/Dropdown/Dropdown.js.map +1 -0
  80. package/dist/molecules/ErrorBoundary/ErrorBoundary.js +128 -0
  81. package/dist/molecules/ErrorBoundary/ErrorBoundary.js.map +1 -0
  82. package/dist/molecules/MobileDrawer/MobileDrawer.js +78 -0
  83. package/dist/molecules/MobileDrawer/MobileDrawer.js.map +1 -0
  84. package/dist/molecules/Modal/Modal.js +262 -0
  85. package/dist/molecules/Modal/Modal.js.map +1 -0
  86. package/dist/molecules/NavLink/NavLink.js +38 -0
  87. package/dist/molecules/NavLink/NavLink.js.map +1 -0
  88. package/dist/molecules/Tabs/Tabs.js +188 -0
  89. package/dist/molecules/Tabs/Tabs.js.map +1 -0
  90. package/dist/molecules/ThemeToggle/ThemeToggle.js +48 -0
  91. package/dist/molecules/ThemeToggle/ThemeToggle.js.map +1 -0
  92. package/dist/molecules/Toast/Toast.js +156 -0
  93. package/dist/molecules/Toast/Toast.js.map +1 -0
  94. package/dist/node_modules/clsx/dist/clsx.js +17 -0
  95. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  96. package/dist/node_modules/iconoir-react/dist/esm/IconoirContext.js +6 -0
  97. package/dist/node_modules/iconoir-react/dist/esm/IconoirContext.js.map +1 -0
  98. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowDown.js +17 -0
  99. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowDown.js.map +1 -0
  100. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowLeft.js +17 -0
  101. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowLeft.js.map +1 -0
  102. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowRight.js +17 -0
  103. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowRight.js.map +1 -0
  104. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowUp.js +17 -0
  105. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowUp.js.map +1 -0
  106. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowUpRight.js +17 -0
  107. package/dist/node_modules/iconoir-react/dist/esm/regular/ArrowUpRight.js.map +1 -0
  108. package/dist/node_modules/iconoir-react/dist/esm/regular/Bell.js +17 -0
  109. package/dist/node_modules/iconoir-react/dist/esm/regular/Bell.js.map +1 -0
  110. package/dist/node_modules/iconoir-react/dist/esm/regular/Calendar.js +17 -0
  111. package/dist/node_modules/iconoir-react/dist/esm/regular/Calendar.js.map +1 -0
  112. package/dist/node_modules/iconoir-react/dist/esm/regular/Check.js +17 -0
  113. package/dist/node_modules/iconoir-react/dist/esm/regular/Check.js.map +1 -0
  114. package/dist/node_modules/iconoir-react/dist/esm/regular/CheckCircle.js +17 -0
  115. package/dist/node_modules/iconoir-react/dist/esm/regular/CheckCircle.js.map +1 -0
  116. package/dist/node_modules/iconoir-react/dist/esm/regular/Clock.js +17 -0
  117. package/dist/node_modules/iconoir-react/dist/esm/regular/Clock.js.map +1 -0
  118. package/dist/node_modules/iconoir-react/dist/esm/regular/Code.js +17 -0
  119. package/dist/node_modules/iconoir-react/dist/esm/regular/Code.js.map +1 -0
  120. package/dist/node_modules/iconoir-react/dist/esm/regular/Copy.js +17 -0
  121. package/dist/node_modules/iconoir-react/dist/esm/regular/Copy.js.map +1 -0
  122. package/dist/node_modules/iconoir-react/dist/esm/regular/Download.js +17 -0
  123. package/dist/node_modules/iconoir-react/dist/esm/regular/Download.js.map +1 -0
  124. package/dist/node_modules/iconoir-react/dist/esm/regular/EditPencil.js +17 -0
  125. package/dist/node_modules/iconoir-react/dist/esm/regular/EditPencil.js.map +1 -0
  126. package/dist/node_modules/iconoir-react/dist/esm/regular/Eye.js +17 -0
  127. package/dist/node_modules/iconoir-react/dist/esm/regular/Eye.js.map +1 -0
  128. package/dist/node_modules/iconoir-react/dist/esm/regular/EyeClosed.js +17 -0
  129. package/dist/node_modules/iconoir-react/dist/esm/regular/EyeClosed.js.map +1 -0
  130. package/dist/node_modules/iconoir-react/dist/esm/regular/Filter.js +17 -0
  131. package/dist/node_modules/iconoir-react/dist/esm/regular/Filter.js.map +1 -0
  132. package/dist/node_modules/iconoir-react/dist/esm/regular/Folder.js +17 -0
  133. package/dist/node_modules/iconoir-react/dist/esm/regular/Folder.js.map +1 -0
  134. package/dist/node_modules/iconoir-react/dist/esm/regular/Github.js +17 -0
  135. package/dist/node_modules/iconoir-react/dist/esm/regular/Github.js.map +1 -0
  136. package/dist/node_modules/iconoir-react/dist/esm/regular/HalfMoon.js +17 -0
  137. package/dist/node_modules/iconoir-react/dist/esm/regular/HalfMoon.js.map +1 -0
  138. package/dist/node_modules/iconoir-react/dist/esm/regular/Heart.js +17 -0
  139. package/dist/node_modules/iconoir-react/dist/esm/regular/Heart.js.map +1 -0
  140. package/dist/node_modules/iconoir-react/dist/esm/regular/Home.js +17 -0
  141. package/dist/node_modules/iconoir-react/dist/esm/regular/Home.js.map +1 -0
  142. package/dist/node_modules/iconoir-react/dist/esm/regular/InfoCircle.js +17 -0
  143. package/dist/node_modules/iconoir-react/dist/esm/regular/InfoCircle.js.map +1 -0
  144. package/dist/node_modules/iconoir-react/dist/esm/regular/Link.js +17 -0
  145. package/dist/node_modules/iconoir-react/dist/esm/regular/Link.js.map +1 -0
  146. package/dist/node_modules/iconoir-react/dist/esm/regular/List.js +17 -0
  147. package/dist/node_modules/iconoir-react/dist/esm/regular/List.js.map +1 -0
  148. package/dist/node_modules/iconoir-react/dist/esm/regular/Lock.js +17 -0
  149. package/dist/node_modules/iconoir-react/dist/esm/regular/Lock.js.map +1 -0
  150. package/dist/node_modules/iconoir-react/dist/esm/regular/LockSlash.js +17 -0
  151. package/dist/node_modules/iconoir-react/dist/esm/regular/LockSlash.js.map +1 -0
  152. package/dist/node_modules/iconoir-react/dist/esm/regular/Mail.js +17 -0
  153. package/dist/node_modules/iconoir-react/dist/esm/regular/Mail.js.map +1 -0
  154. package/dist/node_modules/iconoir-react/dist/esm/regular/Menu.js +17 -0
  155. package/dist/node_modules/iconoir-react/dist/esm/regular/Menu.js.map +1 -0
  156. package/dist/node_modules/iconoir-react/dist/esm/regular/Minus.js +17 -0
  157. package/dist/node_modules/iconoir-react/dist/esm/regular/Minus.js.map +1 -0
  158. package/dist/node_modules/iconoir-react/dist/esm/regular/MoreHoriz.js +17 -0
  159. package/dist/node_modules/iconoir-react/dist/esm/regular/MoreHoriz.js.map +1 -0
  160. package/dist/node_modules/iconoir-react/dist/esm/regular/MoreVert.js +17 -0
  161. package/dist/node_modules/iconoir-react/dist/esm/regular/MoreVert.js.map +1 -0
  162. package/dist/node_modules/iconoir-react/dist/esm/regular/NavArrowDown.js +17 -0
  163. package/dist/node_modules/iconoir-react/dist/esm/regular/NavArrowDown.js.map +1 -0
  164. package/dist/node_modules/iconoir-react/dist/esm/regular/NavArrowLeft.js +17 -0
  165. package/dist/node_modules/iconoir-react/dist/esm/regular/NavArrowLeft.js.map +1 -0
  166. package/dist/node_modules/iconoir-react/dist/esm/regular/NavArrowRight.js +17 -0
  167. package/dist/node_modules/iconoir-react/dist/esm/regular/NavArrowRight.js.map +1 -0
  168. package/dist/node_modules/iconoir-react/dist/esm/regular/NavArrowUp.js +17 -0
  169. package/dist/node_modules/iconoir-react/dist/esm/regular/NavArrowUp.js.map +1 -0
  170. package/dist/node_modules/iconoir-react/dist/esm/regular/OpenInWindow.js +17 -0
  171. package/dist/node_modules/iconoir-react/dist/esm/regular/OpenInWindow.js.map +1 -0
  172. package/dist/node_modules/iconoir-react/dist/esm/regular/Page.js +17 -0
  173. package/dist/node_modules/iconoir-react/dist/esm/regular/Page.js.map +1 -0
  174. package/dist/node_modules/iconoir-react/dist/esm/regular/Plus.js +17 -0
  175. package/dist/node_modules/iconoir-react/dist/esm/regular/Plus.js.map +1 -0
  176. package/dist/node_modules/iconoir-react/dist/esm/regular/RefreshDouble.js +17 -0
  177. package/dist/node_modules/iconoir-react/dist/esm/regular/RefreshDouble.js.map +1 -0
  178. package/dist/node_modules/iconoir-react/dist/esm/regular/Search.js +17 -0
  179. package/dist/node_modules/iconoir-react/dist/esm/regular/Search.js.map +1 -0
  180. package/dist/node_modules/iconoir-react/dist/esm/regular/Settings.js +17 -0
  181. package/dist/node_modules/iconoir-react/dist/esm/regular/Settings.js.map +1 -0
  182. package/dist/node_modules/iconoir-react/dist/esm/regular/SortDown.js +17 -0
  183. package/dist/node_modules/iconoir-react/dist/esm/regular/SortDown.js.map +1 -0
  184. package/dist/node_modules/iconoir-react/dist/esm/regular/Sparks.js +17 -0
  185. package/dist/node_modules/iconoir-react/dist/esm/regular/Sparks.js.map +1 -0
  186. package/dist/node_modules/iconoir-react/dist/esm/regular/Star.js +17 -0
  187. package/dist/node_modules/iconoir-react/dist/esm/regular/Star.js.map +1 -0
  188. package/dist/node_modules/iconoir-react/dist/esm/regular/SunLight.js +17 -0
  189. package/dist/node_modules/iconoir-react/dist/esm/regular/SunLight.js.map +1 -0
  190. package/dist/node_modules/iconoir-react/dist/esm/regular/Terminal.js +17 -0
  191. package/dist/node_modules/iconoir-react/dist/esm/regular/Terminal.js.map +1 -0
  192. package/dist/node_modules/iconoir-react/dist/esm/regular/Trash.js +17 -0
  193. package/dist/node_modules/iconoir-react/dist/esm/regular/Trash.js.map +1 -0
  194. package/dist/node_modules/iconoir-react/dist/esm/regular/Upload.js +17 -0
  195. package/dist/node_modules/iconoir-react/dist/esm/regular/Upload.js.map +1 -0
  196. package/dist/node_modules/iconoir-react/dist/esm/regular/User.js +17 -0
  197. package/dist/node_modules/iconoir-react/dist/esm/regular/User.js.map +1 -0
  198. package/dist/node_modules/iconoir-react/dist/esm/regular/ViewGrid.js +17 -0
  199. package/dist/node_modules/iconoir-react/dist/esm/regular/ViewGrid.js.map +1 -0
  200. package/dist/node_modules/iconoir-react/dist/esm/regular/WarningTriangle.js +17 -0
  201. package/dist/node_modules/iconoir-react/dist/esm/regular/WarningTriangle.js.map +1 -0
  202. package/dist/node_modules/iconoir-react/dist/esm/regular/Xmark.js +17 -0
  203. package/dist/node_modules/iconoir-react/dist/esm/regular/Xmark.js.map +1 -0
  204. package/dist/node_modules/iconoir-react/dist/esm/regular/XmarkCircle.js +17 -0
  205. package/dist/node_modules/iconoir-react/dist/esm/regular/XmarkCircle.js.map +1 -0
  206. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +2996 -0
  207. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  208. package/dist/organisms/Footer/Footer.js +108 -0
  209. package/dist/organisms/Footer/Footer.js.map +1 -0
  210. package/dist/organisms/Hero/Hero.d.ts.map +1 -1
  211. package/dist/organisms/Hero/Hero.js +101 -0
  212. package/dist/organisms/Hero/Hero.js.map +1 -0
  213. package/dist/organisms/Nav/Nav.js +177 -0
  214. package/dist/organisms/Nav/Nav.js.map +1 -0
  215. package/dist/organisms/Section/Section.js +57 -0
  216. package/dist/organisms/Section/Section.js.map +1 -0
  217. package/dist/tokens/colors.js +105 -0
  218. package/dist/tokens/colors.js.map +1 -0
  219. package/dist/tokens/effects.js +26 -0
  220. package/dist/tokens/effects.js.map +1 -0
  221. package/dist/tokens/motion.js +25 -0
  222. package/dist/tokens/motion.js.map +1 -0
  223. package/dist/tokens/spacing.js +31 -0
  224. package/dist/tokens/spacing.js.map +1 -0
  225. package/dist/tokens/typography.js +63 -0
  226. package/dist/tokens/typography.js.map +1 -0
  227. package/dist/utils/cn.js +9 -0
  228. package/dist/utils/cn.js.map +1 -0
  229. package/package.json +5 -3
@@ -0,0 +1,153 @@
1
+ import { jsxs as P, jsx as k, Fragment as I } from "react/jsx-runtime";
2
+ import { forwardRef as O, useState as F, useRef as w, useId as S, useCallback as g, useEffect as x } from "react";
3
+ import { createPortal as q } from "react-dom";
4
+ import { cn as N } from "../../utils/cn.js";
5
+ function H(t, e, d, n) {
6
+ const i = {
7
+ width: window.innerWidth,
8
+ height: window.innerHeight
9
+ }, u = {
10
+ top: {
11
+ top: t.top - e.height - n,
12
+ left: t.left + (t.width - e.width) / 2
13
+ },
14
+ bottom: {
15
+ top: t.bottom + n,
16
+ left: t.left + (t.width - e.width) / 2
17
+ },
18
+ left: {
19
+ top: t.top + (t.height - e.height) / 2,
20
+ left: t.left - e.width - n
21
+ },
22
+ right: {
23
+ top: t.top + (t.height - e.height) / 2,
24
+ left: t.right + n
25
+ }
26
+ }, v = (l) => {
27
+ const { top: c, left: f } = u[l];
28
+ return c >= 0 && f >= 0 && c + e.height <= i.height && f + e.width <= i.width;
29
+ }, s = {
30
+ top: ["top", "bottom", "right", "left"],
31
+ bottom: ["bottom", "top", "right", "left"],
32
+ left: ["left", "right", "top", "bottom"],
33
+ right: ["right", "left", "top", "bottom"]
34
+ }[d].find(v) ?? d, r = u[s], a = 8;
35
+ return {
36
+ top: Math.max(a, Math.min(r.top, i.height - e.height - a)),
37
+ left: Math.max(a, Math.min(r.left, i.width - e.width - a)),
38
+ actualPosition: s
39
+ };
40
+ }
41
+ const U = O(
42
+ ({
43
+ content: t,
44
+ children: e,
45
+ position: d = "top",
46
+ showDelay: n = 200,
47
+ hideDelay: i = 0,
48
+ disabled: u = !1,
49
+ arrow: v = !0,
50
+ className: y
51
+ }, s) => {
52
+ const [r, a] = F(!1), [l, c] = F(null), f = w(null), T = w(null), h = w(void 0), m = w(void 0), E = S(), p = g(() => {
53
+ const o = f.current, L = T.current;
54
+ if (!o || !L) return;
55
+ const j = o.getBoundingClientRect(), A = L.getBoundingClientRect();
56
+ c(H(j, A, d, 8));
57
+ }, [d]), M = g(() => {
58
+ u || (m.current !== void 0 && clearTimeout(m.current), h.current = setTimeout(() => {
59
+ a(!0);
60
+ }, n));
61
+ }, [u, n]), C = g(() => {
62
+ h.current !== void 0 && clearTimeout(h.current), m.current = setTimeout(() => {
63
+ a(!1), c(null);
64
+ }, i);
65
+ }, [i]);
66
+ x(() => {
67
+ if (r) {
68
+ const o = requestAnimationFrame(p);
69
+ return () => cancelAnimationFrame(o);
70
+ }
71
+ }, [r, p]), x(() => {
72
+ if (!r) return;
73
+ const o = () => p();
74
+ return window.addEventListener("scroll", o, !0), window.addEventListener("resize", o), () => {
75
+ window.removeEventListener("scroll", o, !0), window.removeEventListener("resize", o);
76
+ };
77
+ }, [r, p]), x(() => () => {
78
+ h.current !== void 0 && clearTimeout(h.current), m.current !== void 0 && clearTimeout(m.current);
79
+ }, []);
80
+ const z = {
81
+ top: "bottom-0 left-1/2 -translate-x-1/2 translate-y-1/2 rotate-45",
82
+ bottom: "top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 rotate-45",
83
+ left: "right-0 top-1/2 translate-x-1/2 -translate-y-1/2 rotate-45",
84
+ right: "left-0 top-1/2 -translate-x-1/2 -translate-y-1/2 rotate-45"
85
+ }, b = l?.actualPosition ?? d, B = r ? q(
86
+ /* @__PURE__ */ P(
87
+ "div",
88
+ {
89
+ ref: T,
90
+ id: E,
91
+ role: "tooltip",
92
+ style: l ? { top: l.top, left: l.left } : { top: -9999, left: -9999 },
93
+ className: N(
94
+ "fixed z-50 pointer-events-none",
95
+ "max-w-xs px-3 py-1.5",
96
+ "text-xs font-medium text-[var(--color-white)]",
97
+ "rounded-lg",
98
+ "bg-[var(--glass-bg)] backdrop-blur-lg",
99
+ "border border-[var(--glass-border)]",
100
+ l ? [
101
+ "opacity-100 scale-100",
102
+ "motion-safe:transition-[opacity,transform] motion-safe:duration-150 motion-safe:ease-out"
103
+ ] : "opacity-0 scale-95",
104
+ y
105
+ ),
106
+ children: [
107
+ t,
108
+ v && /* @__PURE__ */ k(
109
+ "span",
110
+ {
111
+ "aria-hidden": !0,
112
+ className: N(
113
+ "absolute w-2 h-2",
114
+ "bg-[var(--glass-bg)]",
115
+ "border border-[var(--glass-border)]",
116
+ z[b],
117
+ b === "top" && "border-t-0 border-l-0",
118
+ b === "bottom" && "border-b-0 border-r-0",
119
+ b === "left" && "border-l-0 border-b-0",
120
+ b === "right" && "border-r-0 border-t-0"
121
+ )
122
+ }
123
+ )
124
+ ]
125
+ }
126
+ ),
127
+ document.body
128
+ ) : null;
129
+ return /* @__PURE__ */ P(I, { children: [
130
+ /* @__PURE__ */ k(
131
+ "div",
132
+ {
133
+ ref: (o) => {
134
+ f.current = o, typeof s == "function" ? s(o) : s && (s.current = o);
135
+ },
136
+ onMouseEnter: M,
137
+ onMouseLeave: C,
138
+ onFocus: M,
139
+ onBlur: C,
140
+ "aria-describedby": r ? E : void 0,
141
+ className: "inline-flex",
142
+ children: e
143
+ }
144
+ ),
145
+ B
146
+ ] });
147
+ }
148
+ );
149
+ U.displayName = "Tooltip";
150
+ export {
151
+ U as Tooltip
152
+ };
153
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sources":["../../../src/atoms/Tooltip/Tooltip.tsx"],"sourcesContent":["import {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useCallback,\n useId,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cn } from '../../utils/cn'\n\nexport type TooltipPosition = 'top' | 'right' | 'bottom' | 'left'\n\nexport interface TooltipProps {\n /** Content to display inside the tooltip */\n content: ReactNode\n /** The element that triggers the tooltip */\n children: ReactNode\n /** Preferred position of the tooltip relative to the trigger */\n position?: TooltipPosition\n /** Delay in ms before showing the tooltip */\n showDelay?: number\n /** Delay in ms before hiding the tooltip */\n hideDelay?: number\n /** Whether the tooltip is disabled */\n disabled?: boolean\n /** Show arrow indicator */\n arrow?: boolean\n /** Additional class names for the tooltip popup */\n className?: string\n}\n\ninterface Coords {\n top: number\n left: number\n actualPosition: TooltipPosition\n}\n\nfunction getCoords(\n triggerRect: DOMRect,\n tooltipRect: DOMRect,\n preferred: TooltipPosition,\n gap: number\n): Coords {\n const viewport = {\n width: window.innerWidth,\n height: window.innerHeight,\n }\n\n const positions: Record<TooltipPosition, { top: number; left: number }> = {\n top: {\n top: triggerRect.top - tooltipRect.height - gap,\n left: triggerRect.left + (triggerRect.width - tooltipRect.width) / 2,\n },\n bottom: {\n top: triggerRect.bottom + gap,\n left: triggerRect.left + (triggerRect.width - tooltipRect.width) / 2,\n },\n left: {\n top: triggerRect.top + (triggerRect.height - tooltipRect.height) / 2,\n left: triggerRect.left - tooltipRect.width - gap,\n },\n right: {\n top: triggerRect.top + (triggerRect.height - tooltipRect.height) / 2,\n left: triggerRect.right + gap,\n },\n }\n\n const fits = (pos: TooltipPosition): boolean => {\n const { top, left } = positions[pos]\n return (\n top >= 0 &&\n left >= 0 &&\n top + tooltipRect.height <= viewport.height &&\n left + tooltipRect.width <= viewport.width\n )\n }\n\n const fallbackOrder: Record<TooltipPosition, TooltipPosition[]> = {\n top: ['top', 'bottom', 'right', 'left'],\n bottom: ['bottom', 'top', 'right', 'left'],\n left: ['left', 'right', 'top', 'bottom'],\n right: ['right', 'left', 'top', 'bottom'],\n }\n\n const actualPosition = fallbackOrder[preferred].find(fits) ?? preferred\n const coords = positions[actualPosition]\n\n const pad = 8\n return {\n top: Math.max(pad, Math.min(coords.top, viewport.height - tooltipRect.height - pad)),\n left: Math.max(pad, Math.min(coords.left, viewport.width - tooltipRect.width - pad)),\n actualPosition,\n }\n}\n\nexport const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(\n (\n {\n content,\n children,\n position = 'top',\n showDelay = 200,\n hideDelay = 0,\n disabled = false,\n arrow = true,\n className,\n },\n ref\n ) => {\n const [visible, setVisible] = useState(false)\n const [coords, setCoords] = useState<Coords | null>(null)\n const triggerRef = useRef<HTMLDivElement | null>(null)\n const tooltipRef = useRef<HTMLDivElement | null>(null)\n const showTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const hideTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const tooltipId = useId()\n\n const updatePosition = useCallback(() => {\n const trigger = triggerRef.current\n const tooltip = tooltipRef.current\n if (!trigger || !tooltip) return\n\n const triggerRect = trigger.getBoundingClientRect()\n const tooltipRect = tooltip.getBoundingClientRect()\n setCoords(getCoords(triggerRect, tooltipRect, position, 8))\n }, [position])\n\n const show = useCallback(() => {\n if (disabled) return\n if (hideTimeout.current !== undefined) clearTimeout(hideTimeout.current)\n showTimeout.current = setTimeout(() => {\n setVisible(true)\n }, showDelay)\n }, [disabled, showDelay])\n\n const hide = useCallback(() => {\n if (showTimeout.current !== undefined) clearTimeout(showTimeout.current)\n hideTimeout.current = setTimeout(() => {\n setVisible(false)\n setCoords(null)\n }, hideDelay)\n }, [hideDelay])\n\n useEffect(() => {\n if (visible) {\n const id = requestAnimationFrame(updatePosition)\n return () => cancelAnimationFrame(id)\n }\n }, [visible, updatePosition])\n\n useEffect(() => {\n if (!visible) return\n\n const handleUpdate = () => updatePosition()\n window.addEventListener('scroll', handleUpdate, true)\n window.addEventListener('resize', handleUpdate)\n return () => {\n window.removeEventListener('scroll', handleUpdate, true)\n window.removeEventListener('resize', handleUpdate)\n }\n }, [visible, updatePosition])\n\n useEffect(() => {\n return () => {\n if (showTimeout.current !== undefined) clearTimeout(showTimeout.current)\n if (hideTimeout.current !== undefined) clearTimeout(hideTimeout.current)\n }\n }, [])\n\n const arrowStyles: Record<TooltipPosition, string> = {\n top: 'bottom-0 left-1/2 -translate-x-1/2 translate-y-1/2 rotate-45',\n bottom: 'top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 rotate-45',\n left: 'right-0 top-1/2 translate-x-1/2 -translate-y-1/2 rotate-45',\n right: 'left-0 top-1/2 -translate-x-1/2 -translate-y-1/2 rotate-45',\n }\n\n const actualPos = coords?.actualPosition ?? position\n\n const tooltipElement = visible\n ? createPortal(\n <div\n ref={tooltipRef}\n id={tooltipId}\n role=\"tooltip\"\n style={\n coords\n ? { top: coords.top, left: coords.left }\n : { top: -9999, left: -9999 }\n }\n className={cn(\n 'fixed z-50 pointer-events-none',\n 'max-w-xs px-3 py-1.5',\n 'text-xs font-medium text-[var(--color-white)]',\n 'rounded-lg',\n 'bg-[var(--glass-bg)] backdrop-blur-lg',\n 'border border-[var(--glass-border)]',\n coords\n ? [\n 'opacity-100 scale-100',\n 'motion-safe:transition-[opacity,transform] motion-safe:duration-150 motion-safe:ease-out',\n ]\n : 'opacity-0 scale-95',\n className\n )}\n >\n {content}\n {arrow && (\n <span\n aria-hidden\n className={cn(\n 'absolute w-2 h-2',\n 'bg-[var(--glass-bg)]',\n 'border border-[var(--glass-border)]',\n arrowStyles[actualPos],\n actualPos === 'top' && 'border-t-0 border-l-0',\n actualPos === 'bottom' && 'border-b-0 border-r-0',\n actualPos === 'left' && 'border-l-0 border-b-0',\n actualPos === 'right' && 'border-r-0 border-t-0'\n )}\n />\n )}\n </div>,\n document.body\n )\n : null\n\n return (\n <>\n <div\n ref={(node) => {\n triggerRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) ref.current = node\n }}\n onMouseEnter={show}\n onMouseLeave={hide}\n onFocus={show}\n onBlur={hide}\n aria-describedby={visible ? tooltipId : undefined}\n className=\"inline-flex\"\n >\n {children}\n </div>\n {tooltipElement}\n </>\n )\n }\n)\n\nTooltip.displayName = 'Tooltip'\n"],"names":["getCoords","triggerRect","tooltipRect","preferred","gap","viewport","positions","fits","pos","top","left","actualPosition","coords","pad","Tooltip","forwardRef","content","children","position","showDelay","hideDelay","disabled","arrow","className","ref","visible","setVisible","useState","setCoords","triggerRef","useRef","tooltipRef","showTimeout","hideTimeout","tooltipId","useId","updatePosition","useCallback","trigger","tooltip","show","hide","useEffect","id","handleUpdate","arrowStyles","actualPos","tooltipElement","createPortal","jsxs","cn","jsx","Fragment","node"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { useRef as m, useEffect as v } from "react";
2
+ import o from "gsap";
3
+ function E(i = {}) {
4
+ const { hoverScale: n = 1.02, pressScale: s = 0.96, duration: t = 0.2 } = i, r = m(null);
5
+ return v(() => {
6
+ const e = r.current;
7
+ if (!e || window.matchMedia(
8
+ "(prefers-reduced-motion: reduce)"
9
+ ).matches) return;
10
+ const u = () => {
11
+ o.to(e, {
12
+ scale: n,
13
+ duration: t,
14
+ ease: "cubic.out"
15
+ });
16
+ }, c = () => {
17
+ o.to(e, {
18
+ scale: 1,
19
+ duration: t,
20
+ ease: "cubic.out"
21
+ });
22
+ }, a = () => {
23
+ o.to(e, {
24
+ scale: s,
25
+ duration: t / 2,
26
+ ease: "cubic.out"
27
+ });
28
+ }, d = () => {
29
+ o.to(e, {
30
+ scale: n,
31
+ duration: t / 2,
32
+ ease: "cubic.out"
33
+ });
34
+ };
35
+ return e.addEventListener("mouseenter", u), e.addEventListener("mouseleave", c), e.addEventListener("mousedown", a), e.addEventListener("mouseup", d), () => {
36
+ e.removeEventListener("mouseenter", u), e.removeEventListener("mouseleave", c), e.removeEventListener("mousedown", a), e.removeEventListener("mouseup", d);
37
+ };
38
+ }, [n, s, t]), r;
39
+ }
40
+ export {
41
+ E as useButtonPulse
42
+ };
43
+ //# sourceMappingURL=useButtonPulse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useButtonPulse.js","sources":["../../src/hooks/useButtonPulse.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport gsap from 'gsap'\n\nexport interface UseButtonPulseOptions {\n /** Scale on hover */\n hoverScale?: number\n /** Scale on press */\n pressScale?: number\n /** Animation duration in seconds */\n duration?: number\n}\n\n/**\n * Hook for subtle button interaction animations\n * Creates depth-aware scale interactions on hover and press\n */\nexport function useButtonPulse(options: UseButtonPulseOptions = {}) {\n const { hoverScale = 1.02, pressScale = 0.96, duration = 0.2 } = options\n\n const ref = useRef<HTMLButtonElement>(null)\n\n useEffect(() => {\n const button = ref.current\n if (!button) return\n\n const prefersReducedMotion = window.matchMedia(\n '(prefers-reduced-motion: reduce)'\n ).matches\n\n if (prefersReducedMotion) return\n\n const handleMouseEnter = () => {\n gsap.to(button, {\n scale: hoverScale,\n duration,\n ease: 'cubic.out',\n })\n }\n\n const handleMouseLeave = () => {\n gsap.to(button, {\n scale: 1,\n duration,\n ease: 'cubic.out',\n })\n }\n\n const handleMouseDown = () => {\n gsap.to(button, {\n scale: pressScale,\n duration: duration / 2,\n ease: 'cubic.out',\n })\n }\n\n const handleMouseUp = () => {\n gsap.to(button, {\n scale: hoverScale,\n duration: duration / 2,\n ease: 'cubic.out',\n })\n }\n\n button.addEventListener('mouseenter', handleMouseEnter)\n button.addEventListener('mouseleave', handleMouseLeave)\n button.addEventListener('mousedown', handleMouseDown)\n button.addEventListener('mouseup', handleMouseUp)\n\n return () => {\n button.removeEventListener('mouseenter', handleMouseEnter)\n button.removeEventListener('mouseleave', handleMouseLeave)\n button.removeEventListener('mousedown', handleMouseDown)\n button.removeEventListener('mouseup', handleMouseUp)\n }\n }, [hoverScale, pressScale, duration])\n\n return ref\n}\n"],"names":["useButtonPulse","options","hoverScale","pressScale","duration","ref","useRef","useEffect","button","handleMouseEnter","gsap","handleMouseLeave","handleMouseDown","handleMouseUp"],"mappings":";;AAgBO,SAASA,EAAeC,IAAiC,IAAI;AAClE,QAAM,EAAE,YAAAC,IAAa,MAAM,YAAAC,IAAa,MAAM,UAAAC,IAAW,QAAQH,GAE3DI,IAAMC,EAA0B,IAAI;AAE1C,SAAAC,EAAU,MAAM;AACd,UAAMC,IAASH,EAAI;AAOnB,QANI,CAACG,KAEwB,OAAO;AAAA,MAClC;AAAA,IAAA,EACA,QAEwB;AAE1B,UAAMC,IAAmB,MAAM;AAC7B,MAAAC,EAAK,GAAGF,GAAQ;AAAA,QACd,OAAON;AAAA,QACP,UAAAE;AAAA,QACA,MAAM;AAAA,MAAA,CACP;AAAA,IACH,GAEMO,IAAmB,MAAM;AAC7B,MAAAD,EAAK,GAAGF,GAAQ;AAAA,QACd,OAAO;AAAA,QACP,UAAAJ;AAAA,QACA,MAAM;AAAA,MAAA,CACP;AAAA,IACH,GAEMQ,IAAkB,MAAM;AAC5B,MAAAF,EAAK,GAAGF,GAAQ;AAAA,QACd,OAAOL;AAAA,QACP,UAAUC,IAAW;AAAA,QACrB,MAAM;AAAA,MAAA,CACP;AAAA,IACH,GAEMS,IAAgB,MAAM;AAC1B,MAAAH,EAAK,GAAGF,GAAQ;AAAA,QACd,OAAON;AAAA,QACP,UAAUE,IAAW;AAAA,QACrB,MAAM;AAAA,MAAA,CACP;AAAA,IACH;AAEA,WAAAI,EAAO,iBAAiB,cAAcC,CAAgB,GACtDD,EAAO,iBAAiB,cAAcG,CAAgB,GACtDH,EAAO,iBAAiB,aAAaI,CAAe,GACpDJ,EAAO,iBAAiB,WAAWK,CAAa,GAEzC,MAAM;AACX,MAAAL,EAAO,oBAAoB,cAAcC,CAAgB,GACzDD,EAAO,oBAAoB,cAAcG,CAAgB,GACzDH,EAAO,oBAAoB,aAAaI,CAAe,GACvDJ,EAAO,oBAAoB,WAAWK,CAAa;AAAA,IACrD;AAAA,EACF,GAAG,CAACX,GAAYC,GAAYC,CAAQ,CAAC,GAE9BC;AACT;"}
@@ -0,0 +1,52 @@
1
+ import { useState as w, useRef as m, useEffect as x } from "react";
2
+ import g from "gsap";
3
+ import { ScrollTrigger as n } from "gsap/ScrollTrigger";
4
+ g.registerPlugin(n);
5
+ function A(e, h = {}) {
6
+ const {
7
+ duration: u = 1.5,
8
+ delay: c = 0,
9
+ onScroll: i = !0,
10
+ suffix: v = "",
11
+ prefix: M = "",
12
+ onComplete: r
13
+ } = h, [s, a] = w(0), l = m(null), t = m(!1);
14
+ x(() => {
15
+ const o = l.current;
16
+ if (!o || t.current) return;
17
+ if (window.matchMedia(
18
+ "(prefers-reduced-motion: reduce)"
19
+ ).matches) {
20
+ a(e), r?.();
21
+ return;
22
+ }
23
+ const f = { value: 0 }, d = () => {
24
+ t.current || (t.current = !0, g.to(f, {
25
+ value: e,
26
+ duration: u,
27
+ delay: c,
28
+ ease: "power2.out",
29
+ onUpdate: () => {
30
+ a(Math.round(f.value));
31
+ },
32
+ onComplete: r
33
+ }));
34
+ };
35
+ return i ? n.create({
36
+ trigger: o,
37
+ start: "top 80%",
38
+ onEnter: d,
39
+ once: !0
40
+ }) : d(), () => {
41
+ n.getAll().forEach((p) => {
42
+ p.trigger === o && p.kill();
43
+ });
44
+ };
45
+ }, [e, u, c, i, r]);
46
+ const S = `${M}${s.toLocaleString()}${v}`;
47
+ return { ref: l, value: s, displayValue: S };
48
+ }
49
+ export {
50
+ A as useCountUp
51
+ };
52
+ //# sourceMappingURL=useCountUp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCountUp.js","sources":["../../src/hooks/useCountUp.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\nimport gsap from 'gsap'\nimport { ScrollTrigger } from 'gsap/ScrollTrigger'\n\ngsap.registerPlugin(ScrollTrigger)\n\nexport interface UseCountUpOptions {\n /** Animation duration in seconds */\n duration?: number\n /** Delay before animation starts */\n delay?: number\n /** Trigger animation on scroll into view */\n onScroll?: boolean\n /** Suffix to append to value (e.g., '%', '+') */\n suffix?: string\n /** Prefix to prepend to value (e.g., '$') */\n prefix?: string\n /** Callback when animation completes */\n onComplete?: () => void\n}\n\nexport interface UseCountUpReturn {\n ref: React.RefObject<HTMLElement | null>\n value: number\n displayValue: string\n}\n\n/**\n * Hook for animated number counting\n * Creates smooth counter animations with scroll trigger support\n */\nexport function useCountUp(\n target: number,\n options: UseCountUpOptions = {}\n): UseCountUpReturn {\n const {\n duration = 1.5,\n delay = 0,\n onScroll = true,\n suffix = '',\n prefix = '',\n onComplete,\n } = options\n\n const [value, setValue] = useState(0)\n const ref = useRef<HTMLElement>(null)\n const hasAnimated = useRef(false)\n\n useEffect(() => {\n const element = ref.current\n if (!element || hasAnimated.current) return\n\n const prefersReducedMotion = window.matchMedia(\n '(prefers-reduced-motion: reduce)'\n ).matches\n\n if (prefersReducedMotion) {\n setValue(target)\n onComplete?.()\n return\n }\n\n const counter = { value: 0 }\n\n const animate = () => {\n if (hasAnimated.current) return\n hasAnimated.current = true\n\n gsap.to(counter, {\n value: target,\n duration,\n delay,\n ease: 'power2.out',\n onUpdate: () => {\n setValue(Math.round(counter.value))\n },\n onComplete,\n })\n }\n\n if (onScroll) {\n ScrollTrigger.create({\n trigger: element,\n start: 'top 80%',\n onEnter: animate,\n once: true,\n })\n } else {\n animate()\n }\n\n return () => {\n ScrollTrigger.getAll().forEach((st) => {\n if (st.trigger === element) st.kill()\n })\n }\n }, [target, duration, delay, onScroll, onComplete])\n\n const displayValue = `${prefix}${value.toLocaleString()}${suffix}`\n\n return { ref, value, displayValue }\n}\n"],"names":["gsap","ScrollTrigger","useCountUp","target","options","duration","delay","onScroll","suffix","prefix","onComplete","value","setValue","useState","ref","useRef","hasAnimated","useEffect","element","counter","animate","st","displayValue"],"mappings":";;;AAIAA,EAAK,eAAeC,CAAa;AA2B1B,SAASC,EACdC,GACAC,IAA6B,IACX;AAClB,QAAM;AAAA,IACJ,UAAAC,IAAW;AAAA,IACX,OAAAC,IAAQ;AAAA,IACR,UAAAC,IAAW;AAAA,IACX,QAAAC,IAAS;AAAA,IACT,QAAAC,IAAS;AAAA,IACT,YAAAC;AAAA,EAAA,IACEN,GAEE,CAACO,GAAOC,CAAQ,IAAIC,EAAS,CAAC,GAC9BC,IAAMC,EAAoB,IAAI,GAC9BC,IAAcD,EAAO,EAAK;AAEhC,EAAAE,EAAU,MAAM;AACd,UAAMC,IAAUJ,EAAI;AACpB,QAAI,CAACI,KAAWF,EAAY,QAAS;AAMrC,QAJ6B,OAAO;AAAA,MAClC;AAAA,IAAA,EACA,SAEwB;AACxB,MAAAJ,EAAST,CAAM,GACfO,IAAA;AACA;AAAA,IACF;AAEA,UAAMS,IAAU,EAAE,OAAO,EAAA,GAEnBC,IAAU,MAAM;AACpB,MAAIJ,EAAY,YAChBA,EAAY,UAAU,IAEtBhB,EAAK,GAAGmB,GAAS;AAAA,QACf,OAAOhB;AAAA,QACP,UAAAE;AAAA,QACA,OAAAC;AAAA,QACA,MAAM;AAAA,QACN,UAAU,MAAM;AACd,UAAAM,EAAS,KAAK,MAAMO,EAAQ,KAAK,CAAC;AAAA,QACpC;AAAA,QACA,YAAAT;AAAA,MAAA,CACD;AAAA,IACH;AAEA,WAAIH,IACFN,EAAc,OAAO;AAAA,MACnB,SAASiB;AAAA,MACT,OAAO;AAAA,MACP,SAASE;AAAA,MACT,MAAM;AAAA,IAAA,CACP,IAEDA,EAAA,GAGK,MAAM;AACX,MAAAnB,EAAc,OAAA,EAAS,QAAQ,CAACoB,MAAO;AACrC,QAAIA,EAAG,YAAYH,KAASG,EAAG,KAAA;AAAA,MACjC,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAClB,GAAQE,GAAUC,GAAOC,GAAUG,CAAU,CAAC;AAElD,QAAMY,IAAe,GAAGb,CAAM,GAAGE,EAAM,eAAA,CAAgB,GAAGH,CAAM;AAEhE,SAAO,EAAE,KAAAM,GAAK,OAAAH,GAAO,cAAAW,EAAA;AACvB;"}
@@ -0,0 +1,37 @@
1
+ import { useRef as y, useCallback as h, useEffect as d } from "react";
2
+ function p({
3
+ shortcuts: r,
4
+ enabled: e = !0
5
+ }) {
6
+ const a = y(r);
7
+ a.current = r;
8
+ const n = h(
9
+ (t) => {
10
+ if (!e) return;
11
+ const i = t.target;
12
+ if (!(i.tagName === "INPUT" || i.tagName === "TEXTAREA" || i.isContentEditable))
13
+ for (const o of a.current) {
14
+ const s = t.key.toLowerCase() === o.key.toLowerCase(), c = o.ctrl ? t.ctrlKey : !t.ctrlKey, f = o.meta ? t.metaKey : !t.metaKey, u = o.shift ? t.shiftKey : !t.shiftKey, l = o.alt ? t.altKey : !t.altKey;
15
+ if (s && c && f && u && l) {
16
+ t.preventDefault(), o.handler();
17
+ return;
18
+ }
19
+ }
20
+ },
21
+ [e]
22
+ );
23
+ d(() => (window.addEventListener("keydown", n), () => window.removeEventListener("keydown", n)), [n]);
24
+ }
25
+ function w() {
26
+ return typeof navigator > "u" ? "ctrl" : navigator.platform.toLowerCase().includes("mac") ? "meta" : "ctrl";
27
+ }
28
+ function K(r) {
29
+ const e = [], a = typeof navigator < "u" && navigator.platform.toLowerCase().includes("mac");
30
+ return r.ctrl && e.push(a ? "^" : "Ctrl"), r.meta && e.push(a ? "⌘" : "Win"), r.alt && e.push(a ? "⌥" : "Alt"), r.shift && e.push(a ? "⇧" : "Shift"), e.push(r.key.toUpperCase()), e.join(a ? "" : "+");
31
+ }
32
+ export {
33
+ K as formatShortcut,
34
+ w as getModifierKey,
35
+ p as useKeyboardShortcuts
36
+ };
37
+ //# sourceMappingURL=useKeyboardShortcuts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useKeyboardShortcuts.js","sources":["../../src/hooks/useKeyboardShortcuts.ts"],"sourcesContent":["import { useEffect, useCallback, useRef } from 'react'\n\nexport interface KeyboardShortcut {\n key: string\n ctrl?: boolean\n meta?: boolean\n shift?: boolean\n alt?: boolean\n handler: () => void\n description?: string\n}\n\nexport interface UseKeyboardShortcutsOptions {\n shortcuts: KeyboardShortcut[]\n enabled?: boolean\n}\n\nexport function useKeyboardShortcuts({\n shortcuts,\n enabled = true,\n}: UseKeyboardShortcutsOptions): void {\n const shortcutsRef = useRef(shortcuts)\n shortcutsRef.current = shortcuts\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent) => {\n if (!enabled) return\n\n // Skip if user is typing in an input\n const target = event.target as HTMLElement\n if (\n target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable\n ) {\n return\n }\n\n for (const shortcut of shortcutsRef.current) {\n const keyMatch = event.key.toLowerCase() === shortcut.key.toLowerCase()\n const ctrlMatch = shortcut.ctrl ? event.ctrlKey : !event.ctrlKey\n const metaMatch = shortcut.meta ? event.metaKey : !event.metaKey\n const shiftMatch = shortcut.shift ? event.shiftKey : !event.shiftKey\n const altMatch = shortcut.alt ? event.altKey : !event.altKey\n\n if (keyMatch && ctrlMatch && metaMatch && shiftMatch && altMatch) {\n event.preventDefault()\n shortcut.handler()\n return\n }\n }\n },\n [enabled]\n )\n\n useEffect(() => {\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [handleKeyDown])\n}\n\n// Helper to get modifier key based on OS\nexport function getModifierKey(): 'meta' | 'ctrl' {\n if (typeof navigator === 'undefined') return 'ctrl'\n return navigator.platform.toLowerCase().includes('mac') ? 'meta' : 'ctrl'\n}\n\n// Format shortcut for display\nexport function formatShortcut(shortcut: KeyboardShortcut): string {\n const parts: string[] = []\n const isMac = typeof navigator !== 'undefined' && navigator.platform.toLowerCase().includes('mac')\n\n if (shortcut.ctrl) parts.push(isMac ? '^' : 'Ctrl')\n if (shortcut.meta) parts.push(isMac ? '⌘' : 'Win')\n if (shortcut.alt) parts.push(isMac ? '⌥' : 'Alt')\n if (shortcut.shift) parts.push(isMac ? '⇧' : 'Shift')\n parts.push(shortcut.key.toUpperCase())\n\n return parts.join(isMac ? '' : '+')\n}\n"],"names":["useKeyboardShortcuts","shortcuts","enabled","shortcutsRef","useRef","handleKeyDown","useCallback","event","target","shortcut","keyMatch","ctrlMatch","metaMatch","shiftMatch","altMatch","useEffect","getModifierKey","formatShortcut","parts","isMac"],"mappings":";AAiBO,SAASA,EAAqB;AAAA,EACnC,WAAAC;AAAA,EACA,SAAAC,IAAU;AACZ,GAAsC;AACpC,QAAMC,IAAeC,EAAOH,CAAS;AACrC,EAAAE,EAAa,UAAUF;AAEvB,QAAMI,IAAgBC;AAAA,IACpB,CAACC,MAAyB;AACxB,UAAI,CAACL,EAAS;AAGd,YAAMM,IAASD,EAAM;AACrB,UACE,EAAAC,EAAO,YAAY,WACnBA,EAAO,YAAY,cACnBA,EAAO;AAKT,mBAAWC,KAAYN,EAAa,SAAS;AAC3C,gBAAMO,IAAWH,EAAM,IAAI,kBAAkBE,EAAS,IAAI,YAAA,GACpDE,IAAYF,EAAS,OAAOF,EAAM,UAAU,CAACA,EAAM,SACnDK,IAAYH,EAAS,OAAOF,EAAM,UAAU,CAACA,EAAM,SACnDM,IAAaJ,EAAS,QAAQF,EAAM,WAAW,CAACA,EAAM,UACtDO,IAAWL,EAAS,MAAMF,EAAM,SAAS,CAACA,EAAM;AAEtD,cAAIG,KAAYC,KAAaC,KAAaC,KAAcC,GAAU;AAChE,YAAAP,EAAM,eAAA,GACNE,EAAS,QAAA;AACT;AAAA,UACF;AAAA,QACF;AAAA,IACF;AAAA,IACA,CAACP,CAAO;AAAA,EAAA;AAGV,EAAAa,EAAU,OACR,OAAO,iBAAiB,WAAWV,CAAa,GACzC,MAAM,OAAO,oBAAoB,WAAWA,CAAa,IAC/D,CAACA,CAAa,CAAC;AACpB;AAGO,SAASW,IAAkC;AAChD,SAAI,OAAO,YAAc,MAAoB,SACtC,UAAU,SAAS,YAAA,EAAc,SAAS,KAAK,IAAI,SAAS;AACrE;AAGO,SAASC,EAAeR,GAAoC;AACjE,QAAMS,IAAkB,CAAA,GAClBC,IAAQ,OAAO,YAAc,OAAe,UAAU,SAAS,YAAA,EAAc,SAAS,KAAK;AAEjG,SAAIV,EAAS,QAAMS,EAAM,KAAKC,IAAQ,MAAM,MAAM,GAC9CV,EAAS,QAAMS,EAAM,KAAKC,IAAQ,MAAM,KAAK,GAC7CV,EAAS,OAAKS,EAAM,KAAKC,IAAQ,MAAM,KAAK,GAC5CV,EAAS,SAAOS,EAAM,KAAKC,IAAQ,MAAM,OAAO,GACpDD,EAAM,KAAKT,EAAS,IAAI,YAAA,CAAa,GAE9BS,EAAM,KAAKC,IAAQ,KAAK,GAAG;AACpC;"}
@@ -0,0 +1,59 @@
1
+ import { useMemo as d, useCallback as m, useState as f, useEffect as h } from "react";
2
+ const r = {
3
+ sm: 640,
4
+ md: 768,
5
+ lg: 1024,
6
+ xl: 1280,
7
+ "2xl": 1536
8
+ };
9
+ function n(t, e = !1) {
10
+ const s = m(() => typeof window > "u" ? e : window.matchMedia(t).matches, [t, e]), [o, i] = f(s);
11
+ return h(() => {
12
+ if (typeof window > "u")
13
+ return;
14
+ const u = window.matchMedia(t);
15
+ i(u.matches);
16
+ const a = (c) => {
17
+ i(c.matches);
18
+ };
19
+ return u.addEventListener("change", a), () => u.removeEventListener("change", a);
20
+ }, [t]), o;
21
+ }
22
+ function x() {
23
+ return n("(max-width: 767px)", !0);
24
+ }
25
+ function w() {
26
+ return n("(min-width: 768px) and (max-width: 1023px)");
27
+ }
28
+ function l() {
29
+ return n("(min-width: 1024px)");
30
+ }
31
+ function g() {
32
+ return n("(min-width: 1280px)");
33
+ }
34
+ function I() {
35
+ const t = n(`(min-width: ${r.sm}px)`), e = n(`(min-width: ${r.md}px)`), s = n(`(min-width: ${r.lg}px)`), o = n(`(min-width: ${r.xl}px)`), i = n(`(min-width: ${r["2xl"]}px)`);
36
+ return d(() => i ? "2xl" : o ? "xl" : s ? "lg" : e ? "md" : t ? "sm" : "xs", [t, e, s, o, i]);
37
+ }
38
+ function M() {
39
+ return n("(hover: none) and (pointer: coarse)");
40
+ }
41
+ function v() {
42
+ return n("(orientation: portrait)");
43
+ }
44
+ function L() {
45
+ return n("(orientation: landscape)");
46
+ }
47
+ export {
48
+ r as BREAKPOINTS,
49
+ I as useBreakpoint,
50
+ l as useIsDesktop,
51
+ L as useIsLandscape,
52
+ g as useIsLargeDesktop,
53
+ x as useIsMobile,
54
+ v as useIsPortrait,
55
+ w as useIsTablet,
56
+ M as useIsTouchDevice,
57
+ n as useMediaQuery
58
+ };
59
+ //# sourceMappingURL=useMediaQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaQuery.js","sources":["../../src/hooks/useMediaQuery.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useMemo } from 'react'\n\n/**\n * Standard breakpoints matching Tailwind CSS defaults\n * sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px\n */\nexport const BREAKPOINTS = {\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n '2xl': 1536,\n} as const\n\nexport type Breakpoint = keyof typeof BREAKPOINTS\n\n/**\n * Hook for responsive media queries with SSR safety\n * Returns false during SSR to prevent hydration mismatches\n *\n * @param query - CSS media query string\n * @param defaultValue - Initial value for SSR (defaults to false)\n * @returns boolean indicating if the query matches\n */\nexport function useMediaQuery(query: string, defaultValue = false): boolean {\n // Use callback to get initial state to avoid SSR issues\n const getInitialState = useCallback(() => {\n if (typeof window === 'undefined') {\n return defaultValue\n }\n return window.matchMedia(query).matches\n }, [query, defaultValue])\n\n const [matches, setMatches] = useState(getInitialState)\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return\n }\n\n const mediaQuery = window.matchMedia(query)\n\n // Set initial value (handles SSR hydration)\n setMatches(mediaQuery.matches)\n\n const handleChange = (event: MediaQueryListEvent) => {\n setMatches(event.matches)\n }\n\n mediaQuery.addEventListener('change', handleChange)\n return () => mediaQuery.removeEventListener('change', handleChange)\n }, [query])\n\n return matches\n}\n\n/**\n * Returns true when viewport is mobile width (< 768px)\n * Mobile-first default: returns true initially for SSR\n */\nexport function useIsMobile(): boolean {\n return useMediaQuery('(max-width: 767px)', true)\n}\n\n/**\n * Returns true when viewport is tablet width (768px - 1023px)\n */\nexport function useIsTablet(): boolean {\n return useMediaQuery('(min-width: 768px) and (max-width: 1023px)')\n}\n\n/**\n * Returns true when viewport is desktop width (>= 1024px)\n */\nexport function useIsDesktop(): boolean {\n return useMediaQuery('(min-width: 1024px)')\n}\n\n/**\n * Returns true when viewport is large desktop width (>= 1280px)\n */\nexport function useIsLargeDesktop(): boolean {\n return useMediaQuery('(min-width: 1280px)')\n}\n\n/**\n * Returns the current breakpoint name\n * Useful for conditional rendering based on screen size\n */\nexport function useBreakpoint(): Breakpoint | 'xs' {\n const isSm = useMediaQuery(`(min-width: ${BREAKPOINTS.sm}px)`)\n const isMd = useMediaQuery(`(min-width: ${BREAKPOINTS.md}px)`)\n const isLg = useMediaQuery(`(min-width: ${BREAKPOINTS.lg}px)`)\n const isXl = useMediaQuery(`(min-width: ${BREAKPOINTS.xl}px)`)\n const is2xl = useMediaQuery(`(min-width: ${BREAKPOINTS['2xl']}px)`)\n\n return useMemo(() => {\n if (is2xl) return '2xl'\n if (isXl) return 'xl'\n if (isLg) return 'lg'\n if (isMd) return 'md'\n if (isSm) return 'sm'\n return 'xs'\n }, [isSm, isMd, isLg, isXl, is2xl])\n}\n\n/**\n * Returns true when user prefers touch interaction\n * Useful for adapting UI interactions\n */\nexport function useIsTouchDevice(): boolean {\n return useMediaQuery('(hover: none) and (pointer: coarse)')\n}\n\n/**\n * Returns true when viewport is in portrait orientation\n */\nexport function useIsPortrait(): boolean {\n return useMediaQuery('(orientation: portrait)')\n}\n\n/**\n * Returns true when viewport is in landscape orientation\n */\nexport function useIsLandscape(): boolean {\n return useMediaQuery('(orientation: landscape)')\n}\n"],"names":["BREAKPOINTS","useMediaQuery","query","defaultValue","getInitialState","useCallback","matches","setMatches","useState","useEffect","mediaQuery","handleChange","event","useIsMobile","useIsTablet","useIsDesktop","useIsLargeDesktop","useBreakpoint","isSm","isMd","isLg","isXl","is2xl","useMemo","useIsTouchDevice","useIsPortrait","useIsLandscape"],"mappings":";AAMO,MAAMA,IAAc;AAAA,EACzB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AACT;AAYO,SAASC,EAAcC,GAAeC,IAAe,IAAgB;AAE1E,QAAMC,IAAkBC,EAAY,MAC9B,OAAO,SAAW,MACbF,IAEF,OAAO,WAAWD,CAAK,EAAE,SAC/B,CAACA,GAAOC,CAAY,CAAC,GAElB,CAACG,GAASC,CAAU,IAAIC,EAASJ,CAAe;AAEtD,SAAAK,EAAU,MAAM;AACd,QAAI,OAAO,SAAW;AACpB;AAGF,UAAMC,IAAa,OAAO,WAAWR,CAAK;AAG1C,IAAAK,EAAWG,EAAW,OAAO;AAE7B,UAAMC,IAAe,CAACC,MAA+B;AACnD,MAAAL,EAAWK,EAAM,OAAO;AAAA,IAC1B;AAEA,WAAAF,EAAW,iBAAiB,UAAUC,CAAY,GAC3C,MAAMD,EAAW,oBAAoB,UAAUC,CAAY;AAAA,EACpE,GAAG,CAACT,CAAK,CAAC,GAEHI;AACT;AAMO,SAASO,IAAuB;AACrC,SAAOZ,EAAc,sBAAsB,EAAI;AACjD;AAKO,SAASa,IAAuB;AACrC,SAAOb,EAAc,4CAA4C;AACnE;AAKO,SAASc,IAAwB;AACtC,SAAOd,EAAc,qBAAqB;AAC5C;AAKO,SAASe,IAA6B;AAC3C,SAAOf,EAAc,qBAAqB;AAC5C;AAMO,SAASgB,IAAmC;AACjD,QAAMC,IAAOjB,EAAc,eAAeD,EAAY,EAAE,KAAK,GACvDmB,IAAOlB,EAAc,eAAeD,EAAY,EAAE,KAAK,GACvDoB,IAAOnB,EAAc,eAAeD,EAAY,EAAE,KAAK,GACvDqB,IAAOpB,EAAc,eAAeD,EAAY,EAAE,KAAK,GACvDsB,IAAQrB,EAAc,eAAeD,EAAY,KAAK,CAAC,KAAK;AAElE,SAAOuB,EAAQ,MACTD,IAAc,QACdD,IAAa,OACbD,IAAa,OACbD,IAAa,OACbD,IAAa,OACV,MACN,CAACA,GAAMC,GAAMC,GAAMC,GAAMC,CAAK,CAAC;AACpC;AAMO,SAASE,IAA4B;AAC1C,SAAOvB,EAAc,qCAAqC;AAC5D;AAKO,SAASwB,IAAyB;AACvC,SAAOxB,EAAc,yBAAyB;AAChD;AAKO,SAASyB,IAA0B;AACxC,SAAOzB,EAAc,0BAA0B;AACjD;"}
@@ -0,0 +1,39 @@
1
+ import { useRef as c, useEffect as u } from "react";
2
+ import i from "gsap";
3
+ function p(n = {}) {
4
+ const { duration: t = 0.5, exitDuration: o = 0.25 } = n, r = c(null);
5
+ return u(() => {
6
+ const e = r.current;
7
+ if (!e) return;
8
+ if (window.matchMedia(
9
+ "(prefers-reduced-motion: reduce)"
10
+ ).matches) {
11
+ e.style.opacity = "1";
12
+ return;
13
+ }
14
+ return i.fromTo(
15
+ e,
16
+ {
17
+ opacity: 0,
18
+ y: 16
19
+ },
20
+ {
21
+ opacity: 1,
22
+ y: 0,
23
+ duration: t,
24
+ ease: "cubic.out"
25
+ }
26
+ ), () => {
27
+ e && i.to(e, {
28
+ opacity: 0,
29
+ y: -8,
30
+ duration: o,
31
+ ease: "cubic.in"
32
+ });
33
+ };
34
+ }, [t, o]), r;
35
+ }
36
+ export {
37
+ p as usePageTransition
38
+ };
39
+ //# sourceMappingURL=usePageTransition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePageTransition.js","sources":["../../src/hooks/usePageTransition.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport gsap from 'gsap'\n\nexport interface UsePageTransitionOptions {\n /** Entrance animation duration in seconds */\n duration?: number\n /** Exit animation duration in seconds */\n exitDuration?: number\n}\n\n/**\n * Hook for page entrance/exit animations\n * Creates smooth transitions when navigating between pages\n */\nexport function usePageTransition(options: UsePageTransitionOptions = {}) {\n const { duration = 0.5, exitDuration = 0.25 } = options\n const pageRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const page = pageRef.current\n if (!page) return\n\n const prefersReducedMotion = window.matchMedia(\n '(prefers-reduced-motion: reduce)'\n ).matches\n\n if (prefersReducedMotion) {\n page.style.opacity = '1'\n return\n }\n\n // Entrance animation\n gsap.fromTo(\n page,\n {\n opacity: 0,\n y: 16,\n },\n {\n opacity: 1,\n y: 0,\n duration,\n ease: 'cubic.out',\n }\n )\n\n // Exit animation on unmount\n return () => {\n if (page) {\n gsap.to(page, {\n opacity: 0,\n y: -8,\n duration: exitDuration,\n ease: 'cubic.in',\n })\n }\n }\n }, [duration, exitDuration])\n\n return pageRef\n}\n"],"names":["usePageTransition","options","duration","exitDuration","pageRef","useRef","useEffect","page","gsap"],"mappings":";;AAcO,SAASA,EAAkBC,IAAoC,IAAI;AACxE,QAAM,EAAE,UAAAC,IAAW,KAAK,cAAAC,IAAe,SAASF,GAC1CG,IAAUC,EAAuB,IAAI;AAE3C,SAAAC,EAAU,MAAM;AACd,UAAMC,IAAOH,EAAQ;AACrB,QAAI,CAACG,EAAM;AAMX,QAJ6B,OAAO;AAAA,MAClC;AAAA,IAAA,EACA,SAEwB;AACxB,MAAAA,EAAK,MAAM,UAAU;AACrB;AAAA,IACF;AAGA,WAAAC,EAAK;AAAA,MACHD;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT,GAAG;AAAA,MAAA;AAAA,MAEL;AAAA,QACE,SAAS;AAAA,QACT,GAAG;AAAA,QACH,UAAAL;AAAA,QACA,MAAM;AAAA,MAAA;AAAA,IACR,GAIK,MAAM;AACX,MAAIK,KACFC,EAAK,GAAGD,GAAM;AAAA,QACZ,SAAS;AAAA,QACT,GAAG;AAAA,QACH,UAAUJ;AAAA,QACV,MAAM;AAAA,MAAA,CACP;AAAA,IAEL;AAAA,EACF,GAAG,CAACD,GAAUC,CAAY,CAAC,GAEpBC;AACT;"}
@@ -0,0 +1,57 @@
1
+ import { useMemo as u, useCallback as s, useState as a, useEffect as d } from "react";
2
+ function c() {
3
+ const e = s(() => typeof window > "u" ? !0 : window.matchMedia("(prefers-reduced-motion: reduce)").matches, []), [i, n] = a(e);
4
+ return d(() => {
5
+ if (typeof window > "u")
6
+ return;
7
+ const t = window.matchMedia("(prefers-reduced-motion: reduce)");
8
+ n(t.matches);
9
+ const r = (o) => {
10
+ n(o.matches);
11
+ };
12
+ return t.addEventListener("change", r), () => t.removeEventListener("change", r);
13
+ }, []), i;
14
+ }
15
+ function h() {
16
+ const e = c();
17
+ return u(
18
+ () => ({
19
+ /** Whether reduced motion is preferred */
20
+ isReduced: e,
21
+ /** Suggested animation duration in ms */
22
+ duration: e ? 0 : 300,
23
+ /** Suggested animation duration as CSS value */
24
+ durationCss: e ? "0ms" : "300ms",
25
+ /** Suggested easing function */
26
+ easing: e ? "linear" : "cubic-bezier(0.4, 0, 0.2, 1)",
27
+ /** Whether to disable transform animations */
28
+ disableTransform: e,
29
+ /** Whether to disable parallax effects */
30
+ disableParallax: e,
31
+ /** Whether to disable auto-playing animations */
32
+ disableAutoPlay: e,
33
+ /** Suggested transition config for Framer Motion / GSAP */
34
+ transition: e ? { duration: 0 } : { duration: 0.3, ease: [0.4, 0, 0.2, 1] }
35
+ }),
36
+ [e]
37
+ );
38
+ }
39
+ function m() {
40
+ const e = s(() => typeof window > "u" ? !1 : window.matchMedia("(prefers-contrast: high)").matches, []), [i, n] = a(e);
41
+ return d(() => {
42
+ if (typeof window > "u")
43
+ return;
44
+ const t = window.matchMedia("(prefers-contrast: high)");
45
+ n(t.matches);
46
+ const r = (o) => {
47
+ n(o.matches);
48
+ };
49
+ return t.addEventListener("change", r), () => t.removeEventListener("change", r);
50
+ }, []), i;
51
+ }
52
+ export {
53
+ h as useMotionConfig,
54
+ m as usePrefersHighContrast,
55
+ c as useReducedMotion
56
+ };
57
+ //# sourceMappingURL=useReducedMotion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useReducedMotion.js","sources":["../../src/hooks/useReducedMotion.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useMemo } from 'react'\n\n/**\n * Hook to detect user's motion preference with SSR safety\n * Returns true if user prefers reduced motion\n *\n * Note: For animations, consider using this to:\n * - Disable or reduce animation duration\n * - Use fade instead of transform animations\n * - Skip parallax and auto-playing animations\n */\nexport function useReducedMotion(): boolean {\n const getInitialState = useCallback(() => {\n if (typeof window === 'undefined') {\n // Default to reduced motion for SSR (safer, more accessible)\n return true\n }\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n }, [])\n\n const [prefersReducedMotion, setPrefersReducedMotion] = useState(getInitialState)\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return\n }\n\n const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)')\n\n // Update on mount for SSR hydration\n setPrefersReducedMotion(mediaQuery.matches)\n\n const handleChange = (event: MediaQueryListEvent) => {\n setPrefersReducedMotion(event.matches)\n }\n\n mediaQuery.addEventListener('change', handleChange)\n return () => mediaQuery.removeEventListener('change', handleChange)\n }, [])\n\n return prefersReducedMotion\n}\n\n/**\n * Returns animation configuration based on reduced motion preference\n * Provides sensible defaults that can be spread into animation props\n */\nexport function useMotionConfig() {\n const prefersReducedMotion = useReducedMotion()\n\n return useMemo(\n () => ({\n /** Whether reduced motion is preferred */\n isReduced: prefersReducedMotion,\n\n /** Suggested animation duration in ms */\n duration: prefersReducedMotion ? 0 : 300,\n\n /** Suggested animation duration as CSS value */\n durationCss: prefersReducedMotion ? '0ms' : '300ms',\n\n /** Suggested easing function */\n easing: prefersReducedMotion ? 'linear' : 'cubic-bezier(0.4, 0, 0.2, 1)',\n\n /** Whether to disable transform animations */\n disableTransform: prefersReducedMotion,\n\n /** Whether to disable parallax effects */\n disableParallax: prefersReducedMotion,\n\n /** Whether to disable auto-playing animations */\n disableAutoPlay: prefersReducedMotion,\n\n /** Suggested transition config for Framer Motion / GSAP */\n transition: prefersReducedMotion\n ? { duration: 0 }\n : { duration: 0.3, ease: [0.4, 0, 0.2, 1] },\n }),\n [prefersReducedMotion]\n )\n}\n\n/**\n * Returns true if user prefers high contrast\n */\nexport function usePrefersHighContrast(): boolean {\n const getInitialState = useCallback(() => {\n if (typeof window === 'undefined') {\n return false\n }\n return window.matchMedia('(prefers-contrast: high)').matches\n }, [])\n\n const [prefersHighContrast, setPrefersHighContrast] = useState(getInitialState)\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return\n }\n\n const mediaQuery = window.matchMedia('(prefers-contrast: high)')\n setPrefersHighContrast(mediaQuery.matches)\n\n const handleChange = (event: MediaQueryListEvent) => {\n setPrefersHighContrast(event.matches)\n }\n\n mediaQuery.addEventListener('change', handleChange)\n return () => mediaQuery.removeEventListener('change', handleChange)\n }, [])\n\n return prefersHighContrast\n}\n"],"names":["useReducedMotion","getInitialState","useCallback","prefersReducedMotion","setPrefersReducedMotion","useState","useEffect","mediaQuery","handleChange","event","useMotionConfig","useMemo","usePrefersHighContrast","prefersHighContrast","setPrefersHighContrast"],"mappings":";AAWO,SAASA,IAA4B;AAC1C,QAAMC,IAAkBC,EAAY,MAC9B,OAAO,SAAW,MAEb,KAEF,OAAO,WAAW,kCAAkC,EAAE,SAC5D,CAAA,CAAE,GAEC,CAACC,GAAsBC,CAAuB,IAAIC,EAASJ,CAAe;AAEhF,SAAAK,EAAU,MAAM;AACd,QAAI,OAAO,SAAW;AACpB;AAGF,UAAMC,IAAa,OAAO,WAAW,kCAAkC;AAGvE,IAAAH,EAAwBG,EAAW,OAAO;AAE1C,UAAMC,IAAe,CAACC,MAA+B;AACnD,MAAAL,EAAwBK,EAAM,OAAO;AAAA,IACvC;AAEA,WAAAF,EAAW,iBAAiB,UAAUC,CAAY,GAC3C,MAAMD,EAAW,oBAAoB,UAAUC,CAAY;AAAA,EACpE,GAAG,CAAA,CAAE,GAEEL;AACT;AAMO,SAASO,IAAkB;AAChC,QAAMP,IAAuBH,EAAA;AAE7B,SAAOW;AAAA,IACL,OAAO;AAAA;AAAA,MAEL,WAAWR;AAAA;AAAA,MAGX,UAAUA,IAAuB,IAAI;AAAA;AAAA,MAGrC,aAAaA,IAAuB,QAAQ;AAAA;AAAA,MAG5C,QAAQA,IAAuB,WAAW;AAAA;AAAA,MAG1C,kBAAkBA;AAAA;AAAA,MAGlB,iBAAiBA;AAAA;AAAA,MAGjB,iBAAiBA;AAAA;AAAA,MAGjB,YAAYA,IACR,EAAE,UAAU,MACZ,EAAE,UAAU,KAAK,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,EAAA;AAAA,IAAE;AAAA,IAE9C,CAACA,CAAoB;AAAA,EAAA;AAEzB;AAKO,SAASS,IAAkC;AAChD,QAAMX,IAAkBC,EAAY,MAC9B,OAAO,SAAW,MACb,KAEF,OAAO,WAAW,0BAA0B,EAAE,SACpD,CAAA,CAAE,GAEC,CAACW,GAAqBC,CAAsB,IAAIT,EAASJ,CAAe;AAE9E,SAAAK,EAAU,MAAM;AACd,QAAI,OAAO,SAAW;AACpB;AAGF,UAAMC,IAAa,OAAO,WAAW,0BAA0B;AAC/D,IAAAO,EAAuBP,EAAW,OAAO;AAEzC,UAAMC,IAAe,CAACC,MAA+B;AACnD,MAAAK,EAAuBL,EAAM,OAAO;AAAA,IACtC;AAEA,WAAAF,EAAW,iBAAiB,UAAUC,CAAY,GAC3C,MAAMD,EAAW,oBAAoB,UAAUC,CAAY;AAAA,EACpE,GAAG,CAAA,CAAE,GAEEK;AACT;"}
@@ -0,0 +1,61 @@
1
+ import { useRef as g, useEffect as p } from "react";
2
+ import n from "gsap";
3
+ import { ScrollTrigger as m } from "gsap/ScrollTrigger";
4
+ n.registerPlugin(m);
5
+ function w(f = {}) {
6
+ const {
7
+ duration: c = 0.8,
8
+ delay: i = 0,
9
+ stagger: r = 0.1,
10
+ direction: s = "up",
11
+ distance: e = 40
12
+ } = f, u = g(null);
13
+ return p(() => {
14
+ const t = u.current;
15
+ if (!t) return;
16
+ const o = Array.from(t.children);
17
+ if (o.length === 0) return;
18
+ const l = {
19
+ up: { y: e, x: 0 },
20
+ down: { y: -e, x: 0 },
21
+ left: { x: e, y: 0 },
22
+ right: { x: -e, y: 0 }
23
+ }[s];
24
+ if (window.matchMedia(
25
+ "(prefers-reduced-motion: reduce)"
26
+ ).matches) {
27
+ o.forEach((d) => {
28
+ d.style.opacity = "1";
29
+ });
30
+ return;
31
+ }
32
+ const a = n.context(() => {
33
+ n.fromTo(
34
+ o,
35
+ {
36
+ opacity: 0,
37
+ ...l
38
+ },
39
+ {
40
+ opacity: 1,
41
+ x: 0,
42
+ y: 0,
43
+ duration: c,
44
+ delay: i,
45
+ stagger: r ? typeof r == "number" ? r : 0.1 : 0,
46
+ ease: "cubic.out",
47
+ scrollTrigger: {
48
+ trigger: t,
49
+ start: "top 80%",
50
+ toggleActions: "play none none none"
51
+ }
52
+ }
53
+ );
54
+ }, t);
55
+ return () => a.revert();
56
+ }, [c, i, r, s, e]), u;
57
+ }
58
+ export {
59
+ w as useScrollReveal
60
+ };
61
+ //# sourceMappingURL=useScrollReveal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScrollReveal.js","sources":["../../src/hooks/useScrollReveal.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport gsap from 'gsap'\nimport { ScrollTrigger } from 'gsap/ScrollTrigger'\n\ngsap.registerPlugin(ScrollTrigger)\n\nexport interface UseScrollRevealOptions {\n /** Animation duration in seconds */\n duration?: number\n /** Delay before animation starts */\n delay?: number\n /** Stagger delay between children (false to disable, number for custom) */\n stagger?: boolean | number\n /** Direction elements animate from */\n direction?: 'up' | 'down' | 'left' | 'right'\n /** Distance in pixels to animate from */\n distance?: number\n}\n\n/**\n * Hook that creates scroll-triggered entrance animations\n * Uses GSAP ScrollTrigger for performant viewport-based reveals\n */\nexport function useScrollReveal(options: UseScrollRevealOptions = {}) {\n const {\n duration = 0.8,\n delay = 0,\n stagger = 0.1,\n direction = 'up',\n distance = 40,\n } = options\n\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const element = ref.current\n if (!element) return\n\n const children = Array.from(element.children) as HTMLElement[]\n if (children.length === 0) return\n\n const directions = {\n up: { y: distance, x: 0 },\n down: { y: -distance, x: 0 },\n left: { x: distance, y: 0 },\n right: { x: -distance, y: 0 },\n }\n\n const movement = directions[direction]\n\n // Check for reduced motion preference\n const prefersReducedMotion = window.matchMedia(\n '(prefers-reduced-motion: reduce)'\n ).matches\n\n if (prefersReducedMotion) {\n children.forEach((child) => {\n child.style.opacity = '1'\n })\n return\n }\n\n // Create timeline for staggered reveals\n const ctx = gsap.context(() => {\n gsap.fromTo(\n children,\n {\n opacity: 0,\n ...movement,\n },\n {\n opacity: 1,\n x: 0,\n y: 0,\n duration,\n delay,\n stagger: stagger ? (typeof stagger === 'number' ? stagger : 0.1) : 0,\n ease: 'cubic.out',\n scrollTrigger: {\n trigger: element,\n start: 'top 80%',\n toggleActions: 'play none none none',\n },\n }\n )\n }, element)\n\n return () => ctx.revert()\n }, [duration, delay, stagger, direction, distance])\n\n return ref\n}\n"],"names":["gsap","ScrollTrigger","useScrollReveal","options","duration","delay","stagger","direction","distance","ref","useRef","useEffect","element","children","movement","child","ctx"],"mappings":";;;AAIAA,EAAK,eAAeC,CAAa;AAmB1B,SAASC,EAAgBC,IAAkC,IAAI;AACpE,QAAM;AAAA,IACJ,UAAAC,IAAW;AAAA,IACX,OAAAC,IAAQ;AAAA,IACR,SAAAC,IAAU;AAAA,IACV,WAAAC,IAAY;AAAA,IACZ,UAAAC,IAAW;AAAA,EAAA,IACTL,GAEEM,IAAMC,EAAuB,IAAI;AAEvC,SAAAC,EAAU,MAAM;AACd,UAAMC,IAAUH,EAAI;AACpB,QAAI,CAACG,EAAS;AAEd,UAAMC,IAAW,MAAM,KAAKD,EAAQ,QAAQ;AAC5C,QAAIC,EAAS,WAAW,EAAG;AAS3B,UAAMC,IAPa;AAAA,MACjB,IAAI,EAAE,GAAGN,GAAU,GAAG,EAAA;AAAA,MACtB,MAAM,EAAE,GAAG,CAACA,GAAU,GAAG,EAAA;AAAA,MACzB,MAAM,EAAE,GAAGA,GAAU,GAAG,EAAA;AAAA,MACxB,OAAO,EAAE,GAAG,CAACA,GAAU,GAAG,EAAA;AAAA,IAAE,EAGFD,CAAS;AAOrC,QAJ6B,OAAO;AAAA,MAClC;AAAA,IAAA,EACA,SAEwB;AACxB,MAAAM,EAAS,QAAQ,CAACE,MAAU;AAC1B,QAAAA,EAAM,MAAM,UAAU;AAAA,MACxB,CAAC;AACD;AAAA,IACF;AAGA,UAAMC,IAAMhB,EAAK,QAAQ,MAAM;AAC7B,MAAAA,EAAK;AAAA,QACHa;AAAA,QACA;AAAA,UACE,SAAS;AAAA,UACT,GAAGC;AAAA,QAAA;AAAA,QAEL;AAAA,UACE,SAAS;AAAA,UACT,GAAG;AAAA,UACH,GAAG;AAAA,UACH,UAAAV;AAAA,UACA,OAAAC;AAAA,UACA,SAASC,IAAW,OAAOA,KAAY,WAAWA,IAAU,MAAO;AAAA,UACnE,MAAM;AAAA,UACN,eAAe;AAAA,YACb,SAASM;AAAA,YACT,OAAO;AAAA,YACP,eAAe;AAAA,UAAA;AAAA,QACjB;AAAA,MACF;AAAA,IAEJ,GAAGA,CAAO;AAEV,WAAO,MAAMI,EAAI,OAAA;AAAA,EACnB,GAAG,CAACZ,GAAUC,GAAOC,GAASC,GAAWC,CAAQ,CAAC,GAE3CC;AACT;"}