@taskon/widget-react 0.0.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 +1064 -0
- package/dist/CommunityTaskList.css +5010 -0
- package/dist/EligibilityInfo.css +1966 -0
- package/dist/LeaderboardWidget.css +815 -0
- package/dist/Quest.css +4584 -0
- package/dist/Table.css +389 -0
- package/dist/TaskOnProvider.css +163 -0
- package/dist/WidgetShell.css +182 -0
- package/dist/chunks/CommunityTaskList-CrH6r4Av.js +6886 -0
- package/dist/chunks/EligibilityInfo-DesW9-k9.js +24900 -0
- package/dist/chunks/LeaderboardWidget-BSGpHKTk.js +1156 -0
- package/dist/chunks/Quest-uSIVq78I.js +8581 -0
- package/dist/chunks/Table-CWGf2FKV.js +449 -0
- package/dist/chunks/TaskOnProvider-QMwxGL44.js +1435 -0
- package/dist/chunks/ThemeProvider-Cs8IUVQj.js +1118 -0
- package/dist/chunks/WidgetShell-NlOgn1x5.js +1517 -0
- package/dist/chunks/common-ja-DWhTaFHb.js +23 -0
- package/dist/chunks/common-ko-80ezXsMG.js +23 -0
- package/dist/chunks/index-CwMvO_wZ.js +777 -0
- package/dist/chunks/leaderboardwidget-ja-Bj6gz6y1.js +119 -0
- package/dist/chunks/leaderboardwidget-ko-f1cLO9ic.js +119 -0
- package/dist/chunks/useToast-BGJhd3BX.js +93 -0
- package/dist/chunks/useWidgetLocale-BVcopbZS.js +74 -0
- package/dist/chunks/usercenter-ja-DBj_dtuz.js +329 -0
- package/dist/chunks/usercenter-ko-DYTkHAld.js +329 -0
- package/dist/community-task.d.ts +451 -0
- package/dist/community-task.js +9 -0
- package/dist/core.d.ts +803 -0
- package/dist/core.js +22 -0
- package/dist/index.css +3662 -0
- package/dist/index.d.ts +1627 -0
- package/dist/index.js +7372 -0
- package/dist/leaderboard.d.ts +547 -0
- package/dist/leaderboard.js +17 -0
- package/dist/quest.d.ts +389 -0
- package/dist/quest.js +8 -0
- package/package.json +97 -0
package/README.md
ADDED
|
@@ -0,0 +1,1064 @@
|
|
|
1
|
+
# @taskon/widget-react
|
|
2
|
+
|
|
3
|
+
TaskOn React Widget - Embeddable white-label components for integrating TaskOn quest/task functionality into your application.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @taskon/widget-react @taskon/core
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @taskon/widget-react @taskon/core
|
|
11
|
+
# or
|
|
12
|
+
yarn add @taskon/widget-react @taskon/core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
// Providers from core (minimal CSS ~3KB)
|
|
19
|
+
import { TaskOnProvider } from "@taskon/widget-react/core";
|
|
20
|
+
// Widgets from their sub-paths (isolated CSS)
|
|
21
|
+
import { QuestWidget } from "@taskon/widget-react/quest";
|
|
22
|
+
|
|
23
|
+
const App = () => (
|
|
24
|
+
<TaskOnProvider
|
|
25
|
+
config={{
|
|
26
|
+
apiKey: "your-api-key",
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
<YourApp />
|
|
30
|
+
</TaskOnProvider>
|
|
31
|
+
);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Import Methods
|
|
35
|
+
|
|
36
|
+
### Recommended: Sub-path Imports (Optimal CSS)
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
// Core: Providers and hooks only (~3KB CSS for Toast)
|
|
40
|
+
import { TaskOnProvider, ThemeProvider, useTaskOnAuth } from "@taskon/widget-react/core";
|
|
41
|
+
|
|
42
|
+
// Widgets: Each loads only its own CSS
|
|
43
|
+
import { QuestWidget } from "@taskon/widget-react/quest"; // ~26KB CSS
|
|
44
|
+
import { CommunityTaskList } from "@taskon/widget-react/community-task"; // ~51KB CSS
|
|
45
|
+
import { LeaderboardWidget } from "@taskon/widget-react/leaderboard"; // ~17KB CSS
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Alternative: Main Entry Import (Loads All CSS)
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
// Loads ALL widget CSS (~92KB) - not recommended for production
|
|
52
|
+
import { TaskOnProvider, QuestWidget, CommunityTaskList } from "@taskon/widget-react";
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage Example
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { TaskOnProvider, useTaskOnAuth } from "@taskon/widget-react/core";
|
|
59
|
+
import { QuestWidget } from "@taskon/widget-react/quest";
|
|
60
|
+
|
|
61
|
+
const App = () => (
|
|
62
|
+
<TaskOnProvider
|
|
63
|
+
config={{
|
|
64
|
+
apiKey: "your-api-key",
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
<YourApp />
|
|
68
|
+
</TaskOnProvider>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Your app controls the login UI
|
|
72
|
+
const YourApp = () => {
|
|
73
|
+
const { userId, login, logout } = useTaskOnAuth();
|
|
74
|
+
const { user, getSignature } = useYourAuth(); // Your auth hook
|
|
75
|
+
|
|
76
|
+
// When user logs in to your app, login to TaskOn
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (user?.email && !userId) {
|
|
79
|
+
const { sign, timestamp } = getSignature(); // Get signature from your backend
|
|
80
|
+
login({ method: "email", value: user.email, sign, timestamp });
|
|
81
|
+
}
|
|
82
|
+
}, [user, userId]);
|
|
83
|
+
|
|
84
|
+
// When user logs out from your app, logout from TaskOn
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (!user && userId) {
|
|
87
|
+
logout();
|
|
88
|
+
}
|
|
89
|
+
}, [user, userId]);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div>
|
|
93
|
+
{userId && <p>TaskOn User ID: {userId}</p>}
|
|
94
|
+
{/* Theme configured in TaskOn Dashboard */}
|
|
95
|
+
<QuestWidget configId="cfg_abc123" />
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Architecture
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
┌─ TaskOnProvider ─────────────────────────────────────────┐
|
|
105
|
+
│ config: { apiKey } │
|
|
106
|
+
│ Purpose: Authentication only │
|
|
107
|
+
│ │
|
|
108
|
+
│ ┌─ Mode A: Cloud Config ──────────────────────────────┐ │
|
|
109
|
+
│ │ <QuestWidget configId="cfg_abc123" /> │ │
|
|
110
|
+
│ │ → Theme from TaskOn cloud │ │
|
|
111
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
112
|
+
│ │
|
|
113
|
+
│ ┌─ Mode B: Local Theme ───────────────────────────────┐ │
|
|
114
|
+
│ │ <ThemeProvider theme={{ mode: 'dark' }}> │ │
|
|
115
|
+
│ │ <QuestWidget /> /* no configId */ │ │
|
|
116
|
+
│ │ </ThemeProvider> │ │
|
|
117
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
118
|
+
└──────────────────────────────────────────────────────────┘
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Theme Source (mutually exclusive)
|
|
122
|
+
|
|
123
|
+
| Mode | Theme Source |
|
|
124
|
+
| --------------------- | ------------------------------------ |
|
|
125
|
+
| `configId` provided | Cloud config (ThemeProvider ignored) |
|
|
126
|
+
| No `configId` | ThemeProvider or default theme |
|
|
127
|
+
|
|
128
|
+
## Security
|
|
129
|
+
|
|
130
|
+
TaskOn uses **API Key** authentication to verify that widget requests come from authorized projects.
|
|
131
|
+
|
|
132
|
+
### Step 1: Get API Key from TaskOn Dashboard
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
API Key: /KDiqEFNCaGTVTdTpCFrZOsUj5vDi5uGLSFmwyHeboE= (for X-API-Key header)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Step 2: Configure TaskOnProvider
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
<TaskOnProvider
|
|
142
|
+
config={{
|
|
143
|
+
apiKey: "your-api-key",
|
|
144
|
+
}}
|
|
145
|
+
>
|
|
146
|
+
<YourApp />
|
|
147
|
+
</TaskOnProvider>;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### HTTP Headers
|
|
151
|
+
|
|
152
|
+
All API requests include:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
X-API-Key: your-api-key # Project authorization
|
|
156
|
+
Authorization: Bearer xxx # User authorization (after login)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Security Best Practices
|
|
160
|
+
|
|
161
|
+
1. **Keep API Key secure** - Don't expose in public repositories
|
|
162
|
+
2. **Use HTTPS** - All communication must be encrypted
|
|
163
|
+
|
|
164
|
+
## TaskOnProvider
|
|
165
|
+
|
|
166
|
+
The root provider component for authentication. Must wrap your application.
|
|
167
|
+
|
|
168
|
+
### Props
|
|
169
|
+
|
|
170
|
+
| Prop | Type | Required | Default | Description |
|
|
171
|
+
| ------------ | ------------------------ | -------- | ------- | -------------------- |
|
|
172
|
+
| `config` | `TaskOnProviderConfig` | Yes | - | Configuration object |
|
|
173
|
+
| `children` | `ReactNode` | Yes | - | Child components |
|
|
174
|
+
|
|
175
|
+
### TaskOnProviderConfig
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
interface TaskOnProviderConfig {
|
|
179
|
+
// Required: API Key for authentication (X-API-Key header)
|
|
180
|
+
apiKey: string;
|
|
181
|
+
|
|
182
|
+
// Locale setting
|
|
183
|
+
locale?: "en" | "ko" | "ja" | "ru" | "es"; // default: auto-detect
|
|
184
|
+
|
|
185
|
+
// Wallet configuration (only needed if using wallet login)
|
|
186
|
+
walletConfig?: {
|
|
187
|
+
evmAdapter?: WalletAdapter; // Custom EVM wallet adapter
|
|
188
|
+
solanaAdapter?: WalletAdapter; // Custom Solana wallet adapter
|
|
189
|
+
disableAutoDetect?: boolean; // Disable auto-detection
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// WalletConnect Project ID (required for WalletConnect support)
|
|
193
|
+
// Get your project ID at https://cloud.walletconnect.com
|
|
194
|
+
walletConnectProjectId?: string;
|
|
195
|
+
|
|
196
|
+
// Callback when user needs to login (e.g., clicks login overlay)
|
|
197
|
+
onRequestLogin?: () => void;
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Internationalization
|
|
202
|
+
|
|
203
|
+
### Supported Locales
|
|
204
|
+
|
|
205
|
+
| Locale | Language |
|
|
206
|
+
| ------ | ----------------- |
|
|
207
|
+
| `en` | English (default) |
|
|
208
|
+
| `ko` | Korean |
|
|
209
|
+
| `ja` | Japanese |
|
|
210
|
+
| `ru` | Russian |
|
|
211
|
+
| `es` | Spanish |
|
|
212
|
+
|
|
213
|
+
### Configuration
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
<TaskOnProvider
|
|
217
|
+
config={{
|
|
218
|
+
apiKey: "your-api-key",
|
|
219
|
+
locale: "ko",
|
|
220
|
+
}}
|
|
221
|
+
>
|
|
222
|
+
<App />
|
|
223
|
+
</TaskOnProvider>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Dynamic Locale Switching
|
|
227
|
+
|
|
228
|
+
Control locale via your own state:
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
const App = () => {
|
|
232
|
+
const [locale, setLocale] = useState("en");
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<TaskOnProvider config={{ apiKey: "your-api-key", locale }}>
|
|
236
|
+
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
|
|
237
|
+
<option value="en">English</option>
|
|
238
|
+
<option value="ko">한국어</option>
|
|
239
|
+
<option value="ja">日本語</option>
|
|
240
|
+
</select>
|
|
241
|
+
<QuestWidget configId="cfg_abc123" />
|
|
242
|
+
</TaskOnProvider>
|
|
243
|
+
);
|
|
244
|
+
};
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Locale Auto-Detection
|
|
248
|
+
|
|
249
|
+
When `locale` is not specified, TaskOn detects from browser language, falling back to `en`.
|
|
250
|
+
|
|
251
|
+
## ThemeProvider
|
|
252
|
+
|
|
253
|
+
Optional provider for theme configuration. Supports nesting for different theme zones.
|
|
254
|
+
|
|
255
|
+
### Props
|
|
256
|
+
|
|
257
|
+
| Prop | Type | Required | Default | Description |
|
|
258
|
+
| ------------ | --------------------- | -------- | -------- | -------------------- |
|
|
259
|
+
| `theme` | `TaskOnThemeConfig` | No | - | Theme configuration |
|
|
260
|
+
| `children` | `ReactNode` | Yes | - | Child components |
|
|
261
|
+
| `inherit` | `boolean` | No | `true` | Inherit parent theme |
|
|
262
|
+
|
|
263
|
+
### TaskOnThemeConfig
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
interface TaskOnThemeConfig {
|
|
267
|
+
// Theme mode
|
|
268
|
+
mode?: "light" | "dark" | "auto"; // default: 'light'
|
|
269
|
+
|
|
270
|
+
// Compact mode
|
|
271
|
+
compact?: boolean; // default: false
|
|
272
|
+
|
|
273
|
+
// Seed tokens - algorithm input, auto-derives other values
|
|
274
|
+
seed?: SeedToken;
|
|
275
|
+
|
|
276
|
+
// Map tokens - override derived values
|
|
277
|
+
map?: MapToken;
|
|
278
|
+
|
|
279
|
+
// Optional: separate config for light/dark mode
|
|
280
|
+
light?: {
|
|
281
|
+
seed?: SeedToken;
|
|
282
|
+
map?: MapToken;
|
|
283
|
+
};
|
|
284
|
+
dark?: {
|
|
285
|
+
seed?: SeedToken;
|
|
286
|
+
map?: MapToken;
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
interface SeedToken {
|
|
291
|
+
colorPrimary?: string; // e.g., '#6366f1'
|
|
292
|
+
colorSecondary?: string;
|
|
293
|
+
colorSuccess?: string;
|
|
294
|
+
colorWarning?: string;
|
|
295
|
+
colorError?: string;
|
|
296
|
+
borderRadius?: number; // e.g., 8
|
|
297
|
+
fontSize?: number; // e.g., 14
|
|
298
|
+
fontFamily?: string;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
interface MapToken {
|
|
302
|
+
// Primary colors (derived from seed.colorPrimary)
|
|
303
|
+
colorPrimary?: string;
|
|
304
|
+
colorPrimaryHover?: string;
|
|
305
|
+
colorPrimaryActive?: string;
|
|
306
|
+
colorPrimaryBg?: string;
|
|
307
|
+
|
|
308
|
+
// Background
|
|
309
|
+
colorBg?: string;
|
|
310
|
+
colorBgElevated?: string;
|
|
311
|
+
colorBgSpotlight?: string;
|
|
312
|
+
|
|
313
|
+
// Text
|
|
314
|
+
colorText?: string;
|
|
315
|
+
colorTextSecondary?: string;
|
|
316
|
+
colorTextTertiary?: string;
|
|
317
|
+
colorTextDisabled?: string;
|
|
318
|
+
|
|
319
|
+
// Border
|
|
320
|
+
colorBorder?: string;
|
|
321
|
+
colorBorderSecondary?: string;
|
|
322
|
+
|
|
323
|
+
// Layout
|
|
324
|
+
borderRadius?: number;
|
|
325
|
+
borderRadiusSm?: number;
|
|
326
|
+
borderRadiusLg?: number;
|
|
327
|
+
|
|
328
|
+
// Typography
|
|
329
|
+
fontSize?: number;
|
|
330
|
+
fontSizeSm?: number;
|
|
331
|
+
fontSizeLg?: number;
|
|
332
|
+
|
|
333
|
+
// Spacing
|
|
334
|
+
spacing?: number; // base spacing unit, e.g., 8
|
|
335
|
+
spacingXs?: number; // e.g., 4
|
|
336
|
+
spacingSm?: number; // e.g., 8
|
|
337
|
+
spacingMd?: number; // e.g., 16
|
|
338
|
+
spacingLg?: number; // e.g., 24
|
|
339
|
+
spacingXl?: number; // e.g., 32
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Token Priority
|
|
344
|
+
|
|
345
|
+
```
|
|
346
|
+
light/dark.map > light/dark.seed (derived) > map > seed (derived) > default
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Theme Inheritance
|
|
350
|
+
|
|
351
|
+
Nested ThemeProviders inherit from parent and can override specific values:
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
<TaskOnProvider config={{ apiKey: "your-api-key" }}>
|
|
355
|
+
<ThemeProvider theme={{ mode: "light", seed: { colorPrimary: "#6366f1" } }}>
|
|
356
|
+
<Header /> {/* light + primary #6366f1 */}
|
|
357
|
+
<ThemeProvider theme={{ mode: "dark" }}>
|
|
358
|
+
<Sidebar /> {/* dark + inherits primary #6366f1 */}
|
|
359
|
+
</ThemeProvider>
|
|
360
|
+
<ThemeProvider theme={{ seed: { colorPrimary: "#ef4444" } }}>
|
|
361
|
+
<DangerZone /> {/* light + primary #ef4444 */}
|
|
362
|
+
</ThemeProvider>
|
|
363
|
+
</ThemeProvider>
|
|
364
|
+
</TaskOnProvider>
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Light/Dark Separate Config
|
|
368
|
+
|
|
369
|
+
Configure different themes for light and dark modes:
|
|
370
|
+
|
|
371
|
+
```tsx
|
|
372
|
+
// Different primary colors for each mode
|
|
373
|
+
<ThemeProvider
|
|
374
|
+
theme={{
|
|
375
|
+
mode: 'auto',
|
|
376
|
+
light: { seed: { colorPrimary: '#6366f1' } },
|
|
377
|
+
dark: { seed: { colorPrimary: '#818cf8' } },
|
|
378
|
+
}}
|
|
379
|
+
>
|
|
380
|
+
<App />
|
|
381
|
+
</ThemeProvider>
|
|
382
|
+
|
|
383
|
+
// Override specific derived values
|
|
384
|
+
<ThemeProvider
|
|
385
|
+
theme={{
|
|
386
|
+
mode: 'auto',
|
|
387
|
+
light: {
|
|
388
|
+
seed: { colorPrimary: '#6366f1' },
|
|
389
|
+
map: { colorPrimaryHover: '#4f46e5' },
|
|
390
|
+
},
|
|
391
|
+
dark: {
|
|
392
|
+
seed: { colorPrimary: '#818cf8' },
|
|
393
|
+
map: { colorBg: '#0a0a0a' },
|
|
394
|
+
},
|
|
395
|
+
}}
|
|
396
|
+
>
|
|
397
|
+
<App />
|
|
398
|
+
</ThemeProvider>
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Disable Inheritance
|
|
402
|
+
|
|
403
|
+
Use `inherit={false}` for completely independent themes:
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
<ThemeProvider theme={{ mode: "dark" }}>
|
|
407
|
+
<DarkContent />
|
|
408
|
+
|
|
409
|
+
<ThemeProvider theme={{ mode: "light" }} inherit={false}>
|
|
410
|
+
<LightPopup /> {/* Fully independent light theme */}
|
|
411
|
+
</ThemeProvider>
|
|
412
|
+
</ThemeProvider>
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Widgets
|
|
416
|
+
|
|
417
|
+
### Cloud Configuration
|
|
418
|
+
|
|
419
|
+
Widgets support cloud configuration via `configId`. Configure in TaskOn Dashboard and load at runtime:
|
|
420
|
+
|
|
421
|
+
```tsx
|
|
422
|
+
// Cloud config includes: theme, feature flags, custom texts
|
|
423
|
+
<QuestWidget configId="cfg_abc123" />
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Widget Props
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
interface WidgetProps {
|
|
430
|
+
// Cloud config ID from TaskOn Dashboard
|
|
431
|
+
configId?: string;
|
|
432
|
+
|
|
433
|
+
// Custom class names for widget parts
|
|
434
|
+
classNames?: {
|
|
435
|
+
root?: string;
|
|
436
|
+
header?: string;
|
|
437
|
+
body?: string;
|
|
438
|
+
footer?: string;
|
|
439
|
+
// ... widget-specific parts
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// Custom inline styles for widget parts
|
|
443
|
+
styles?: {
|
|
444
|
+
root?: React.CSSProperties;
|
|
445
|
+
header?: React.CSSProperties;
|
|
446
|
+
body?: React.CSSProperties;
|
|
447
|
+
footer?: React.CSSProperties;
|
|
448
|
+
// ... widget-specific parts
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Styling with classNames and styles
|
|
454
|
+
|
|
455
|
+
Widgets support fine-grained styling via `classNames` and `styles` props:
|
|
456
|
+
|
|
457
|
+
```tsx
|
|
458
|
+
// Using classNames
|
|
459
|
+
<QuestWidget
|
|
460
|
+
configId="cfg_abc123"
|
|
461
|
+
classNames={{
|
|
462
|
+
root: 'my-quest-widget',
|
|
463
|
+
header: 'my-quest-header',
|
|
464
|
+
body: 'my-quest-body',
|
|
465
|
+
}}
|
|
466
|
+
/>
|
|
467
|
+
|
|
468
|
+
// Using inline styles
|
|
469
|
+
<QuestWidget
|
|
470
|
+
configId="cfg_abc123"
|
|
471
|
+
styles={{
|
|
472
|
+
root: { maxWidth: 400 },
|
|
473
|
+
header: { borderBottom: '1px solid #eee' },
|
|
474
|
+
body: { padding: 24 },
|
|
475
|
+
}}
|
|
476
|
+
/>
|
|
477
|
+
|
|
478
|
+
// Combining both
|
|
479
|
+
<QuestWidget
|
|
480
|
+
configId="cfg_abc123"
|
|
481
|
+
classNames={{ root: 'custom-widget' }}
|
|
482
|
+
styles={{ header: { backgroundColor: 'transparent' } }}
|
|
483
|
+
/>
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
Each widget documents its available parts in its own API reference.
|
|
487
|
+
|
|
488
|
+
### Usage Examples
|
|
489
|
+
|
|
490
|
+
```tsx
|
|
491
|
+
// Example 1: Using cloud config (theme from Dashboard)
|
|
492
|
+
<TaskOnProvider config={{ apiKey: 'your-api-key' }}>
|
|
493
|
+
<QuestWidget configId="cfg_abc123" />
|
|
494
|
+
<TaskWidget configId="cfg_xyz789" />
|
|
495
|
+
</TaskOnProvider>
|
|
496
|
+
|
|
497
|
+
// Example 2: Using local theme (no cloud config)
|
|
498
|
+
<TaskOnProvider config={{ apiKey: 'your-api-key' }}>
|
|
499
|
+
<ThemeProvider theme={{ mode: 'dark', seed: { colorPrimary: '#6366f1' } }}>
|
|
500
|
+
<QuestWidget />
|
|
501
|
+
<TaskWidget />
|
|
502
|
+
</ThemeProvider>
|
|
503
|
+
</TaskOnProvider>
|
|
504
|
+
|
|
505
|
+
// Example 3: Different local themes for different areas
|
|
506
|
+
<TaskOnProvider config={{ apiKey: 'your-api-key' }}>
|
|
507
|
+
<ThemeProvider theme={{ mode: 'light' }}>
|
|
508
|
+
<TaskWidget />
|
|
509
|
+
</ThemeProvider>
|
|
510
|
+
|
|
511
|
+
<ThemeProvider theme={{ mode: 'dark', compact: true }}>
|
|
512
|
+
<QuestWidget />
|
|
513
|
+
</ThemeProvider>
|
|
514
|
+
</TaskOnProvider>
|
|
515
|
+
|
|
516
|
+
// Example 4: Mixed - some with cloud config, some with local theme
|
|
517
|
+
<TaskOnProvider config={{ apiKey: 'your-api-key' }}>
|
|
518
|
+
{/* Cloud config */}
|
|
519
|
+
<QuestWidget configId="cfg_abc123" />
|
|
520
|
+
|
|
521
|
+
{/* Local theme */}
|
|
522
|
+
<ThemeProvider theme={{ mode: 'dark' }}>
|
|
523
|
+
<TaskWidget />
|
|
524
|
+
</ThemeProvider>
|
|
525
|
+
</TaskOnProvider>
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
## Login Methods
|
|
529
|
+
|
|
530
|
+
TaskOn uses a unified `login` method with signature verification. All login methods require a backend signature for security.
|
|
531
|
+
|
|
532
|
+
### Unified Login API
|
|
533
|
+
|
|
534
|
+
```typescript
|
|
535
|
+
import { useTaskOnAuth } from "@taskon/widget-react";
|
|
536
|
+
|
|
537
|
+
const { login } = useTaskOnAuth();
|
|
538
|
+
|
|
539
|
+
// Login with any method
|
|
540
|
+
await login({
|
|
541
|
+
method: "evm_wallet", // Login method type
|
|
542
|
+
value: "0x1234...", // Address / email / OAuth token
|
|
543
|
+
sign: signatureFromBackend, // Backend signature
|
|
544
|
+
timestamp: 1234567890, // Signature timestamp (seconds)
|
|
545
|
+
});
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Supported Methods
|
|
549
|
+
|
|
550
|
+
| Method | `method` value | `value` parameter |
|
|
551
|
+
| ------------- | ----------------- | ----------------------- |
|
|
552
|
+
| EVM Wallet | `evm_wallet` | Wallet address (0x...) |
|
|
553
|
+
| Solana Wallet | `solana_wallet` | Wallet address (base58) |
|
|
554
|
+
| Email | `email` | Email address |
|
|
555
|
+
| Discord | `discord` | OAuth token |
|
|
556
|
+
| Twitter | `twitter` | OAuth token |
|
|
557
|
+
| Telegram | `telegram` | OAuth token |
|
|
558
|
+
|
|
559
|
+
### LoginParams Type
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
interface LoginParams {
|
|
563
|
+
method: LoginMethod; // Login method type
|
|
564
|
+
value: string; // Address / email / OAuth token
|
|
565
|
+
sign: string; // Backend signature
|
|
566
|
+
timestamp: number; // Signature timestamp (seconds)
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
type LoginMethod =
|
|
570
|
+
| "evm_wallet"
|
|
571
|
+
| "solana_wallet"
|
|
572
|
+
| "email"
|
|
573
|
+
| "discord"
|
|
574
|
+
| "twitter"
|
|
575
|
+
| "telegram";
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
## Wallet Integration
|
|
579
|
+
|
|
580
|
+
When tasks or rewards involve blockchain operations (e.g., token rewards, NFT minting, on-chain verification), widgets need to interact with the user's wallet for:
|
|
581
|
+
|
|
582
|
+
- **Connecting wallet** - Get user's wallet address
|
|
583
|
+
- **Signing messages** - Verify wallet ownership
|
|
584
|
+
- **Calling contracts** - Claim on-chain rewards, execute transactions
|
|
585
|
+
|
|
586
|
+
### Overview
|
|
587
|
+
|
|
588
|
+
TaskOn widgets include built-in wallet management, but also support external wallet providers for seamless integration with existing dApps. When wrapped in an external provider, the widget automatically detects and reuses your wallet management.
|
|
589
|
+
|
|
590
|
+
### Wallet Management
|
|
591
|
+
|
|
592
|
+
TaskOn provides flexible wallet integration options:
|
|
593
|
+
|
|
594
|
+
| Setup | Behavior |
|
|
595
|
+
| -------------- | ------------------------------------- |
|
|
596
|
+
| Custom adapter | Uses your provided `WalletAdapter` |
|
|
597
|
+
| Default | Uses built-in window.ethereum adapter |
|
|
598
|
+
|
|
599
|
+
### Custom Wallet Adapter (Recommended)
|
|
600
|
+
|
|
601
|
+
If you want full control over wallet connection (e.g., using RainbowKit, Web3Modal), provide a custom adapter:
|
|
602
|
+
|
|
603
|
+
```tsx
|
|
604
|
+
import { createWalletAdapter } from "./my-wallet-adapter";
|
|
605
|
+
|
|
606
|
+
<TaskOnProvider
|
|
607
|
+
config={{
|
|
608
|
+
apiKey: "your-api-key",
|
|
609
|
+
walletConfig: {
|
|
610
|
+
evmAdapter: createWalletAdapter(),
|
|
611
|
+
},
|
|
612
|
+
}}
|
|
613
|
+
>
|
|
614
|
+
<App />
|
|
615
|
+
</TaskOnProvider>;
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### Built-in Wallet Support
|
|
619
|
+
|
|
620
|
+
If no custom adapter is provided, TaskOn automatically uses `window.ethereum` to connect to browser wallets like MetaMask:
|
|
621
|
+
|
|
622
|
+
```tsx
|
|
623
|
+
// No wallet config needed - uses window.ethereum by default
|
|
624
|
+
<TaskOnProvider config={{ apiKey: "your-api-key" }}>
|
|
625
|
+
<App />
|
|
626
|
+
</TaskOnProvider>
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### Built-in Wallet Binding Dialog
|
|
630
|
+
|
|
631
|
+
When tasks require wallet binding (e.g., on-chain verification), TaskOn shows a built-in wallet selection dialog:
|
|
632
|
+
|
|
633
|
+
**Desktop (without adapter):**
|
|
634
|
+
- MetaMask
|
|
635
|
+
- ONTO Wallet
|
|
636
|
+
- Bitget Wallet
|
|
637
|
+
- OKX Wallet
|
|
638
|
+
- WalletConnect (requires `walletConnectProjectId`)
|
|
639
|
+
|
|
640
|
+
**Mobile (non-Dapp browser):**
|
|
641
|
+
- WalletConnect only (requires `walletConnectProjectId`)
|
|
642
|
+
|
|
643
|
+
**Mobile (Dapp browser / wallet app):**
|
|
644
|
+
- Uses injected provider directly
|
|
645
|
+
|
|
646
|
+
To enable WalletConnect in the dialog:
|
|
647
|
+
|
|
648
|
+
```tsx
|
|
649
|
+
<TaskOnProvider
|
|
650
|
+
config={{
|
|
651
|
+
apiKey: "your-api-key",
|
|
652
|
+
walletConnectProjectId: "your-project-id", // Get from cloud.walletconnect.com
|
|
653
|
+
}}
|
|
654
|
+
>
|
|
655
|
+
<App />
|
|
656
|
+
</TaskOnProvider>
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Built-in Wallet Management
|
|
660
|
+
|
|
661
|
+
If no external provider is detected, the widget uses its built-in wallet management. No configuration needed:
|
|
662
|
+
|
|
663
|
+
```tsx
|
|
664
|
+
<TaskOnProvider config={{ apiKey: "your-api-key" }}>
|
|
665
|
+
<App /> {/* Widget handles wallet connection internally */}
|
|
666
|
+
</TaskOnProvider>
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### Configuration Options
|
|
670
|
+
|
|
671
|
+
```typescript
|
|
672
|
+
interface WalletConfig {
|
|
673
|
+
// EVM wallet adapter (highest priority)
|
|
674
|
+
evmAdapter?: WalletAdapter;
|
|
675
|
+
|
|
676
|
+
// Solana wallet adapter (highest priority)
|
|
677
|
+
solanaAdapter?: WalletAdapter;
|
|
678
|
+
|
|
679
|
+
// Disable auto-detection of external providers
|
|
680
|
+
disableAutoDetect?: boolean;
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Custom Wallet Adapter
|
|
685
|
+
|
|
686
|
+
For projects with their own wallet management:
|
|
687
|
+
|
|
688
|
+
```tsx
|
|
689
|
+
// Example: Custom wallet management
|
|
690
|
+
const useCustomWalletAdapter = (): WalletAdapter => {
|
|
691
|
+
const { openWalletModal, connectedAddress, chainId } = useYourWalletManager();
|
|
692
|
+
|
|
693
|
+
return {
|
|
694
|
+
connect: async () => {
|
|
695
|
+
// Open your wallet selection modal, return selected address
|
|
696
|
+
const address = await openWalletModal();
|
|
697
|
+
return address;
|
|
698
|
+
},
|
|
699
|
+
disconnect: async () => {
|
|
700
|
+
await yourDisconnectLogic();
|
|
701
|
+
},
|
|
702
|
+
signMessage: async (message) => {
|
|
703
|
+
return await yourSignMessageLogic(message);
|
|
704
|
+
},
|
|
705
|
+
getAddress: () => connectedAddress,
|
|
706
|
+
getChainId: () => chainId,
|
|
707
|
+
switchNetwork: async (chainId) => {
|
|
708
|
+
await yourSwitchNetworkLogic(chainId);
|
|
709
|
+
},
|
|
710
|
+
};
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
const App = () => {
|
|
714
|
+
const evmAdapter = useCustomWalletAdapter();
|
|
715
|
+
|
|
716
|
+
return (
|
|
717
|
+
<TaskOnProvider
|
|
718
|
+
config={{
|
|
719
|
+
apiKey: "your-api-key",
|
|
720
|
+
walletConfig: { evmAdapter },
|
|
721
|
+
}}
|
|
722
|
+
>
|
|
723
|
+
<YourApp />
|
|
724
|
+
</TaskOnProvider>
|
|
725
|
+
);
|
|
726
|
+
};
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
### Priority Order
|
|
730
|
+
|
|
731
|
+
When multiple options are available:
|
|
732
|
+
|
|
733
|
+
1. **Custom Adapter** - `walletConfig.evmAdapter` / `solanaAdapter` (highest)
|
|
734
|
+
2. **Built-in Adapter** - window.ethereum adapter for EVM wallets (lowest)
|
|
735
|
+
|
|
736
|
+
## Hooks
|
|
737
|
+
|
|
738
|
+
### useTaskOnAuth
|
|
739
|
+
|
|
740
|
+
Access TaskOn authentication with unified login method.
|
|
741
|
+
|
|
742
|
+
```tsx
|
|
743
|
+
import { useTaskOnAuth } from "@taskon/widget-react";
|
|
744
|
+
|
|
745
|
+
const Component = () => {
|
|
746
|
+
const {
|
|
747
|
+
// State
|
|
748
|
+
userId, // TaskOn user ID (number | null)
|
|
749
|
+
isLoggedIn, // Whether user is logged in
|
|
750
|
+
isInitializing, // Whether provider is initializing
|
|
751
|
+
|
|
752
|
+
// Unified login method
|
|
753
|
+
login, // (params: LoginParams) => Promise<void>
|
|
754
|
+
|
|
755
|
+
// Logout
|
|
756
|
+
logout, // () => void
|
|
757
|
+
} = useTaskOnAuth();
|
|
758
|
+
|
|
759
|
+
return <div>TaskOn ID: {userId}</div>;
|
|
760
|
+
};
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
### Login Function
|
|
764
|
+
|
|
765
|
+
```typescript
|
|
766
|
+
// Unified login method
|
|
767
|
+
login: (params: LoginParams) => Promise<void>;
|
|
768
|
+
|
|
769
|
+
// LoginParams
|
|
770
|
+
interface LoginParams {
|
|
771
|
+
method: LoginMethod; // Login method type
|
|
772
|
+
value: string; // Address / email / OAuth token
|
|
773
|
+
sign: string; // Backend signature
|
|
774
|
+
timestamp: number; // Signature timestamp (seconds)
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// Logout
|
|
778
|
+
logout: () => void;
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
### useTaskOnTheme
|
|
782
|
+
|
|
783
|
+
Access current theme. Must be used within ThemeProvider.
|
|
784
|
+
|
|
785
|
+
```tsx
|
|
786
|
+
import { useTaskOnTheme } from "@taskon/widget-react";
|
|
787
|
+
|
|
788
|
+
const Component = () => {
|
|
789
|
+
const theme = useTaskOnTheme();
|
|
790
|
+
|
|
791
|
+
return (
|
|
792
|
+
<div
|
|
793
|
+
style={{
|
|
794
|
+
background: theme.tokens.colorBg,
|
|
795
|
+
color: theme.tokens.colorText,
|
|
796
|
+
padding: theme.tokens.spacingMd,
|
|
797
|
+
borderRadius: theme.tokens.borderRadius,
|
|
798
|
+
}}
|
|
799
|
+
>
|
|
800
|
+
Current mode: {theme.mode}
|
|
801
|
+
</div>
|
|
802
|
+
);
|
|
803
|
+
};
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
### Integration Examples
|
|
807
|
+
|
|
808
|
+
```tsx
|
|
809
|
+
// Example 1: With EVM Wallet
|
|
810
|
+
const EVMWalletIntegration = () => {
|
|
811
|
+
const { evmAddress } = useWallet(); // TaskOn wallet hook
|
|
812
|
+
const { userId, login } = useTaskOnAuth();
|
|
813
|
+
|
|
814
|
+
const handleLogin = async () => {
|
|
815
|
+
if (evmAddress && !userId) {
|
|
816
|
+
// Get signature from your backend
|
|
817
|
+
const { sign, timestamp } = await fetchSignatureFromBackend(evmAddress);
|
|
818
|
+
await login({
|
|
819
|
+
method: "evm_wallet",
|
|
820
|
+
value: evmAddress,
|
|
821
|
+
sign,
|
|
822
|
+
timestamp,
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
useEffect(() => {
|
|
828
|
+
handleLogin();
|
|
829
|
+
}, [evmAddress, userId]);
|
|
830
|
+
|
|
831
|
+
return <div>{userId ? `TaskOn: ${userId}` : "Not logged in"}</div>;
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
// Example 2: With Custom Wallet Adapter
|
|
835
|
+
const CustomWalletIntegration = () => {
|
|
836
|
+
const { evmAddress, connectEvm } = useWallet();
|
|
837
|
+
const { userId, login } = useTaskOnAuth();
|
|
838
|
+
|
|
839
|
+
const handleLogin = async () => {
|
|
840
|
+
if (publicKey && !userId) {
|
|
841
|
+
const address = publicKey.toBase58();
|
|
842
|
+
const { sign, timestamp } = await fetchSignatureFromBackend(address);
|
|
843
|
+
await login({
|
|
844
|
+
method: "solana_wallet",
|
|
845
|
+
value: address,
|
|
846
|
+
sign,
|
|
847
|
+
timestamp,
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
useEffect(() => {
|
|
853
|
+
handleLogin();
|
|
854
|
+
}, [publicKey, userId]);
|
|
855
|
+
|
|
856
|
+
return <div>{userId ? `TaskOn: ${userId}` : "Not logged in"}</div>;
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
// Example 3: Email login
|
|
860
|
+
const EmailLogin = () => {
|
|
861
|
+
const { login } = useTaskOnAuth();
|
|
862
|
+
|
|
863
|
+
const handleEmailLogin = async (email: string) => {
|
|
864
|
+
const { sign, timestamp } = await fetchSignatureFromBackend(email);
|
|
865
|
+
await login({
|
|
866
|
+
method: "email",
|
|
867
|
+
value: email,
|
|
868
|
+
sign,
|
|
869
|
+
timestamp,
|
|
870
|
+
});
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
return (
|
|
874
|
+
<button onClick={() => handleEmailLogin("user@example.com")}>Login</button>
|
|
875
|
+
);
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
// Example 4: Discord OAuth callback
|
|
879
|
+
const DiscordCallback = () => {
|
|
880
|
+
const { login } = useTaskOnAuth();
|
|
881
|
+
|
|
882
|
+
useEffect(() => {
|
|
883
|
+
// After your Discord OAuth flow
|
|
884
|
+
const processOAuth = async () => {
|
|
885
|
+
const oauthToken = getDiscordTokenFromOAuth();
|
|
886
|
+
const { sign, timestamp } = await fetchSignatureFromBackend(oauthToken);
|
|
887
|
+
await login({
|
|
888
|
+
method: "discord",
|
|
889
|
+
value: oauthToken,
|
|
890
|
+
sign,
|
|
891
|
+
timestamp,
|
|
892
|
+
});
|
|
893
|
+
};
|
|
894
|
+
processOAuth();
|
|
895
|
+
}, []);
|
|
896
|
+
|
|
897
|
+
return <div>Processing...</div>;
|
|
898
|
+
};
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
## WalletAdapter Interface
|
|
902
|
+
|
|
903
|
+
For custom wallet integration:
|
|
904
|
+
|
|
905
|
+
```typescript
|
|
906
|
+
interface WalletAdapter {
|
|
907
|
+
// Required
|
|
908
|
+
connect: () => Promise<string>;
|
|
909
|
+
disconnect: () => Promise<void>;
|
|
910
|
+
signMessage: (message: string) => Promise<string>;
|
|
911
|
+
getAddress: () => string | null;
|
|
912
|
+
|
|
913
|
+
// Optional (EVM only)
|
|
914
|
+
getChainId?: () => number | null;
|
|
915
|
+
switchNetwork?: (chainId: number) => Promise<void>;
|
|
916
|
+
|
|
917
|
+
// Optional (Event subscriptions)
|
|
918
|
+
onAccountChange?: (callback: (address: string | null) => void) => () => void;
|
|
919
|
+
onChainChange?: (callback: (chainId: number) => void) => () => void;
|
|
920
|
+
}
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
## Types
|
|
924
|
+
|
|
925
|
+
### TaskOnAuthState
|
|
926
|
+
|
|
927
|
+
```typescript
|
|
928
|
+
interface TaskOnAuthState {
|
|
929
|
+
userId: number | null; // TaskOn user ID (null if not logged in)
|
|
930
|
+
isLoggedIn: boolean; // Whether user is logged in
|
|
931
|
+
isInitializing: boolean; // Whether provider is initializing
|
|
932
|
+
}
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
### LoginParams
|
|
936
|
+
|
|
937
|
+
```typescript
|
|
938
|
+
interface LoginParams {
|
|
939
|
+
method: LoginMethod; // Login method type
|
|
940
|
+
value: string; // Address / email / OAuth token
|
|
941
|
+
sign: string; // Backend signature
|
|
942
|
+
timestamp: number; // Signature timestamp (seconds)
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
type LoginMethod =
|
|
946
|
+
| "evm_wallet"
|
|
947
|
+
| "solana_wallet"
|
|
948
|
+
| "email"
|
|
949
|
+
| "discord"
|
|
950
|
+
| "twitter"
|
|
951
|
+
| "telegram";
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
### TaskOnTheme
|
|
955
|
+
|
|
956
|
+
The resolved theme object returned by `useTaskOnTheme()`:
|
|
957
|
+
|
|
958
|
+
```typescript
|
|
959
|
+
interface TaskOnTheme {
|
|
960
|
+
mode: "light" | "dark";
|
|
961
|
+
compact: boolean;
|
|
962
|
+
|
|
963
|
+
// All tokens are resolved (seed + derived + overrides)
|
|
964
|
+
tokens: {
|
|
965
|
+
// Primary colors
|
|
966
|
+
colorPrimary: string;
|
|
967
|
+
colorPrimaryHover: string;
|
|
968
|
+
colorPrimaryActive: string;
|
|
969
|
+
colorPrimaryBg: string;
|
|
970
|
+
|
|
971
|
+
// Secondary colors
|
|
972
|
+
colorSecondary: string;
|
|
973
|
+
|
|
974
|
+
// Status colors
|
|
975
|
+
colorSuccess: string;
|
|
976
|
+
colorWarning: string;
|
|
977
|
+
colorError: string;
|
|
978
|
+
|
|
979
|
+
// Background
|
|
980
|
+
colorBg: string;
|
|
981
|
+
colorBgElevated: string;
|
|
982
|
+
colorBgSpotlight: string;
|
|
983
|
+
|
|
984
|
+
// Text
|
|
985
|
+
colorText: string;
|
|
986
|
+
colorTextSecondary: string;
|
|
987
|
+
colorTextTertiary: string;
|
|
988
|
+
colorTextDisabled: string;
|
|
989
|
+
|
|
990
|
+
// Border
|
|
991
|
+
colorBorder: string;
|
|
992
|
+
colorBorderSecondary: string;
|
|
993
|
+
|
|
994
|
+
// Layout
|
|
995
|
+
borderRadius: number;
|
|
996
|
+
borderRadiusSm: number;
|
|
997
|
+
borderRadiusLg: number;
|
|
998
|
+
|
|
999
|
+
// Typography
|
|
1000
|
+
fontSize: number;
|
|
1001
|
+
fontSizeSm: number;
|
|
1002
|
+
fontSizeLg: number;
|
|
1003
|
+
fontFamily: string;
|
|
1004
|
+
|
|
1005
|
+
// Spacing
|
|
1006
|
+
spacing: number;
|
|
1007
|
+
spacingXs: number;
|
|
1008
|
+
spacingSm: number;
|
|
1009
|
+
spacingMd: number;
|
|
1010
|
+
spacingLg: number;
|
|
1011
|
+
spacingXl: number;
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
## SSR Compatibility
|
|
1017
|
+
|
|
1018
|
+
This package is SSR-compatible:
|
|
1019
|
+
|
|
1020
|
+
- All components are marked with `'use client'`
|
|
1021
|
+
- Browser APIs are safely wrapped
|
|
1022
|
+
- No hydration mismatches
|
|
1023
|
+
|
|
1024
|
+
Works with:
|
|
1025
|
+
|
|
1026
|
+
- Next.js App Router
|
|
1027
|
+
- Next.js Pages Router
|
|
1028
|
+
- Remix
|
|
1029
|
+
- Other React SSR frameworks
|
|
1030
|
+
|
|
1031
|
+
## Peer Dependencies
|
|
1032
|
+
|
|
1033
|
+
- `react` >= 18.0.0
|
|
1034
|
+
- `react-dom` >= 18.0.0
|
|
1035
|
+
- `@taskon/core` >= 0.0.0
|
|
1036
|
+
|
|
1037
|
+
### Optional Peer Dependencies
|
|
1038
|
+
|
|
1039
|
+
For WalletConnect support in the built-in wallet binding dialog:
|
|
1040
|
+
|
|
1041
|
+
```bash
|
|
1042
|
+
npm install @walletconnect/ethereum-provider @walletconnect/modal
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
Then configure your project ID:
|
|
1046
|
+
|
|
1047
|
+
```tsx
|
|
1048
|
+
<TaskOnProvider
|
|
1049
|
+
config={{
|
|
1050
|
+
apiKey: "your-api-key",
|
|
1051
|
+
walletConnectProjectId: "your-walletconnect-project-id",
|
|
1052
|
+
}}
|
|
1053
|
+
>
|
|
1054
|
+
<App />
|
|
1055
|
+
</TaskOnProvider>
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
Get your WalletConnect Project ID at https://cloud.walletconnect.com
|
|
1059
|
+
|
|
1060
|
+
If not configured, the WalletConnect option will be disabled in the wallet binding dialog.
|
|
1061
|
+
|
|
1062
|
+
## License
|
|
1063
|
+
|
|
1064
|
+
MIT
|