@thenamespace/ens-components 0.10.0 → 0.12.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.
- package/README.md +436 -135
- package/dist/index.d.ts +6 -2
- package/dist/index.js +39546 -38785
- package/dist/index.js.map +1 -1
- package/dist/types/components/subname-onchain-registrar-modal/SubnameOnChainRegistrarModal.d.ts +2 -1
- package/dist/types/components/subname-onchain-registrar-modal/sub-components/InitialStep.d.ts +2 -1
- package/dist/types/components/subname-onchain-registrar-modal/sub-components/RegistrationStep.d.ts +9 -4
- package/dist/types/context/profile-filter.context.d.ts +19 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/numbers.d.ts +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,209 +1,510 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @thenamespace/ens-components
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React components for ENS (Ethereum Name Service) name registration and subname minting.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @thenamespace/ens-components
|
|
9
|
+
```
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
- 📱 **Responsive** - Mobile-first design approach
|
|
9
|
-
- 🌙 **Dark/Light Theme** - Built-in theme support
|
|
10
|
-
- 🎯 **TypeScript** - Full type safety and IntelliSense
|
|
11
|
-
- 📦 **Tree-shakable** - Import only what you need
|
|
12
|
-
- 🎭 **Storybook** - Interactive component documentation
|
|
13
|
-
- ⚡ **Performance** - Optimized for production use
|
|
11
|
+
## Peer Dependencies
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
This package requires the following peer dependencies:
|
|
16
14
|
|
|
17
15
|
```bash
|
|
18
|
-
npm install @
|
|
19
|
-
# or
|
|
20
|
-
yarn add @arti/ui-components
|
|
21
|
-
# or
|
|
22
|
-
pnpm add @arti/ui-components
|
|
16
|
+
npm install wagmi @rainbow-me/rainbowkit @tanstack/react-query viem react react-dom
|
|
23
17
|
```
|
|
24
18
|
|
|
25
19
|
## Quick Start
|
|
26
20
|
|
|
27
|
-
### 1.
|
|
21
|
+
### 1. Setup Required Providers
|
|
22
|
+
|
|
23
|
+
Wrap your application with the required providers:
|
|
28
24
|
|
|
29
25
|
```tsx
|
|
30
|
-
|
|
31
|
-
import "
|
|
26
|
+
import React from "react";
|
|
27
|
+
import { WagmiProvider } from "wagmi";
|
|
28
|
+
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
|
|
29
|
+
import { RainbowKitProvider, getDefaultConfig } from "@rainbow-me/rainbowkit";
|
|
30
|
+
import { mainnet, sepolia } from "wagmi/chains";
|
|
31
|
+
import { http } from "wagmi";
|
|
32
|
+
|
|
33
|
+
// Import styles
|
|
34
|
+
import "@thenamespace/ens-components/index.css";
|
|
35
|
+
import "@rainbow-me/rainbowkit/styles.css";
|
|
36
|
+
|
|
37
|
+
const wagmiConfig = getDefaultConfig({
|
|
38
|
+
appName: "My ENS App",
|
|
39
|
+
projectId: "YOUR_WALLETCONNECT_PROJECT_ID", // Get from https://cloud.walletconnect.com
|
|
40
|
+
chains: [mainnet, sepolia],
|
|
41
|
+
transports: {
|
|
42
|
+
[mainnet.id]: http(),
|
|
43
|
+
[sepolia.id]: http(),
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const queryClient = new QueryClient();
|
|
48
|
+
|
|
49
|
+
function AppProviders({ children }: { children: React.ReactNode }) {
|
|
50
|
+
return (
|
|
51
|
+
<WagmiProvider config={wagmiConfig}>
|
|
52
|
+
<QueryClientProvider client={queryClient}>
|
|
53
|
+
<RainbowKitProvider>
|
|
54
|
+
{children}
|
|
55
|
+
</RainbowKitProvider>
|
|
56
|
+
</QueryClientProvider>
|
|
57
|
+
</WagmiProvider>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
32
60
|
```
|
|
33
61
|
|
|
34
|
-
### 2.
|
|
62
|
+
### 2. Use the Components
|
|
35
63
|
|
|
36
64
|
```tsx
|
|
37
|
-
import {
|
|
65
|
+
import { ENSNamesRegistrarComponent, SubnameOnChainRegistrarModal } from "@thenamespace/ens-components";
|
|
38
66
|
|
|
39
|
-
function
|
|
67
|
+
function MyApp() {
|
|
40
68
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
</
|
|
69
|
+
<AppProviders>
|
|
70
|
+
{/* Your components here */}
|
|
71
|
+
</AppProviders>
|
|
44
72
|
);
|
|
45
73
|
}
|
|
46
74
|
```
|
|
47
75
|
|
|
48
|
-
|
|
76
|
+
## Components
|
|
77
|
+
|
|
78
|
+
### ENSNamesRegistrarComponent
|
|
79
|
+
|
|
80
|
+
Component for registering top-level ENS names (e.g., `myname.eth`).
|
|
81
|
+
|
|
82
|
+
#### Basic Usage
|
|
49
83
|
|
|
50
84
|
```tsx
|
|
51
|
-
import {
|
|
85
|
+
import { useState } from "react";
|
|
86
|
+
import { ENSNamesRegistrarComponent } from "@thenamespace/ens-components";
|
|
87
|
+
|
|
88
|
+
function RegisterENSName() {
|
|
89
|
+
const [name, setName] = useState("");
|
|
90
|
+
const [duration, setDuration] = useState(1);
|
|
52
91
|
|
|
53
|
-
function MyComponent() {
|
|
54
92
|
return (
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<Button>Hover me</Button>
|
|
65
|
-
</Tooltip>
|
|
66
|
-
</div>
|
|
93
|
+
<ENSNamesRegistrarComponent
|
|
94
|
+
name={name}
|
|
95
|
+
duration={duration}
|
|
96
|
+
onNameChange={setName}
|
|
97
|
+
onDurationChange={setDuration}
|
|
98
|
+
onCompleteRegistration={() => {
|
|
99
|
+
console.log("Registration complete!");
|
|
100
|
+
}}
|
|
101
|
+
/>
|
|
67
102
|
);
|
|
68
103
|
}
|
|
69
104
|
```
|
|
70
105
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
### Atoms
|
|
74
|
-
|
|
75
|
-
- **Button** - Interactive button with variants and icons
|
|
76
|
-
- **Input** - Form input with prefix/suffix support
|
|
77
|
-
- **Text** - Typography component with size and weight options
|
|
78
|
-
- **Icon** - Icon component with Lucide React icons
|
|
79
|
-
- **ChainIcon** - Blockchain network icons
|
|
80
|
-
- **Tooltip** - Contextual tooltip component
|
|
106
|
+
#### Component Flow
|
|
81
107
|
|
|
82
|
-
|
|
108
|
+
The component has 4 main steps:
|
|
83
109
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
110
|
+
1. **NameSearch** - User searches for an available ENS name
|
|
111
|
+
2. **RegistrationForm** - User reviews details and sets registration duration
|
|
112
|
+
3. **RegistrationProcess** - Transaction processing with multiple steps
|
|
113
|
+
4. **SuccessScreen** - Registration completion confirmation
|
|
87
114
|
|
|
88
|
-
|
|
115
|
+
#### Props
|
|
89
116
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
117
|
+
| Prop | Type | Required | Default | Description |
|
|
118
|
+
|------|------|----------|---------|-------------|
|
|
119
|
+
| `name` | `string` | No | `"brightwave"` | Initial ENS name (without .eth suffix) |
|
|
120
|
+
| `duration` | `number` | No | `1` | Registration duration in years |
|
|
121
|
+
| `onNameChange` | `(name: string) => void` | No | - | Callback when name changes |
|
|
122
|
+
| `onDurationChange` | `(duration: number) => void` | No | - | Callback when duration changes |
|
|
123
|
+
| `onBack` | `() => void` | No | - | Callback when back button is clicked |
|
|
124
|
+
| `onClose` | `() => void` | No | - | Callback when close button is clicked |
|
|
125
|
+
| `onNext` | `() => void` | No | - | Callback when next button is clicked |
|
|
126
|
+
| `onCompleteProfile` | `() => void` | No | - | Callback when "Complete Profile" is clicked |
|
|
127
|
+
| `onOpenWallet` | `() => void` | No | - | Callback when wallet needs to be opened |
|
|
128
|
+
| `onCompleteRegistration` | `() => void` | No | - | Callback when registration completes |
|
|
129
|
+
| `onRegisterAnother` | `() => void` | No | - | Callback when "Register Another" is clicked |
|
|
130
|
+
| `onViewName` | `() => void` | No | - | Callback when "View Name" is clicked |
|
|
93
131
|
|
|
94
|
-
|
|
132
|
+
#### Complete Example
|
|
95
133
|
|
|
96
134
|
```tsx
|
|
97
|
-
import {
|
|
98
|
-
|
|
99
|
-
useWaitForTransaction,
|
|
100
|
-
useWeb3Clients,
|
|
101
|
-
} from "@arti/ui-components";
|
|
135
|
+
import { useState } from "react";
|
|
136
|
+
import { ENSNamesRegistrarComponent } from "@thenamespace/ens-components";
|
|
102
137
|
|
|
103
|
-
function
|
|
104
|
-
const
|
|
105
|
-
const
|
|
138
|
+
function ENSRegistrationExample() {
|
|
139
|
+
const [name, setName] = useState("");
|
|
140
|
+
const [duration, setDuration] = useState(1);
|
|
141
|
+
const [registeredNames, setRegisteredNames] = useState<string[]>([]);
|
|
142
|
+
|
|
143
|
+
const handleCompleteRegistration = () => {
|
|
144
|
+
if (name) {
|
|
145
|
+
setRegisteredNames([...registeredNames, name]);
|
|
146
|
+
alert(`Successfully registered ${name}.eth!`);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
106
149
|
|
|
107
150
|
return (
|
|
108
151
|
<div>
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
152
|
+
<ENSNamesRegistrarComponent
|
|
153
|
+
name={name}
|
|
154
|
+
duration={duration}
|
|
155
|
+
onNameChange={setName}
|
|
156
|
+
onDurationChange={setDuration}
|
|
157
|
+
onBack={() => console.log("Back clicked")}
|
|
158
|
+
onClose={() => console.log("Close clicked")}
|
|
159
|
+
onNext={() => console.log("Next clicked")}
|
|
160
|
+
onCompleteProfile={() => {
|
|
161
|
+
console.log("Complete profile clicked");
|
|
162
|
+
// Navigate to profile completion page
|
|
163
|
+
}}
|
|
164
|
+
onOpenWallet={() => console.log("Open wallet clicked")}
|
|
165
|
+
onCompleteRegistration={handleCompleteRegistration}
|
|
166
|
+
onRegisterAnother={() => {
|
|
167
|
+
setName("");
|
|
168
|
+
setDuration(1);
|
|
169
|
+
}}
|
|
170
|
+
onViewName={() => {
|
|
171
|
+
if (name) {
|
|
172
|
+
window.open(`https://app.ens.domains/${name}`, "_blank");
|
|
173
|
+
}
|
|
174
|
+
}}
|
|
175
|
+
/>
|
|
176
|
+
|
|
177
|
+
{registeredNames.length > 0 && (
|
|
178
|
+
<div>
|
|
179
|
+
<h3>Registered Names:</h3>
|
|
180
|
+
<ul>
|
|
181
|
+
{registeredNames.map((n) => (
|
|
182
|
+
<li key={n}>{n}.eth</li>
|
|
183
|
+
))}
|
|
184
|
+
</ul>
|
|
185
|
+
</div>
|
|
186
|
+
)}
|
|
112
187
|
</div>
|
|
113
188
|
);
|
|
114
189
|
}
|
|
115
190
|
```
|
|
116
191
|
|
|
117
|
-
|
|
192
|
+
---
|
|
118
193
|
|
|
119
|
-
|
|
120
|
-
import {
|
|
121
|
-
formatAddress,
|
|
122
|
-
parseRecords,
|
|
123
|
-
validateAddress,
|
|
124
|
-
getCoinInfo,
|
|
125
|
-
getResolverAddress,
|
|
126
|
-
} from "@arti/ui-components";
|
|
127
|
-
|
|
128
|
-
// Format Ethereum address
|
|
129
|
-
const shortAddress = formatAddress(
|
|
130
|
-
"0x1234567890abcdef1234567890abcdef12345678"
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
// Parse ENS records
|
|
134
|
-
const records = parseRecords(recordData);
|
|
135
|
-
|
|
136
|
-
// Validate address
|
|
137
|
-
const isValid = validateAddress("0x123...");
|
|
138
|
-
```
|
|
194
|
+
### SubnameOnChainRegistrarModal
|
|
139
195
|
|
|
140
|
-
|
|
196
|
+
Component for registering on-chain subnames (e.g., `mysubname.mydomain.eth`).
|
|
197
|
+
|
|
198
|
+
#### Basic Usage
|
|
141
199
|
|
|
142
200
|
```tsx
|
|
143
|
-
import
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
201
|
+
import { useState } from "react";
|
|
202
|
+
import { SubnameOnChainRegistrarModal } from "@thenamespace/ens-components";
|
|
203
|
+
|
|
204
|
+
function RegisterSubname() {
|
|
205
|
+
const [step, setStep] = useState(0);
|
|
206
|
+
const [name, setName] = useState("");
|
|
207
|
+
const [parentName] = useState("mydomain.eth");
|
|
208
|
+
const [profileComplete, setProfileComplete] = useState(false);
|
|
209
|
+
const [owner, setOwner] = useState("");
|
|
210
|
+
const [duration, setDuration] = useState(1);
|
|
211
|
+
const [useAsPrimary, setUseAsPrimary] = useState(false);
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<SubnameOnChainRegistrarModal
|
|
215
|
+
step={step}
|
|
216
|
+
name={name}
|
|
217
|
+
parentName={parentName}
|
|
218
|
+
profileComplete={profileComplete}
|
|
219
|
+
owner={owner}
|
|
220
|
+
duration={duration}
|
|
221
|
+
useAsPrimary={useAsPrimary}
|
|
222
|
+
onStepChange={setStep}
|
|
223
|
+
onNameChange={setName}
|
|
224
|
+
onProfileCompleteChange={setProfileComplete}
|
|
225
|
+
onOwnerChange={setOwner}
|
|
226
|
+
onDurationChange={setDuration}
|
|
227
|
+
onUseAsPrimaryChange={setUseAsPrimary}
|
|
228
|
+
onCompleteRegistration={() => {
|
|
229
|
+
setStep(2); // Move to success screen
|
|
230
|
+
}}
|
|
231
|
+
/>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
149
234
|
```
|
|
150
235
|
|
|
151
|
-
|
|
236
|
+
#### Component Flow
|
|
237
|
+
|
|
238
|
+
The component has 3 main steps:
|
|
239
|
+
|
|
240
|
+
1. **InitialStep** (step 0) - User enters subname label
|
|
241
|
+
2. **RegistrationStep** (step 1) - User reviews details and registers
|
|
242
|
+
3. **SuccessScreen** (step 2) - Registration completion confirmation
|
|
243
|
+
|
|
244
|
+
#### Props
|
|
245
|
+
|
|
246
|
+
| Prop | Type | Required | Default | Description |
|
|
247
|
+
|------|------|----------|---------|-------------|
|
|
248
|
+
| `step` | `number` | No | `0` | Current step (0: Initial, 1: Registration, 2: Success) |
|
|
249
|
+
| `name` | `string` | No | `""` | Subname label (without parent domain) |
|
|
250
|
+
| `parentName` | `string` | No | `"celotest.eth"` | Parent domain name |
|
|
251
|
+
| `profileComplete` | `boolean` | No | `false` | Whether profile is complete |
|
|
252
|
+
| `domainSuffix` | `string` | No | `"eth"` | Domain suffix |
|
|
253
|
+
| `owner` | `string` | No | `"0x035eB...24117D3"` | Owner address for the subname |
|
|
254
|
+
| `duration` | `number` | No | `1` | Registration duration in years |
|
|
255
|
+
| `registrationFee` | `string` | No | - | Registration fee (optional) |
|
|
256
|
+
| `networkFee` | `string` | No | - | Network fee (optional) |
|
|
257
|
+
| `totalCost` | `string` | No | - | Total cost (optional) |
|
|
258
|
+
| `useAsPrimary` | `boolean` | No | `false` | Whether to use as primary name |
|
|
259
|
+
| `profileImageUrl` | `string` | No | - | Profile image URL (optional) |
|
|
260
|
+
| `onStepChange` | `(step: number) => void` | No | - | Callback when step changes |
|
|
261
|
+
| `onNameChange` | `(name: string) => void` | No | - | Callback when name changes |
|
|
262
|
+
| `onProfileCompleteChange` | `(complete: boolean) => void` | No | - | Callback when profile complete status changes |
|
|
263
|
+
| `onOwnerChange` | `(owner: string) => void` | No | - | Callback when owner changes |
|
|
264
|
+
| `onDurationChange` | `(duration: number) => void` | No | - | Callback when duration changes |
|
|
265
|
+
| `onUseAsPrimaryChange` | `(useAsPrimary: boolean) => void` | No | - | Callback when useAsPrimary changes |
|
|
266
|
+
| `onRegister` | `() => void` | No | - | Callback when register button is clicked |
|
|
267
|
+
| `onCancel` | `() => void` | No | - | Callback when cancel button is clicked |
|
|
268
|
+
| `onClose` | `() => void` | No | - | Callback when close button is clicked |
|
|
269
|
+
| `onCompleteProfile` | `() => void` | No | - | Callback when "Complete Profile" is clicked |
|
|
270
|
+
| `onOpenWallet` | `() => void` | No | - | Callback when wallet needs to be opened |
|
|
271
|
+
| `onCompleteRegistration` | `() => void` | No | - | Callback when registration completes |
|
|
272
|
+
| `onRegisterAnother` | `() => void` | No | - | Callback when "Register Another" is clicked |
|
|
273
|
+
| `onViewName` | `() => void` | No | - | Callback when "View Name" is clicked |
|
|
274
|
+
| `onFinish` | `() => void` | No | - | Callback when finish button is clicked (success screen) |
|
|
275
|
+
|
|
276
|
+
#### Complete Example
|
|
152
277
|
|
|
153
278
|
```tsx
|
|
154
|
-
import {
|
|
279
|
+
import { useState } from "react";
|
|
280
|
+
import { SubnameOnChainRegistrarModal } from "@thenamespace/ens-components";
|
|
281
|
+
|
|
282
|
+
function SubnameRegistrationExample() {
|
|
283
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
284
|
+
const [step, setStep] = useState(0);
|
|
285
|
+
const [name, setName] = useState("");
|
|
286
|
+
const [parentName] = useState("mydomain.eth");
|
|
287
|
+
const [profileComplete, setProfileComplete] = useState(false);
|
|
288
|
+
const [owner, setOwner] = useState("");
|
|
289
|
+
const [duration, setDuration] = useState(1);
|
|
290
|
+
const [useAsPrimary, setUseAsPrimary] = useState(false);
|
|
291
|
+
const [registeredSubnames, setRegisteredSubnames] = useState<string[]>([]);
|
|
292
|
+
|
|
293
|
+
const handleCompleteRegistration = () => {
|
|
294
|
+
const fullName = name ? `${name}.${parentName}` : "";
|
|
295
|
+
if (fullName) {
|
|
296
|
+
setRegisteredSubnames([...registeredSubnames, fullName]);
|
|
297
|
+
setStep(2); // Move to success screen
|
|
298
|
+
alert(`Successfully registered ${fullName}!`);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const handleFinish = () => {
|
|
303
|
+
setIsOpen(false);
|
|
304
|
+
setStep(0);
|
|
305
|
+
setName("");
|
|
306
|
+
setProfileComplete(false);
|
|
307
|
+
setDuration(1);
|
|
308
|
+
setUseAsPrimary(false);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
if (!isOpen) {
|
|
312
|
+
return (
|
|
313
|
+
<div>
|
|
314
|
+
<button onClick={() => setIsOpen(true)}>
|
|
315
|
+
Register Subname
|
|
316
|
+
</button>
|
|
317
|
+
{registeredSubnames.length > 0 && (
|
|
318
|
+
<div>
|
|
319
|
+
<h3>Registered Subnames:</h3>
|
|
320
|
+
<ul>
|
|
321
|
+
{registeredSubnames.map((n) => (
|
|
322
|
+
<li key={n}>{n}</li>
|
|
323
|
+
))}
|
|
324
|
+
</ul>
|
|
325
|
+
</div>
|
|
326
|
+
)}
|
|
327
|
+
</div>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
155
330
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
331
|
+
return (
|
|
332
|
+
<div style={{ position: "fixed", inset: 0, backgroundColor: "rgba(0, 0, 0, 0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1000 }}>
|
|
333
|
+
<div style={{ backgroundColor: "white", borderRadius: "8px", padding: "20px", maxWidth: "600px", width: "90%", maxHeight: "90vh", overflow: "auto" }}>
|
|
334
|
+
<SubnameOnChainRegistrarModal
|
|
335
|
+
step={step}
|
|
336
|
+
name={name}
|
|
337
|
+
parentName={parentName}
|
|
338
|
+
profileComplete={profileComplete}
|
|
339
|
+
owner={owner}
|
|
340
|
+
duration={duration}
|
|
341
|
+
useAsPrimary={useAsPrimary}
|
|
342
|
+
onStepChange={setStep}
|
|
343
|
+
onNameChange={setName}
|
|
344
|
+
onProfileCompleteChange={setProfileComplete}
|
|
345
|
+
onOwnerChange={setOwner}
|
|
346
|
+
onDurationChange={setDuration}
|
|
347
|
+
onUseAsPrimaryChange={setUseAsPrimary}
|
|
348
|
+
onRegister={() => console.log("Register clicked")}
|
|
349
|
+
onCancel={() => {
|
|
350
|
+
console.log("Cancel clicked");
|
|
351
|
+
setStep(0);
|
|
352
|
+
}}
|
|
353
|
+
onClose={handleFinish}
|
|
354
|
+
onCompleteProfile={() => {
|
|
355
|
+
console.log("Complete profile clicked");
|
|
356
|
+
setProfileComplete(true);
|
|
357
|
+
}}
|
|
358
|
+
onCompleteRegistration={handleCompleteRegistration}
|
|
359
|
+
onFinish={handleFinish}
|
|
360
|
+
/>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
);
|
|
364
|
+
}
|
|
161
365
|
```
|
|
162
366
|
|
|
163
|
-
##
|
|
164
|
-
|
|
165
|
-
The library uses CSS custom properties for theming. You can override the default theme:
|
|
367
|
+
## Full Example with Both Components
|
|
166
368
|
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
369
|
+
```tsx
|
|
370
|
+
import React, { useState } from "react";
|
|
371
|
+
import { WagmiProvider } from "wagmi";
|
|
372
|
+
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
|
|
373
|
+
import { RainbowKitProvider, getDefaultConfig } from "@rainbow-me/rainbowkit";
|
|
374
|
+
import { mainnet, sepolia } from "wagmi/chains";
|
|
375
|
+
import { http } from "wagmi";
|
|
376
|
+
import { ENSNamesRegistrarComponent, SubnameOnChainRegistrarModal } from "@thenamespace/ens-components";
|
|
377
|
+
import "@thenamespace/ens-components/index.css";
|
|
378
|
+
import "@rainbow-me/rainbowkit/styles.css";
|
|
379
|
+
|
|
380
|
+
const wagmiConfig = getDefaultConfig({
|
|
381
|
+
appName: "My ENS App",
|
|
382
|
+
projectId: "YOUR_WALLETCONNECT_PROJECT_ID",
|
|
383
|
+
chains: [mainnet, sepolia],
|
|
384
|
+
transports: {
|
|
385
|
+
[mainnet.id]: http(),
|
|
386
|
+
[sepolia.id]: http(),
|
|
387
|
+
},
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
const queryClient = new QueryClient();
|
|
391
|
+
|
|
392
|
+
function AppProviders({ children }: { children: React.ReactNode }) {
|
|
393
|
+
return (
|
|
394
|
+
<WagmiProvider config={wagmiConfig}>
|
|
395
|
+
<QueryClientProvider client={queryClient}>
|
|
396
|
+
<RainbowKitProvider>
|
|
397
|
+
{children}
|
|
398
|
+
</RainbowKitProvider>
|
|
399
|
+
</QueryClientProvider>
|
|
400
|
+
</WagmiProvider>
|
|
401
|
+
);
|
|
173
402
|
}
|
|
174
|
-
```
|
|
175
403
|
|
|
176
|
-
|
|
404
|
+
function App() {
|
|
405
|
+
const [activeTab, setActiveTab] = useState<"ens" | "subname">("ens");
|
|
406
|
+
|
|
407
|
+
// ENS Name Registration State
|
|
408
|
+
const [ensName, setEnsName] = useState("");
|
|
409
|
+
const [ensDuration, setEnsDuration] = useState(1);
|
|
410
|
+
|
|
411
|
+
// Subname Registration State
|
|
412
|
+
const [subnameStep, setSubnameStep] = useState(0);
|
|
413
|
+
const [subname, setSubname] = useState("");
|
|
414
|
+
const [parentName] = useState("mydomain.eth");
|
|
415
|
+
const [profileComplete, setProfileComplete] = useState(false);
|
|
416
|
+
const [owner, setOwner] = useState("");
|
|
417
|
+
const [duration, setDuration] = useState(1);
|
|
418
|
+
const [useAsPrimary, setUseAsPrimary] = useState(false);
|
|
177
419
|
|
|
178
|
-
|
|
420
|
+
return (
|
|
421
|
+
<AppProviders>
|
|
422
|
+
<div style={{ padding: "20px" }}>
|
|
423
|
+
<div style={{ marginBottom: "20px" }}>
|
|
424
|
+
<button
|
|
425
|
+
onClick={() => setActiveTab("ens")}
|
|
426
|
+
style={{ marginRight: "10px", padding: "10px", backgroundColor: activeTab === "ens" ? "#007bff" : "#ccc", color: "white", border: "none", borderRadius: "4px", cursor: "pointer" }}
|
|
427
|
+
>
|
|
428
|
+
Register ENS Name
|
|
429
|
+
</button>
|
|
430
|
+
<button
|
|
431
|
+
onClick={() => setActiveTab("subname")}
|
|
432
|
+
style={{ padding: "10px", backgroundColor: activeTab === "subname" ? "#007bff" : "#ccc", color: "white", border: "none", borderRadius: "4px", cursor: "pointer" }}
|
|
433
|
+
>
|
|
434
|
+
Register Subname
|
|
435
|
+
</button>
|
|
436
|
+
</div>
|
|
437
|
+
|
|
438
|
+
{activeTab === "ens" && (
|
|
439
|
+
<div>
|
|
440
|
+
<h2>Register ENS Name</h2>
|
|
441
|
+
<ENSNamesRegistrarComponent
|
|
442
|
+
name={ensName}
|
|
443
|
+
duration={ensDuration}
|
|
444
|
+
onNameChange={setEnsName}
|
|
445
|
+
onDurationChange={setEnsDuration}
|
|
446
|
+
onCompleteRegistration={() => {
|
|
447
|
+
alert(`Successfully registered ${ensName}.eth!`);
|
|
448
|
+
}}
|
|
449
|
+
/>
|
|
450
|
+
</div>
|
|
451
|
+
)}
|
|
452
|
+
|
|
453
|
+
{activeTab === "subname" && (
|
|
454
|
+
<div>
|
|
455
|
+
<h2>Register On-Chain Subname</h2>
|
|
456
|
+
<SubnameOnChainRegistrarModal
|
|
457
|
+
step={subnameStep}
|
|
458
|
+
name={subname}
|
|
459
|
+
parentName={parentName}
|
|
460
|
+
profileComplete={profileComplete}
|
|
461
|
+
owner={owner}
|
|
462
|
+
duration={duration}
|
|
463
|
+
useAsPrimary={useAsPrimary}
|
|
464
|
+
onStepChange={setSubnameStep}
|
|
465
|
+
onNameChange={setSubname}
|
|
466
|
+
onProfileCompleteChange={setProfileComplete}
|
|
467
|
+
onOwnerChange={setOwner}
|
|
468
|
+
onDurationChange={setDuration}
|
|
469
|
+
onUseAsPrimaryChange={setUseAsPrimary}
|
|
470
|
+
onCompleteRegistration={() => {
|
|
471
|
+
setSubnameStep(2);
|
|
472
|
+
alert(`Successfully registered ${subname}.${parentName}!`);
|
|
473
|
+
}}
|
|
474
|
+
onFinish={() => {
|
|
475
|
+
setSubnameStep(0);
|
|
476
|
+
setSubname("");
|
|
477
|
+
}}
|
|
478
|
+
/>
|
|
479
|
+
</div>
|
|
480
|
+
)}
|
|
481
|
+
</div>
|
|
482
|
+
</AppProviders>
|
|
483
|
+
);
|
|
484
|
+
}
|
|
179
485
|
|
|
180
|
-
|
|
181
|
-
npm run storybook
|
|
486
|
+
export default App;
|
|
182
487
|
```
|
|
183
488
|
|
|
184
|
-
##
|
|
489
|
+
## Styling
|
|
185
490
|
|
|
186
|
-
|
|
187
|
-
# Install dependencies
|
|
188
|
-
npm install
|
|
189
|
-
|
|
190
|
-
# Start development build
|
|
191
|
-
npm run dev
|
|
491
|
+
The components come with their own CSS. Make sure to import the styles:
|
|
192
492
|
|
|
193
|
-
|
|
194
|
-
|
|
493
|
+
```tsx
|
|
494
|
+
import "@thenamespace/ens-components/index.css";
|
|
495
|
+
import "@rainbow-me/rainbowkit/styles.css";
|
|
496
|
+
```
|
|
195
497
|
|
|
196
|
-
|
|
197
|
-
npm run storybook
|
|
498
|
+
## Requirements
|
|
198
499
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
500
|
+
- React 18+
|
|
501
|
+
- Node.js 16+
|
|
502
|
+
- A WalletConnect Project ID (get one at https://cloud.walletconnect.com)
|
|
202
503
|
|
|
203
504
|
## License
|
|
204
505
|
|
|
205
506
|
ISC
|
|
206
507
|
|
|
207
|
-
##
|
|
508
|
+
## Support
|
|
208
509
|
|
|
209
|
-
|
|
510
|
+
For issues and questions, please visit the package repository.
|