@tuwaio/nova-core 0.0.10 → 0.1.1

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.
package/README.md CHANGED
@@ -4,48 +4,240 @@
4
4
  [![License](https://img.shields.io/npm/l/@tuwaio/nova-core.svg)](./LICENSE)
5
5
  [![Build Status](https://img.shields.io/github/actions/workflow/status/TuwaIO/nova-uikit/release.yml?branch=main)](https://github.com/TuwaIO/nova-uikit/actions)
6
6
 
7
- The foundational package for the TUWA design system. Provides core styling primitives, theme variables, and common React hooks and utilities.
7
+ The foundational package for the Nova UI Kit design system. Provides core styling primitives, theme variables, utility functions, and common React hooks for building consistent Web3 applications.
8
+
9
+ -----
8
10
 
9
11
  ## What is `@tuwaio/nova-core`?
10
12
 
11
- `@tuwaio/nova-core` is the engine of the TUWA design system. It is **not** a component library. Instead, it provides the low-level tools necessary to build consistent, high-quality user interfaces across all TUWA products.
13
+ `@tuwaio/nova-core` is the **foundational engine** of the Nova UI Kit design system. It is **not** a component library—instead, it provides the low-level tools, design tokens, and utilities necessary to build consistent, high-quality user interfaces across all TUWA products.
14
+
15
+ Built for the **TUWA ecosystem**, Nova Core serves as the shared foundation that powers all other Nova packages (`@tuwaio/nova-connect`, `@tuwaio/nova-transactions`) and ensures design consistency across multi-chain Web3 applications.
16
+
17
+ **Why Nova Core?**
18
+
19
+ Building design systems requires consistent foundations: colors, spacing, typography, and utility functions. Without a shared core, different packages end up with conflicting styles, duplicated code, and inconsistent user experiences.
20
+
21
+ Nova Core solves this by:
22
+
23
+ 1. **Providing Unified Design Tokens:** A comprehensive CSS variable system that ensures visual consistency across all components.
24
+ 2. **Offering Smart Utilities:** Battle-tested helper functions like the `cn` utility that combines `clsx` and `tailwind-merge` for conflict-free styling.
25
+ 3. **Supplying Common Hooks:** A collection of reusable React hooks for common Web3 UI patterns.
26
+ 4. **Ensuring Tailwind CSS v4 Integration:** Seamless compatibility with modern Tailwind CSS workflows.
27
+
28
+ -----
12
29
 
13
- Use this package to:
14
- - Ensure brand consistency with a centralized theme and styling.
15
- - Speed up development with a set of battle-tested helper hooks and utilities.
16
- - Provide a solid foundation for our component library, `@tuwaio/nova-transactions`.
30
+ ## Key Features
17
31
 
18
- ## Core Features
32
+ - **🎨 Complete Design Token System:** Comprehensive CSS variables for colors, spacing, typography, shadows, and animations
33
+ - **🛠️ Smart Utility Functions:** Advanced `cn` utility that merges Tailwind classes intelligently, preventing style conflicts
34
+ - **🎣 Common React Hooks:** Collection of reusable hooks for Web3 UI patterns like wallet state, transaction status, and theme management
35
+ - **⚡ Tailwind CSS v4 Ready:** Full compatibility with modern Tailwind CSS workflows and arbitrary value usage
36
+ - **🌓 Dark Mode Support:** Built-in dark mode theming with CSS variable-based switching
37
+ - **♿ Accessibility First:** ARIA-compliant design tokens and utilities for building accessible interfaces
38
+ - **📱 Responsive Design:** Mobile-first breakpoints and responsive utility functions
19
39
 
20
- - **🎨 Styling Primitives:** A single CSS file containing all TUWA design tokens as CSS variables (e.g., `--tuwa-color-primary`).
21
- - **🛠️ Helper Utilities:** A smart `cn` utility that combines `clsx` and `tailwind-merge` for building dynamic and conflict-free class names.
22
- - **🎣 Common Hooks:** A collection of generic, reusable React hooks for common tasks.
40
+ -----
23
41
 
24
- ## Installation
42
+ ## 💾 Installation
25
43
 
26
- 1. Install the package using your preferred package manager:
44
+ ### Requirements
27
45
 
28
- ```bash
29
- pnpm add @tuwaio/nova-core
30
- ```
46
+ - **React:** 19+
47
+ - **Node.js:** 20+
48
+ - **TypeScript:** 5.9+ (recommended)
31
49
 
32
- 2. **Import the core styles** into the root of your application's main CSS file (e.g., `globals.css`). **This step is crucial.**
50
+ ### Package Installation
33
51
 
34
- ```css
35
- @import '@tuwaio/nova-core/dist/index.css';
36
- ```
52
+ Install the package using your preferred package manager:
37
53
 
38
- ### Usage
54
+ ```bash
55
+ # Using pnpm (recommended)
56
+ pnpm add @tuwaio/nova-core
57
+
58
+ # Using npm
59
+ npm install @tuwaio/nova-core
60
+
61
+ # Using yarn
62
+ yarn add @tuwaio/nova-core
63
+ ```
64
+
65
+ ### CSS Setup
66
+
67
+ **⚠️ Critical Step:** Import the core styles into your application's main CSS file. This step is essential for accessing base styles.
68
+
69
+ ```css
70
+ /* src/styles/globals.css or src/styles/app.css */
71
+ @import '@tuwaio/nova-core/dist/index.css';
72
+ ```
39
73
 
40
- For example with Tailwind CSS v4, you can use the CSS variables from this package directly in your className as arbitrary values only need to @import tailwindcss in your .css file.
74
+ -----
75
+
76
+ ## 🚀 Usage
77
+
78
+ ### Design Tokens with Tailwind CSS v4
79
+
80
+ Nova Core is designed to work seamlessly with Tailwind CSS v4. You can use the CSS variables directly in your `className` as arbitrary values:
41
81
 
42
82
  ```tsx
43
- // You can use the variables directly
44
- <button className="bg-[var(--tuwa-color-primary)] text-[var(--tuwa-color-foreground)] p-[var(--tuwa-spacing-md)]">
45
- Click Me
83
+ // Using Nova design tokens in Tailwind classes
84
+ <button className="bg-[var(--tuwa-color-primary)] text-[var(--tuwa-text-on-primary)]">
85
+ Connect Wallet
46
86
  </button>
87
+
88
+ // With hover states and transitions
89
+ <div className="
90
+ p-[var(--tuwa-spacing-md)]
91
+ bg-[var(--tuwa-bg-secondary)]
92
+ hover:bg-[var(--tuwa-bg-hover)]
93
+ transition-colors
94
+ ">
95
+ Card Content
96
+ </div>
47
97
  ```
48
98
 
99
+ ### The `cn` Utility Function
100
+
101
+ The `cn` utility combines `clsx` and `tailwind-merge` to provide intelligent class merging:
102
+
103
+ ```tsx
104
+ import { cn } from '@tuwaio/nova-core';
105
+
106
+ // Basic usage
107
+ const buttonClass = cn(
108
+ 'px-4 py-2 font-medium rounded-lg', // base styles
109
+ 'bg-blue-500 text-white', // default variant
110
+ {'opacity-50 cursor-not-allowed': isLoading}, // conditional styles
111
+ className // additional classes from props
112
+ );
113
+
114
+ // Tailwind class conflict resolution
115
+ const mergedClasses = cn(
116
+ 'p-4 text-sm', // base classes
117
+ 'p-6 text-lg' // these override the base classes intelligently
118
+ );
119
+ // Result: 'p-6 text-lg' (conflicts resolved)
120
+ ```
121
+
122
+ ### Common React Hooks
123
+
124
+ Nova Core provides several utility hooks for common Web3 UI patterns:
125
+
126
+ ```tsx
127
+ import { useCopyToClipboard } from '@tuwaio/nova-core';
128
+
129
+ function WalletAddress({ address }: { address: string }) {
130
+ const [copied, copy] = useCopyToClipboard();
131
+
132
+ return (
133
+ <div className={cn('transition-all', isCollapsed && 'w-12')}>
134
+ <button
135
+ onClick={() => copy(address)}
136
+ className="font-mono text-sm hover:bg-[var(--tuwa-bg-hover)]"
137
+ >
138
+ {address.slice(0, 6)}
139
+ {copied && ' ✓'}
140
+ </button>
141
+ </div>
142
+ );
143
+ }
144
+ ```
145
+
146
+ -----
147
+
148
+ ## 🛠️ Theme Customization
149
+
150
+ ### Basic Customization
151
+
152
+ Override design tokens in your CSS to match your brand:
153
+
154
+ ```css
155
+ /* src/styles/globals.css */
156
+ @import '@tuwaio/nova-core/dist/index.css';
157
+
158
+ /* Your custom theme overrides */
159
+ :root {
160
+ /* Brand Colors */
161
+ --tuwa-color-primary: #3b82f6; /* Blue-500 */
162
+ --tuwa-color-primary-hover: #2563eb; /* Blue-600 */
163
+
164
+ /* Background System */
165
+ --tuwa-bg-primary: #ffffff;
166
+ --tuwa-bg-secondary: #f8fafc;
167
+ --tuwa-bg-hover: #f1f5f9;
168
+
169
+ /* Text Colors */
170
+ --tuwa-text-primary: #0f172a;
171
+ --tuwa-text-secondary: #64748b;
172
+ --tuwa-text-muted: #94a3b8;
173
+
174
+ /* Border System */
175
+ --tuwa-border-primary: #e2e8f0;
176
+ --tuwa-border-secondary: #cbd5e1;
177
+ }
178
+ ```
179
+
180
+ ### Dark Mode Support
181
+
182
+ Nova Core includes built-in dark mode support:
183
+
184
+ ```css
185
+ /* Dark mode overrides */
186
+ .dark {
187
+ --tuwa-color-primary: #60a5fa; /* Blue-400 */
188
+ --tuwa-bg-primary: #0f172a; /* Slate-900 */
189
+ --tuwa-bg-secondary: #1e293b; /* Slate-800 */
190
+ --tuwa-text-primary: #f1f5f9; /* Slate-100 */
191
+ --tuwa-text-secondary: #cbd5e1; /* Slate-300 */
192
+ --tuwa-border-primary: #374151; /* Gray-700 */
193
+ }
194
+ ```
195
+
196
+ ### Advanced Usage
197
+
198
+ #### Component Integration
199
+
200
+ Nova Core works seamlessly with other Nova packages:
201
+
202
+ ```tsx
203
+ import { cn } from '@tuwaio/nova-core';
204
+ import { ConnectButton } from '@tuwaio/nova-connect/components';
205
+ import { NovaTransactionsProvider } from '@tuwaio/nova-transactions';
206
+
207
+ function App() {
208
+ return (
209
+ <div className={cn(
210
+ 'min-h-screen',
211
+ 'bg-[var(--tuwa-bg-primary)]',
212
+ 'text-[var(--tuwa-text-primary)]'
213
+ )}>
214
+ <NovaTransactionsProvider {...params} />
215
+ <header className="border-b border-[var(--tuwa-border-primary)]">
216
+ <ConnectButton />
217
+ </header>
218
+ <main>
219
+ {/* Your app content */}
220
+ </main>
221
+ </div>
222
+ );
223
+ }
224
+ ```
225
+
226
+ ### API Reference
227
+
228
+ #### Utilities
229
+
230
+ | Function | Description | Usage |
231
+ | :--- | :--- | :--- |
232
+ | **`cn(...classes)`** | Merges class names intelligently, resolving Tailwind conflicts | `cn('p-4 text-sm', 'p-6', conditional && 'hidden')` |
233
+
234
+ #### Hooks
235
+
236
+ | Hook | Description | Return Type |
237
+ | :--- | :--- | :--- |
238
+ | **`useCopyToClipboard()`** | Copy text to clipboard with feedback | `[boolean, (text: string) => void]` |
239
+ | **`useMediaQuery(query)`** | Responsive media query hook | `boolean` |
240
+
49
241
  ## 🤝 Contributing & Support
50
242
 
51
243
  Contributions are welcome! Please read our main **[Contribution Guidelines](https://github.com/TuwaIO/workflows/blob/main/CONTRIBUTING.md)**.
package/dist/index.cjs CHANGED
@@ -1,2 +1,49 @@
1
- 'use strict';var react=require('react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge');function w(e=2e3){let[o,t]=react.useState(false),[n,r]=react.useState(null),s=react.useCallback(async a=>{if(a)try{await navigator.clipboard.writeText(a),t(!0),r(null),setTimeout(()=>t(!1),e);}catch(c){let l=c instanceof Error?c:new Error("Failed to copy text.");console.error(l),r(l),setTimeout(()=>r(null),e);}},[e]);return {isCopied:o,copy:s,error:n}}function E(e){let o=r=>typeof window<"u"?window.matchMedia(r).matches:false,[t,n]=react.useState(o(e));return react.useEffect(()=>{let r=window.matchMedia(e),s=()=>n(r.matches);return s(),window.addEventListener("resize",s),()=>window.removeEventListener("resize",s)},[e]),t}function v(...e){return tailwindMerge.twMerge(clsx.clsx(e))}var i=e=>e&&typeof e=="object"&&!Array.isArray(e);function g(e,o){let t={...e};return i(e)&&i(o)&&Object.keys(o).forEach(n=>{let r=e[n],s=o[n];i(r)&&i(s)?t[n]=g(r,s):t[n]=s;}),t}function R(e,o,t){if(!e)return "";if(e.length<=o+t)return e;let n=e.slice(0,o),r=e.slice(e.length-t);return `${n}...${r}`}exports.cn=v;exports.deepMerge=g;exports.textCenterEllipsis=R;exports.useCopyToClipboard=w;exports.useMediaQuery=E;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var framerMotion=require('framer-motion'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime'),l=require('react'),r=require('@radix-ui/react-dialog');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var l__namespace=/*#__PURE__*/_interopNamespace(l);var r__namespace=/*#__PURE__*/_interopNamespace(r);var J="novacore:cursor-pointer novacore:rounded-md novacore:bg-[var(--tuwa-standart-button-bg)] novacore:px-3 novacore:py-2 novacore:flex novacore:items-center novacore:gap-1 novacore:text-sm novacore:font-semibold novacore:text-[var(--tuwa-text-primary)] novacore:transition-colors novacore:hover:bg-[var(--tuwa-standart-button-hover)] novacore:disabled:cursor-not-allowed novacore:disabled:opacity-50";function s(...o){return tailwindMerge.twMerge(clsx.clsx(o))}var m=o=>o&&typeof o=="object"&&!Array.isArray(o);function M(o,e){let a={...o};return m(o)&&m(e)&&Object.keys(e).forEach(n=>{let t=o[n],i=e[n];m(t)&&m(i)?a[n]=M(t,i):a[n]=i;}),a}function q(o=1200){if(typeof window>"u")return false;let e="ontouchstart"in window,a=navigator.maxTouchPoints>0,n=false;window.matchMedia&&(n=window.matchMedia("(pointer: coarse)").matches);let t=e||a||n,i=window.innerWidth<=o;return t&&i}function eo(o,e,a){if(!o)return "";if(o.length<=e+a)return o;let n=o.slice(0,e),t=o.slice(o.length-a);return `${n}...${t}`}function vo({className:o,strokeWidth:e,isOpen:a}){return jsxRuntime.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:e??2,stroke:"currentColor",className:s("novacore:w-4 novacore:h-4 novacore:text-[var(--tuwa-text-secondary)]",o),children:[jsxRuntime.jsx(framerMotion.AnimatePresence,{children:a&&jsxRuntime.jsx(framerMotion.motion.path,{strokeLinecap:"round",strokeLinejoin:"round",d:"m4.5 15.75 7.5-7.5 7.5 7.5",variants:{hidden:{translateY:3,scaleY:.8,opacity:0},visible:{translateY:0,scaleY:1,opacity:1}},initial:"hidden",animate:"visible",transition:{duration:.4}})}),jsxRuntime.jsx(framerMotion.AnimatePresence,{children:!a&&jsxRuntime.jsx(framerMotion.motion.path,{strokeLinecap:"round",strokeLinejoin:"round",d:"m19.5 8.25-7.5 7.5-7.5-7.5",className:"novacore:relative",variants:{hidden:{translateY:-3,scaleY:.8,opacity:0},visible:{translateY:0,scaleY:1,opacity:1}},initial:"hidden",animate:"visible",transition:{duration:.4}})})]})}var T=l__namespace.forwardRef(({className:o,...e},a)=>jsxRuntime.jsxs("svg",{ref:a,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:s("novacore:h-5 novacore:w-5 novacore:text-[var(--tuwa-text-primary)] novacore:transition-colors",o),...e,children:[jsxRuntime.jsx("path",{d:"M18 6 6 18"}),jsxRuntime.jsx("path",{d:"m6 6 12 12"})]}));T.displayName="CloseIcon";var ho=r__namespace.Root,Do=r__namespace.Trigger,A=r__namespace.Portal,No=r__namespace.Close,S={initial:{opacity:0,scale:.9,y:20},animate:{opacity:1,scale:1,y:0},exit:{opacity:0,scale:.9,transition:{duration:.2}}},L={initial:{opacity:0},animate:{opacity:1},exit:{opacity:0}},N=({className:o,backdropAnimation:e})=>(l__namespace.useEffect(()=>(typeof window<"u"&&window.document.body.classList.add("NovaModalOpen"),()=>{typeof window<"u"&&window.document.body.classList.remove("NovaModalOpen");}),[]),jsxRuntime.jsx(framerMotion.AnimatePresence,{children:jsxRuntime.jsx(framerMotion.motion.div,{variants:e??L,transition:{duration:.2,ease:"easeInOut"},animate:"animate",initial:"initial",exit:"exit",className:"novacore:relative novacore:rounded-t-2xl novacore:sm:rounded-2xl novacore:overflow-hidden",children:jsxRuntime.jsx("div",{className:s("novacore:fixed novacore:inset-0 novacore:z-50 novacore:bg-black/55 novacore:backdrop-blur-sm novacore:backdrop-saturate-150",o)})})}));N.displayName=r__namespace.Overlay.displayName;var V=l__namespace.forwardRef(({className:o,children:e,modalAnimation:a,backdropAnimation:n,...t},i)=>jsxRuntime.jsxs(A,{children:[jsxRuntime.jsx(N,{backdropAnimation:n}),jsxRuntime.jsx(r__namespace.Content,{"aria-describedby":"tuwa:modal-content",ref:i,className:s("NovaNoScrolling novacore:fixed novacore:bottom-0 novacore:left-0 novacore:p-0 novacore:sm:bottom-auto novacore:sm:left-[50%] novacore:sm:top-[50%] novacore:sm:translate-x-[-50%] novacore:sm:translate-y-[-50%] novacore:z-50 novacore:sm:p-4 novacore:outline-none",o),...t,children:jsxRuntime.jsx(framerMotion.motion.div,{layout:true,className:"NovaNoScrolling novacore:relative novacore:overflow-hidden",transition:{layout:{duration:.2,ease:[.1,.1,.2,1]}},children:jsxRuntime.jsx(framerMotion.AnimatePresence,{children:jsxRuntime.jsx(framerMotion.motion.div,{variants:a??S,transition:{duration:.2,ease:"easeInOut"},animate:"animate",initial:"initial",exit:"exit",className:"NovaNoScrolling novacore:relative novacore:rounded-t-2xl novacore:sm:rounded-2xl novacore:overflow-hidden",children:jsxRuntime.jsx("div",{className:s("NovaNoScrolling novacore:relative novacore:flex novacore:max-h-[98dvh] novacore:w-full novacore:flex-col novacore:gap-3 novacore:overflow-y-auto novacore:rounded-t-2xl novacore:sm:rounded-2xl novacore:shadow-2xl","novacore:border novacore:border-[var(--tuwa-border-primary)] novacore:bg-[var(--tuwa-bg-primary)]"),children:e})})})})})]}));V.displayName=r__namespace.Content.displayName;var W=({className:o,...e})=>jsxRuntime.jsx("div",{"aria-describedby":"tuwa:modal-header",className:s("novacore:sticky novacore:flex novacore:top-0 novacore:z-11 novacore:w-full novacore:flex-row novacore:items-center novacore:justify-between","novacore:border-b novacore:border-[var(--tuwa-border-primary)] novacore:bg-[var(--tuwa-bg-primary)] novacore:p-4",o),...e});W.displayName="DialogHeader";var B=({className:o,...e})=>jsxRuntime.jsx("div",{"aria-describedby":"tuwa:modal-footer",className:s("novacore:flex novacore:flex-col-reverse novacore:sm:flex-row novacore:sm:justify-end novacore:sm:space-x-2",o),...e});B.displayName="DialogFooter";var H=l__namespace.forwardRef(({className:o,...e},a)=>jsxRuntime.jsx(r__namespace.Title,{ref:a,"aria-describedby":"tuwa:modal-title",className:s("novacore:text-lg novacore:font-bold novacore:leading-none novacore:tracking-tight novacore:text-[var(--tuwa-text-primary)] novacore:m-0",o),...e}));H.displayName=r__namespace.Title.displayName;var O=l__namespace.forwardRef(({className:o,...e},a)=>jsxRuntime.jsx(r__namespace.Description,{"aria-describedby":"tuwa:modal-description",ref:a,className:s("novacore:text-sm novacore:text-[var(--tuwa-text-secondary)]",o),...e}));O.displayName=r__namespace.Description.displayName;function Mo({starsCount:o}){let[e,a]=l.useState(false);l.useEffect(()=>a(true),[]);let n=l.useMemo(()=>{if(!e)return [];let t=o??200;return Array.from({length:t}).map(()=>({x:Math.random()*window.innerWidth,y:Math.random()*window.innerHeight,r:Math.random()*1+.5,isSupernova:Math.random()<.1,delay:Math.random()*10,duration:5+Math.random()*5}))},[e]);return jsxRuntime.jsx("div",{className:"novacore:absolute novacore:inset-0 novacore:z-1 novacore:h-full novacore:w-full novacore:overflow-hidden",children:jsxRuntime.jsxs("svg",{width:"100%",height:"100%",xmlns:"http://www.w3.org/2000/svg",children:[jsxRuntime.jsx("defs",{children:jsxRuntime.jsx("style",{children:`
2
+ /* Pulse animation now includes scale for a more organic feel. */
3
+ @keyframes pulse {
4
+ 0%, 100% {
5
+ opacity: 0.2;
6
+ transform: scale(0.9);
7
+ }
8
+ 50% {
9
+ opacity: 0.8;
10
+ transform: scale(1.2);
11
+ }
12
+ }
13
+
14
+ /* Supernova animation remains impactful. */
15
+ @keyframes supernova {
16
+ 0% {
17
+ transform: scale(1);
18
+ stroke: rgba(var(--tuwa-bg-primary), 0.5);
19
+ opacity: 0.8;
20
+ }
21
+ 20% {
22
+ transform: scale(3);
23
+ stroke: var(--tuwa-button-gradient-from);
24
+ opacity: 1;
25
+ }
26
+ 100% {
27
+ transform: scale(0.8);
28
+ stroke: var(--tuwa-button-gradient-to);
29
+ opacity: 0;
30
+ }
31
+ }
32
+
33
+ .pulsar {
34
+ animation-name: pulse;
35
+ animation-timing-function: ease-in-out;
36
+ animation-iteration-count: infinite;
37
+ transform-origin: center;
38
+ }
39
+
40
+ .supernova {
41
+ animation-name: supernova;
42
+ animation-timing-function: ease-out;
43
+ animation-iteration-count: infinite;
44
+ transform-origin: center;
45
+ stroke-width: 2;
46
+ }
47
+ `})}),n.map((t,i)=>jsxRuntime.jsx("circle",{cx:t.x,cy:t.y,r:t.r,fill:"rgba(var(--tuwa-bg-primary), 0.7)",className:t.isSupernova?"supernova":"pulsar",style:{animationDelay:`${t.delay}s`,animationDuration:`${t.duration}s`}},i))]})})}function Ao({closeToast:o}){return jsxRuntime.jsx("button",{type:"button",onClick:o,"aria-label":"Close toast notification",title:"Close toast notification",className:s("novacore:absolute novacore:top-2 novacore:right-2 novacore:cursor-pointer novacore:rounded-full novacore:p-1","novacore:text-[var(--tuwa-text-tertiary)] novacore:transition-colors","novacore:hover:bg-[var(--tuwa-bg-muted)] novacore:hover:text-[var(--tuwa-text-primary)]"),children:jsxRuntime.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor",className:"novacore:h-5 novatx:w-5",children:jsxRuntime.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M6 18 18 6M6 6l12 12"})})})}function Wo(o=2e3){let[e,a]=l.useState(false),[n,t]=l.useState(null),i=l.useCallback(async f=>{if(f)try{await navigator.clipboard.writeText(f),a(!0),t(null),setTimeout(()=>a(!1),o);}catch(g){let w=g instanceof Error?g:new Error("Failed to copy text.");console.error(w),t(w),setTimeout(()=>t(null),o);}},[o]);return {isCopied:e,copy:i,error:n}}function Oo(o){let e=t=>typeof window<"u"?window.matchMedia(t).matches:false,[a,n]=l.useState(e(o));return l.useEffect(()=>{let t=window.matchMedia(o),i=()=>n(t.matches);return i(),window.addEventListener("resize",i),()=>window.removeEventListener("resize",i)},[o]),a}
48
+ exports.ChevronArrowWithAnim=vo;exports.CloseIcon=T;exports.Dialog=ho;exports.DialogClose=No;exports.DialogContent=V;exports.DialogDescription=O;exports.DialogFooter=B;exports.DialogHeader=W;exports.DialogOverlay=N;exports.DialogPortal=A;exports.DialogTitle=H;exports.DialogTrigger=Do;exports.StarsBackground=Mo;exports.ToastCloseButton=Ao;exports.cn=s;exports.deepMerge=M;exports.isTouchDevice=q;exports.standardButtonClasses=J;exports.textCenterEllipsis=eo;exports.useCopyToClipboard=Wo;exports.useMediaQuery=Oo;//# sourceMappingURL=index.cjs.map
2
49
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useCopyToClipboard.ts","../src/hooks/useMediaQuery.ts","../src/utils/cn.ts","../src/utils/deepMerge.ts","../src/utils/textCenterEllipsis.ts"],"names":["useCopyToClipboard","timeout","isCopied","setIsCopied","useState","error","setError","copy","useCallback","text","e","copyError","useMediaQuery","query","getMatches","q","matches","setMatches","useEffect","media","listener","cn","inputs","twMerge","clsx","isObject","item","deepMerge","target","source","output","key","targetValue","sourceValue","textCenterEllipsis","str","from","to","start","end"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @file This file contains a custom React hook for copying text to the clipboard.\n */\n\nimport { useCallback, useState } from 'react';\n\n/**\n * A custom React hook that provides functionality to copy text to the clipboard.\n * It also manages a \"copied\" state with a timeout for user feedback.\n *\n * @param {number} [timeout=2000] - The duration in milliseconds to keep the `isCopied` state as true.\n * @returns {{\n * isCopied: boolean;\n * copy: (text: string) => Promise<void>;\n * error: Error | null;\n * }} An object containing the `isCopied` state, the `copy` function, and any potential error.\n *\n * @example\n * const MyComponent = () => {\n * const { isCopied, copy } = useCopyToClipboard();\n * const textToCopy = '0x123...';\n *\n * return (\n * <button onClick={() => copy(textToCopy)}>\n * {isCopied ? 'Copied!' : 'Copy Address'}\n * </button>\n * );\n * }\n */\nexport function useCopyToClipboard(timeout = 2000): {\n isCopied: boolean;\n copy: (text: string) => Promise<void>;\n error: Error | null;\n} {\n const [isCopied, setIsCopied] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const copy = useCallback(\n async (text: string) => {\n if (!text) return;\n\n try {\n await navigator.clipboard.writeText(text);\n setIsCopied(true);\n setError(null);\n\n setTimeout(() => setIsCopied(false), timeout);\n } catch (e) {\n const copyError = e instanceof Error ? e : new Error('Failed to copy text.');\n console.error(copyError);\n setError(copyError);\n\n // Reset error state after timeout as well\n setTimeout(() => setError(null), timeout);\n }\n },\n [timeout],\n );\n\n return { isCopied, copy, error };\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * A custom hook to detect if a media query matches the current screen dimensions.\n * Handles SSR gracefully.\n * @param {string} query - The media query string (e.g., '(max-width: 767px)').\n * @returns {boolean} Whether the query matches or not.\n */\nexport function useMediaQuery(query: string): boolean {\n const getMatches = (q: string): boolean => {\n if (typeof window !== 'undefined') {\n return window.matchMedia(q).matches;\n }\n return false;\n };\n\n const [matches, setMatches] = useState<boolean>(getMatches(query));\n\n useEffect(() => {\n const media = window.matchMedia(query);\n const listener = () => setMatches(media.matches);\n\n // Re-check on mount and subscribe to changes\n listener();\n window.addEventListener('resize', listener);\n\n return () => window.removeEventListener('resize', listener);\n }, [query]);\n\n return matches;\n}\n","/**\n * @file This file contains a utility function for conditionally merging Tailwind CSS classes.\n */\n\nimport { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * A utility function to conditionally join class names together and resolve\n * conflicting Tailwind CSS classes.\n *\n * It combines the functionality of `clsx` and `tailwind-merge`.\n *\n * @param {...ClassValue[]} inputs - A list of class values to be combined.\n * This can include strings, numbers, objects, arrays, and booleans.\n * @returns {string} The final, merged class name string.\n *\n * @example\n * cn('p-4', 'bg-red-500', { 'font-bold': true }); // => 'p-4 bg-red-500 font-bold'\n * cn('p-2', 'p-4'); // => 'p-4' (tailwind-merge resolves the conflict)\n *\n * @see https://github.com/dcastil/tailwind-merge\n * @see https://github.com/lukeed/clsx\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * @file This file contains a utility for performing a deep (recursive) merge of two objects.\n */\n\n/**\n * Checks if the provided item is a plain object (i.e., not null and not an array).\n *\n * @param {any} item - The item to check.\n * @returns {item is Record<string, any>} True if the item is a plain object, otherwise false.\n */\nconst isObject = (item: any): item is Record<string, any> => {\n return item && typeof item === 'object' && !Array.isArray(item);\n};\n\n/**\n * Recursively merges the properties of a source object into a target object.\n * This function creates a new object and does not mutate the original target.\n *\n * @template T - The type of the objects being merged.\n * @param {T} target - The base object.\n * @param {Partial<T>} source - The object with properties to merge into the target.\n * @returns {T} A new object representing the merged result.\n *\n * @example\n * const defaults = { a: 1, b: { c: 2, d: 3 } };\n * const custom = { b: { c: 99 } };\n * const result = deepMerge(defaults, custom);\n * // result will be { a: 1, b: { c: 99, d: 3 } }\n */\nexport function deepMerge<T extends object>(target: T, source: Partial<T>): T {\n // Start with a shallow copy of the target to avoid mutation.\n const output = { ...target };\n\n if (isObject(target) && isObject(source)) {\n // Iterate over the keys in the source object.\n Object.keys(source).forEach((key) => {\n const targetValue = target[key as keyof T];\n const sourceValue = source[key as keyof T];\n\n // If the value is an object in both target and source, merge them recursively.\n if (isObject(targetValue) && isObject(sourceValue)) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n (output as Record<string, any>)[key] = deepMerge(targetValue, sourceValue);\n } else {\n // Otherwise, the source value overwrites the target value.\n (output as Record<string, any>)[key] = sourceValue;\n }\n });\n }\n\n return output;\n}\n","/**\n * @file This file contains a utility function for truncating a string with a center ellipsis.\n */\n\n/**\n * Truncates a string by showing a specified number of characters from the start and end,\n * with an ellipsis in the middle. If the string is too short to be truncated, it's returned as is.\n *\n * @param {string} str - The string to truncate.\n * @param {number} from - The number of characters to show from the beginning of the string.\n * @param {number} to - The number of characters to show from the end of the string.\n * @returns {string} The truncated string, or the original string if it's too short.\n *\n * @example\n * const hash = '0x1234567890abcdef1234567890abcdef';\n * textCenterEllipsis(hash, 6, 4); // => \"0x1234...cdef\"\n *\n * textCenterEllipsis('short', 6, 4); // => \"short\"\n */\nexport function textCenterEllipsis(str: string | undefined | null, from: number, to: number): string {\n if (!str) {\n return '';\n }\n\n // If the string is short enough, don't truncate it.\n if (str.length <= from + to) {\n return str;\n }\n\n const start = str.slice(0, from);\n const end = str.slice(str.length - to);\n\n return `${start}...${end}`;\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/classes.ts","../src/utils/cn.ts","../src/utils/deepMerge.ts","../src/utils/isTouchDevice.ts","../src/utils/textCenterEllipsis.ts","../src/components/ChevronArrowWithAnim.tsx","../src/components/CloseIcon.tsx","../src/components/Modal.tsx","../src/components/StarsBackground.tsx","../src/components/ToastCloseButton.tsx","../src/hooks/useCopyToClipboard.ts","../src/hooks/useMediaQuery.ts"],"names":["standardButtonClasses","cn","inputs","twMerge","clsx","isObject","item","deepMerge","target","source","output","key","targetValue","sourceValue","isTouchDevice","maxWidth","hasTouchStart","hasMaxTouchPoints","hasCoarsePointer","supportsTouch","isSmallScreen","textCenterEllipsis","str","from","to","start","end","ChevronArrowWithAnim","className","strokeWidth","isOpen","jsxs","jsx","AnimatePresence","motion","CloseIcon","h","props","ref","Dialog","r","DialogTrigger","DialogPortal","DialogClose","defaultModalAnimation","defaultModalBackdropAnimation","DialogOverlay","backdropAnimation","l","DialogContent","children","modalAnimation","DialogHeader","DialogFooter","DialogTitle","DialogDescription","StarsBackground","starsCount","isMounted","setIsMounted","useState","useEffect","stars","useMemo","numStars","star","ToastCloseButton","closeToast","useCopyToClipboard","timeout","isCopied","setIsCopied","error","setError","copy","useCallback","text","e","copyError","useMediaQuery","query","getMatches","q","matches","setMatches","media","listener"],"mappings":"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","file":"index.cjs","sourcesContent":["export const standardButtonClasses =\n 'novacore:cursor-pointer novacore:rounded-md novacore:bg-[var(--tuwa-standart-button-bg)] novacore:px-3 novacore:py-2 novacore:flex novacore:items-center novacore:gap-1 novacore:text-sm novacore:font-semibold novacore:text-[var(--tuwa-text-primary)] novacore:transition-colors novacore:hover:bg-[var(--tuwa-standart-button-hover)] novacore:disabled:cursor-not-allowed novacore:disabled:opacity-50';\n","/**\n * @file This file contains a utility function for conditionally merging Tailwind CSS classes.\n */\n\nimport { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * A utility function to conditionally join class names together and resolve\n * conflicting Tailwind CSS classes.\n *\n * It combines the functionality of `clsx` and `tailwind-merge`.\n *\n * @param {...ClassValue[]} inputs - A list of class values to be combined.\n * This can include strings, numbers, objects, arrays, and booleans.\n * @returns {string} The final, merged class name string.\n *\n * @example\n * cn('p-4', 'bg-red-500', { 'font-bold': true }); // => 'p-4 bg-red-500 font-bold'\n * cn('p-2', 'p-4'); // => 'p-4' (tailwind-merge resolves the conflict)\n *\n * @see https://github.com/dcastil/tailwind-merge\n * @see https://github.com/lukeed/clsx\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * @file This file contains a utility for performing a deep (recursive) merge of two objects.\n */\n\n/**\n * Checks if the provided item is a plain object (i.e., not null and not an array).\n *\n * @param {any} item - The item to check.\n * @returns {item is Record<string, any>} True if the item is a plain object, otherwise false.\n */\nconst isObject = (item: any): item is Record<string, any> => {\n return item && typeof item === 'object' && !Array.isArray(item);\n};\n\n/**\n * Recursively merges the properties of a source object into a target object.\n * This function creates a new object and does not mutate the original target.\n *\n * @template T - The type of the objects being merged.\n * @param {T} target - The base object.\n * @param {Partial<T>} source - The object with properties to merge into the target.\n * @returns {T} A new object representing the merged result.\n *\n * @example\n * const defaults = { a: 1, b: { c: 2, d: 3 } };\n * const custom = { b: { c: 99 } };\n * const result = deepMerge(defaults, custom);\n * // result will be { a: 1, b: { c: 99, d: 3 } }\n */\nexport function deepMerge<T extends object>(target: T, source: Partial<T>): T {\n // Start with a shallow copy of the target to avoid mutation.\n const output = { ...target };\n\n if (isObject(target) && isObject(source)) {\n // Iterate over the keys in the source object.\n Object.keys(source).forEach((key) => {\n const targetValue = target[key as keyof T];\n const sourceValue = source[key as keyof T];\n\n // If the value is an object in both target and source, merge them recursively.\n if (isObject(targetValue) && isObject(sourceValue)) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n (output as Record<string, any>)[key] = deepMerge(targetValue, sourceValue);\n } else {\n // Otherwise, the source value overwrites the target value.\n (output as Record<string, any>)[key] = sourceValue;\n }\n });\n }\n\n return output;\n}\n","/**\n * @fileoverview Utility function to determine if the current environment supports touch input.\n * This is safe to use in Next.js applications as it checks for the `window` object existence.\n */\n\n/**\n * Determines if the current browsing device supports touch input,\n * while also excluding large screens (typically desktop-sized touch monitors).\n *\n * It checks for:\n * 1. The presence of 'ontouchstart' or navigator.maxTouchPoints > 0 or '(pointer: coarse)'.\n * 2. ONLY returns true if the screen width is less than or equal to the specified threshold (e.g., 1200px).\n *\n * This function is safe for server-side rendering (SSR) environments like Next.js.\n *\n * @param {number} [maxWidth=1200] The maximum screen width (in pixels) for a device to be considered 'touch' (default is 1200).\n * @returns {boolean} Returns true if the environment is determined to support touch input AND is within the width limit, otherwise false.\n */\nexport function isTouchDevice(maxWidth: number = 1200): boolean {\n // 1. Check if we are running in a browser environment (Client Side).\n if (typeof window === 'undefined') {\n // If not in a browser (SSR), we assume no touch support for safety.\n return false;\n }\n\n // --- Core Touch Support Checks (Client Side Only) ---\n\n // A. Check for 'ontouchstart' event property (classic check).\n const hasTouchStart = 'ontouchstart' in window;\n\n // B. Check for maxTouchPoints (reliable modern check).\n const hasMaxTouchPoints = navigator.maxTouchPoints > 0;\n\n // C. Check for 'pointer: coarse' media query (detects \"rough\" pointer like a finger).\n let hasCoarsePointer = false;\n if (window.matchMedia) {\n hasCoarsePointer = window.matchMedia('(pointer: coarse)').matches;\n }\n\n // Determine if the device inherently supports touch input.\n const supportsTouch = hasTouchStart || hasMaxTouchPoints || hasCoarsePointer;\n\n // 2. Check the screen size condition.\n // The device must support touch AND its current width must be less than or equal to the defined maxWidth.\n const isSmallScreen = window.innerWidth <= maxWidth;\n\n // Return true only if both conditions are met.\n return supportsTouch && isSmallScreen;\n}\n","/**\n * @file This file contains a utility function for truncating a string with a center ellipsis.\n */\n\n/**\n * Truncates a string by showing a specified number of characters from the start and end,\n * with an ellipsis in the middle. If the string is too short to be truncated, it's returned as is.\n *\n * @param {string} str - The string to truncate.\n * @param {number} from - The number of characters to show from the beginning of the string.\n * @param {number} to - The number of characters to show from the end of the string.\n * @returns {string} The truncated string, or the original string if it's too short.\n *\n * @example\n * const hash = '0x1234567890abcdef1234567890abcdef';\n * textCenterEllipsis(hash, 6, 4); // => \"0x1234...cdef\"\n *\n * textCenterEllipsis('short', 6, 4); // => \"short\"\n */\nexport function textCenterEllipsis(str: string | undefined | null, from: number, to: number): string {\n if (!str) {\n return '';\n }\n\n // If the string is short enough, don't truncate it.\n if (str.length <= from + to) {\n return str;\n }\n\n const start = str.slice(0, from);\n const end = str.slice(str.length - to);\n\n return `${start}...${end}`;\n}\n","import { AnimatePresence, motion } from 'framer-motion';\n\nimport { cn } from '../utils';\n\nexport function ChevronArrowWithAnim({\n className,\n strokeWidth,\n isOpen,\n}: {\n className?: string;\n strokeWidth?: number;\n isOpen?: boolean;\n}) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={strokeWidth ?? 2}\n stroke=\"currentColor\"\n className={cn('novacore:w-4 novacore:h-4 novacore:text-[var(--tuwa-text-secondary)]', className)}\n >\n <AnimatePresence>\n {isOpen && (\n <motion.path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m4.5 15.75 7.5-7.5 7.5 7.5\"\n variants={{\n hidden: { translateY: 3, scaleY: 0.8, opacity: 0 },\n visible: { translateY: 0, scaleY: 1, opacity: 1 },\n }}\n initial=\"hidden\"\n animate=\"visible\"\n transition={{ duration: 0.4 }}\n />\n )}\n </AnimatePresence>\n\n <AnimatePresence>\n {!isOpen && (\n <motion.path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m19.5 8.25-7.5 7.5-7.5-7.5\"\n className=\"novacore:relative\"\n variants={{\n hidden: { translateY: -3, scaleY: 0.8, opacity: 0 },\n visible: { translateY: 0, scaleY: 1, opacity: 1 },\n }}\n initial=\"hidden\"\n animate=\"visible\"\n transition={{ duration: 0.4 }}\n />\n )}\n </AnimatePresence>\n </svg>\n );\n}\n","import * as React from 'react';\n\nimport { cn } from '../utils';\n\n/**\n * A reusable close button icon (X mark) styled with TUWA color scheme.\n */\nexport const CloseIcon = React.forwardRef<SVGSVGElement, React.SVGAttributes<SVGSVGElement>>(\n ({ className, ...props }, ref) => (\n <svg\n ref={ref}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(\n 'novacore:h-5 novacore:w-5 novacore:text-[var(--tuwa-text-primary)] novacore:transition-colors',\n className,\n )}\n {...props}\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n ),\n);\nCloseIcon.displayName = 'CloseIcon';\n","import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { AnimatePresence, motion, Variants } from 'framer-motion';\nimport * as React from 'react';\n\nimport { cn } from '../utils';\n\nconst Dialog = DialogPrimitive.Root;\nconst DialogTrigger = DialogPrimitive.Trigger;\nconst DialogPortal = DialogPrimitive.Portal;\nconst DialogClose = DialogPrimitive.Close;\n\nconst defaultModalAnimation: Variants = {\n initial: { opacity: 0, scale: 0.9, y: 20 },\n animate: { opacity: 1, scale: 1, y: 0 },\n exit: {\n opacity: 0,\n scale: 0.9,\n transition: {\n duration: 0.2,\n },\n },\n};\n\nconst defaultModalBackdropAnimation: Variants = {\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n exit: { opacity: 0 },\n};\n\nconst DialogOverlay = ({ className, backdropAnimation }: { backdropAnimation?: Variants; className?: string }) => {\n React.useEffect(() => {\n if (typeof window !== 'undefined') {\n window.document.body.classList.add('NovaModalOpen');\n }\n return () => {\n if (typeof window !== 'undefined') {\n window.document.body.classList.remove('NovaModalOpen');\n }\n };\n }, []);\n return (\n <AnimatePresence>\n <motion.div\n variants={backdropAnimation ?? defaultModalBackdropAnimation}\n transition={{ duration: 0.2, ease: 'easeInOut' }}\n animate=\"animate\"\n initial=\"initial\"\n exit=\"exit\"\n className=\"novacore:relative novacore:rounded-t-2xl novacore:sm:rounded-2xl novacore:overflow-hidden\"\n >\n <div\n className={cn(\n 'novacore:fixed novacore:inset-0 novacore:z-50 novacore:bg-black/55 novacore:backdrop-blur-sm novacore:backdrop-saturate-150',\n className,\n )}\n />\n </motion.div>\n </AnimatePresence>\n );\n};\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName;\n\nconst DialogContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n modalAnimation?: Variants;\n backdropAnimation?: Variants;\n }\n>(({ className, children, modalAnimation, backdropAnimation, ...props }, ref) => (\n <DialogPortal>\n <DialogOverlay backdropAnimation={backdropAnimation} />\n\n <DialogPrimitive.Content\n aria-describedby=\"tuwa:modal-content\"\n ref={ref}\n className={cn(\n 'NovaNoScrolling novacore:fixed novacore:bottom-0 novacore:left-0 novacore:p-0 novacore:sm:bottom-auto novacore:sm:left-[50%] novacore:sm:top-[50%] novacore:sm:translate-x-[-50%] novacore:sm:translate-y-[-50%] novacore:z-50 novacore:sm:p-4 novacore:outline-none',\n className,\n )}\n {...props}\n >\n <motion.div\n layout\n className=\"NovaNoScrolling novacore:relative novacore:overflow-hidden\"\n transition={{\n layout: {\n duration: 0.2,\n ease: [0.1, 0.1, 0.2, 1],\n },\n }}\n >\n <AnimatePresence>\n <motion.div\n variants={modalAnimation ?? defaultModalAnimation}\n transition={{ duration: 0.2, ease: 'easeInOut' }}\n animate=\"animate\"\n initial=\"initial\"\n exit=\"exit\"\n className=\"NovaNoScrolling novacore:relative novacore:rounded-t-2xl novacore:sm:rounded-2xl novacore:overflow-hidden\"\n >\n <div\n className={cn(\n 'NovaNoScrolling novacore:relative novacore:flex novacore:max-h-[98dvh] novacore:w-full novacore:flex-col novacore:gap-3 novacore:overflow-y-auto novacore:rounded-t-2xl novacore:sm:rounded-2xl novacore:shadow-2xl',\n 'novacore:border novacore:border-[var(--tuwa-border-primary)] novacore:bg-[var(--tuwa-bg-primary)]',\n )}\n >\n {children}\n </div>\n </motion.div>\n </AnimatePresence>\n </motion.div>\n </DialogPrimitive.Content>\n </DialogPortal>\n));\nDialogContent.displayName = DialogPrimitive.Content.displayName;\n\nconst DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n aria-describedby=\"tuwa:modal-header\"\n className={cn(\n 'novacore:sticky novacore:flex novacore:top-0 novacore:z-11 novacore:w-full novacore:flex-row novacore:items-center novacore:justify-between',\n 'novacore:border-b novacore:border-[var(--tuwa-border-primary)] novacore:bg-[var(--tuwa-bg-primary)] novacore:p-4',\n className,\n )}\n {...props}\n />\n);\nDialogHeader.displayName = 'DialogHeader';\n\nconst DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n aria-describedby=\"tuwa:modal-footer\"\n className={cn(\n 'novacore:flex novacore:flex-col-reverse novacore:sm:flex-row novacore:sm:justify-end novacore:sm:space-x-2',\n className,\n )}\n {...props}\n />\n);\nDialogFooter.displayName = 'DialogFooter';\n\nconst DialogTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n aria-describedby=\"tuwa:modal-title\"\n className={cn(\n 'novacore:text-lg novacore:font-bold novacore:leading-none novacore:tracking-tight novacore:text-[var(--tuwa-text-primary)] novacore:m-0',\n className,\n )}\n {...props}\n />\n));\nDialogTitle.displayName = DialogPrimitive.Title.displayName;\n\nconst DialogDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n aria-describedby=\"tuwa:modal-description\"\n ref={ref}\n className={cn('novacore:text-sm novacore:text-[var(--tuwa-text-secondary)]', className)}\n {...props}\n />\n));\nDialogDescription.displayName = DialogPrimitive.Description.displayName;\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n","import { useEffect, useMemo, useState } from 'react';\n\nexport function StarsBackground({ starsCount }: { starsCount?: number }) {\n const [isMounted, setIsMounted] = useState(false);\n useEffect(() => setIsMounted(true), []);\n\n const stars = useMemo(() => {\n if (!isMounted) {\n return [];\n }\n\n const numStars = starsCount ?? 200;\n return Array.from({ length: numStars }).map(() => ({\n x: Math.random() * window.innerWidth,\n y: Math.random() * window.innerHeight,\n r: Math.random() * 1 + 0.5,\n isSupernova: Math.random() < 0.1,\n delay: Math.random() * 10,\n duration: 5 + Math.random() * 5,\n }));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isMounted]);\n\n return (\n <div className=\"novacore:absolute novacore:inset-0 novacore:z-1 novacore:h-full novacore:w-full novacore:overflow-hidden\">\n <svg width=\"100%\" height=\"100%\" xmlns=\"http://www.w3.org/2000/svg\">\n <defs>\n <style>\n {`\n /* Pulse animation now includes scale for a more organic feel. */\n @keyframes pulse {\n 0%, 100% { \n opacity: 0.2;\n transform: scale(0.9);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.2);\n }\n }\n \n /* Supernova animation remains impactful. */\n @keyframes supernova {\n 0% { \n transform: scale(1);\n stroke: rgba(var(--tuwa-bg-primary), 0.5);\n opacity: 0.8;\n }\n 20% { \n transform: scale(3);\n stroke: var(--tuwa-button-gradient-from);\n opacity: 1;\n }\n 100% { \n transform: scale(0.8);\n stroke: var(--tuwa-button-gradient-to);\n opacity: 0;\n }\n }\n\n .pulsar {\n animation-name: pulse;\n animation-timing-function: ease-in-out;\n animation-iteration-count: infinite;\n transform-origin: center;\n }\n\n .supernova {\n animation-name: supernova;\n animation-timing-function: ease-out;\n animation-iteration-count: infinite;\n transform-origin: center;\n stroke-width: 2;\n }\n `}\n </style>\n </defs>\n\n {stars.map((star, i) => (\n <circle\n key={i}\n cx={star.x}\n cy={star.y}\n r={star.r}\n fill={`rgba(var(--tuwa-bg-primary), 0.7)`}\n className={star.isSupernova ? 'supernova' : 'pulsar'}\n style={{\n animationDelay: `${star.delay}s`,\n animationDuration: `${star.duration}s`,\n }}\n />\n ))}\n </svg>\n </div>\n );\n}\n","/**\n * @file This file contains a reusable close button component, designed primarily for toast notifications.\n */\n\nimport { cn } from '../utils';\n\n/**\n * Defines the props for the ToastCloseButton component.\n */\nexport type ToastCloseButtonProps = {\n /**\n * The function to call when the button is clicked. This is typically provided by the\n * toast library (e.g., react-toastify) to dismiss the notification.\n */\n closeToast?: (e: React.MouseEvent<HTMLElement>) => void;\n};\n\n/**\n * A simple, styled close button component ('X' icon) intended for use within toast notifications.\n * It uses theme-aware CSS variables for styling and i18n labels for accessibility.\n */\nexport function ToastCloseButton({ closeToast }: ToastCloseButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={closeToast}\n aria-label=\"Close toast notification\"\n title=\"Close toast notification\"\n className={cn(\n 'novacore:absolute novacore:top-2 novacore:right-2 novacore:cursor-pointer novacore:rounded-full novacore:p-1',\n 'novacore:text-[var(--tuwa-text-tertiary)] novacore:transition-colors',\n 'novacore:hover:bg-[var(--tuwa-bg-muted)] novacore:hover:text-[var(--tuwa-text-primary)]',\n )}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"novacore:h-5 novatx:w-5\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" />\n </svg>\n </button>\n );\n}\n","/**\n * @file This file contains a custom React hook for copying text to the clipboard.\n */\n\nimport { useCallback, useState } from 'react';\n\n/**\n * A custom React hook that provides functionality to copy text to the clipboard.\n * It also manages a \"copied\" state with a timeout for user feedback.\n *\n * @param {number} [timeout=2000] - The duration in milliseconds to keep the `isCopied` state as true.\n * @returns {{\n * isCopied: boolean;\n * copy: (text: string) => Promise<void>;\n * error: Error | null;\n * }} An object containing the `isCopied` state, the `copy` function, and any potential error.\n *\n * @example\n * const MyComponent = () => {\n * const { isCopied, copy } = useCopyToClipboard();\n * const textToCopy = '0x123...';\n *\n * return (\n * <button onClick={() => copy(textToCopy)}>\n * {isCopied ? 'Copied!' : 'Copy Address'}\n * </button>\n * );\n * }\n */\nexport function useCopyToClipboard(timeout = 2000): {\n isCopied: boolean;\n copy: (text: string) => Promise<void>;\n error: Error | null;\n} {\n const [isCopied, setIsCopied] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const copy = useCallback(\n async (text: string) => {\n if (!text) return;\n\n try {\n await navigator.clipboard.writeText(text);\n setIsCopied(true);\n setError(null);\n\n setTimeout(() => setIsCopied(false), timeout);\n } catch (e) {\n const copyError = e instanceof Error ? e : new Error('Failed to copy text.');\n console.error(copyError);\n setError(copyError);\n\n // Reset error state after timeout as well\n setTimeout(() => setError(null), timeout);\n }\n },\n [timeout],\n );\n\n return { isCopied, copy, error };\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * A custom hook to detect if a media query matches the current screen dimensions.\n * Handles SSR gracefully.\n * @param {string} query - The media query string (e.g., '(max-width: 767px)').\n * @returns {boolean} Whether the query matches or not.\n */\nexport function useMediaQuery(query: string): boolean {\n const getMatches = (q: string): boolean => {\n if (typeof window !== 'undefined') {\n return window.matchMedia(q).matches;\n }\n return false;\n };\n\n const [matches, setMatches] = useState<boolean>(getMatches(query));\n\n useEffect(() => {\n const media = window.matchMedia(query);\n const listener = () => setMatches(media.matches);\n\n // Re-check on mount and subscribe to changes\n listener();\n window.addEventListener('resize', listener);\n\n return () => window.removeEventListener('resize', listener);\n }, [query]);\n\n return matches;\n}\n"]}