@rockerone/xprnkit 0.4.0 → 0.4.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
@@ -1,86 +1,27 @@
1
- # xprnkit
1
+ # @rockerone/xprnkit
2
2
 
3
- To install dependencies:
4
-
5
- ```bash
6
- bun install
7
- ```
8
-
9
- # XPRNKit:
3
+ > **⚠️ Warning:** Version 0.4.0 introduces breaking changes. Make sure to save your project before migrate.
10
4
 
11
5
  ## Accelerating dApp Development for XPRNetwork
12
6
 
13
7
  XPRNKit is a React-based library designed to streamline decentralized application (dApp) development and prototyping on the XPRNetwork blockchain. It offers a comprehensive set of tools, components, and utilities that enable developers to rapidly build, deploy, and test dApps with minimal setup. By abstracting away much of the underlying complexity of blockchain interactions, XPRNKit empowers developers to focus on core functionality and user experience.
14
8
 
15
- Whether you're creating smart contracts, integrating wallets, or handling token transactions, XPRNKit simplifies common tasks and accelerates the development process. Its perfect for both experienced blockchain developers looking to prototype quickly and newcomers who want to get up and running with XPRNetwork faster.
9
+ Whether you're creating smart contracts, integrating wallets, or handling token transactions, XPRNKit simplifies common tasks and accelerates the development process. It's perfect for both experienced blockchain developers looking to prototype quickly and newcomers who want to get up and running with XPRNetwork faster.
16
10
 
17
11
  ## Key Features
18
12
 
19
13
  - **Pre-built Components**: Ready-to-use UI components for common dApp functionality like wallet connections, token balances, and transaction history.
20
14
  - **Blockchain Integration**: Simplified access to XPRNetwork's blockchain features, reducing the need for extensive configuration.
21
- - **Developer-Friendly Hook**: A simple unique hook to access objects and method to maximizing flexibility.
22
- - **Multi-Session Support**: Connect and manage multiple wallet sessions simultaneously, with easy switching between accounts.
15
+ - **Developer-Friendly Hook**: A simple unique hook to access objects and methods, maximizing flexibility.
16
+ - **Identity Proof**: Built-in wallet signature verification for secure user authentication with JWT token support.
17
+ - **Multi-Account Support**: Connect and switch between multiple wallet accounts, powered by Proton Web SDK session storage.
18
+ - **Token Swap Interface**: Complete swap UI with market provider abstraction and customizable layouts.
23
19
 
24
20
  XPRNKit is the ideal toolkit for developers who want to build and deploy secure, scalable, and user-friendly dApps on XPRNetwork with greater efficiency.
25
21
 
26
22
  ---
27
23
 
28
- ## 0.3.1 Performance Update
29
-
30
- Version 0.3.1 introduces significant performance optimizations to the `XPRNProvider` multi-session management system. The internal state architecture has been refactored to use refs instead of useState for session storage, dramatically reducing unnecessary re-renders.
31
-
32
- ### Performance Gains
33
-
34
- | Scenario | Before | After | Improvement |
35
- |----------|--------|-------|-------------|
36
- | **Single-session usage** | baseline | optimized | **~1.5x faster** |
37
- | **Multi-session (2-3 wallets)** | baseline | optimized | **~3-4x faster** |
38
- | **Heavy multi-session (4+ wallets)** | baseline | optimized | **~5x+ faster** |
39
-
40
- ### Re-render Reduction (3-wallet scenario)
41
-
42
- | Operation | Before | After | Reduction |
43
- |-----------|--------|-------|-----------|
44
- | Connect wallet 1 | 3 re-renders | 2 re-renders | 33% |
45
- | Connect wallet 2 | 2 re-renders | 0 re-renders | 100% |
46
- | Connect wallet 3 | 2 re-renders | 0 re-renders | 100% |
47
- | Profile fetch (active) | 1 re-render | 1 re-render | 0% |
48
- | Profile fetch (non-active) | 1 re-render | 0 re-renders | 100% |
49
- | Authenticate (non-active) | 1 re-render | 0 re-renders | 100% |
50
- | **Total (3-wallet setup)** | **13 re-renders** | **4 re-renders** | **~70%** |
51
-
52
- ### Callback Stability
53
-
54
- All session management callbacks are now stable references:
55
-
56
- | Callback | Dependencies | Stable? |
57
- |----------|--------------|---------|
58
- | `listSessions` | `[]` | ✅ Never recreated |
59
- | `getSessionById` | `[]` | ✅ Never recreated |
60
- | `getSessionByActor` | `[]` | ✅ Never recreated |
61
- | `getAllProfiles` | `[]` | ✅ Never recreated |
62
- | `getActiveSession` | `[]` | ✅ Never recreated |
63
- | `setActiveSession` | `[forceUpdate]` | ✅ Stable |
64
- | `switchSession` | `[setActiveSession]` | ✅ Stable |
65
- | `removeSession` | `[config, forceUpdate]` | ✅ Stable |
66
- | `disconnect` | `[removeSession]` | ✅ Stable |
67
- | `authenticate` | `[config, forceUpdate]` | ✅ Stable |
68
- | `connect` | `[config, forceUpdate]` | ✅ Stable |
69
-
70
- ### Key Optimizations
71
-
72
- - **Ref-based session storage**: Sessions Map is now stored in a ref, eliminating Map recreation on every update
73
- - **Selective re-renders**: Only triggers re-renders when the **active session** data changes
74
- - **Zero re-renders for non-active operations**: Adding/updating non-active sessions doesn't cause re-renders
75
- - **Stable callback references**: Consumer components using these callbacks won't re-render due to callback identity changes
76
-
77
- ### Backward Compatibility
78
-
79
- These optimizations are fully backward compatible. All existing code using `useXPRN()` continues to work without changes.
80
-
81
- ---
82
-
83
- # XPRNProvider and useXPRN Documentation
24
+ # XPRNProvider and useXPRN
84
25
 
85
26
  ## XPRNProvider
86
27
 
@@ -107,10 +48,9 @@ type XPRProviderConfig = {
107
48
  dAppName: string;
108
49
  requesterAccount: string;
109
50
  requesterLogo?: string;
110
- authenticationUrl?: string;
111
- enforceAuthentication?: boolean;
112
51
  apiMode: "testnet" | "mainnet";
113
52
  restoreSession?: boolean;
53
+ identityProof?: XPRNKitIdentityProofConfig;
114
54
  };
115
55
  ```
116
56
 
@@ -119,15 +59,14 @@ type XPRProviderConfig = {
119
59
  - `dAppName`: Your dApp's display name.
120
60
  - `requesterAccount`: Your dApp's account name.
121
61
  - `requesterLogo`: Optional logo URL for your dApp.
122
- - `authenticationUrl`: Optional URL for user authentication endpoint.
123
- - `enforceAuthentication`: If true, automatically authenticates users on connection.
124
- - `apiMode`: Either "testnet" or "mainnet" for different network environments.
62
+ - `apiMode`: Either `"testnet"` or `"mainnet"` for different network environments.
125
63
  - `restoreSession`: If true, restores the last active session on page refresh.
64
+ - `identityProof`: Optional identity proof configuration (see [Identity Proof](#identity-proof) section).
126
65
 
127
66
  ### Usage
128
67
 
129
68
  ```jsx
130
- import {XPRNProvider} from "./path/to/XPRNProvider";
69
+ import { XPRNProvider } from '@rockerone/xprnkit';
131
70
 
132
71
  const config = {
133
72
  chainId: "your-chain-id",
@@ -151,19 +90,18 @@ The `useXPRN` hook provides access to the XPRN context within your React compone
151
90
  ### Usage
152
91
 
153
92
  ```jsx
154
- import {useXPRN} from "./path/to/XPRNProvider";
93
+ import { useXPRN } from '@rockerone/xprnkit';
155
94
 
156
95
  function YourComponent() {
157
96
  const {
158
97
  session,
159
98
  profile,
99
+ identityProof,
100
+ identityProofStatus,
160
101
  connect,
161
102
  disconnect,
162
- authenticate,
163
- // Multi-session methods
164
- listSessions,
165
- setActiveSession,
166
- getActiveSession,
103
+ pushTransaction,
104
+ switchToSession,
167
105
  } = useXPRN();
168
106
 
169
107
  // Use the context values and functions
@@ -174,688 +112,563 @@ function YourComponent() {
174
112
 
175
113
  The `useXPRN` hook returns an object with the following properties:
176
114
 
177
- #### Backward Compatible Properties (Active Session)
115
+ #### State
178
116
 
179
- - `session`: Current active LinkSession object or null.
180
- - `link`: ProtonWebLink object for active session or null.
181
- - `profile`: XPRNProfile object for active session or null.
182
- - `rpc`: JsonRpc object or null.
183
- - `authentication`: XPRNAuthentication object for active session or null.
184
- - `connect`: Function to initiate a connection (newly connected wallet becomes active).
185
- - `disconnect`: Function to disconnect a session (active or specific by actor).
186
- - `authenticate`: Function to authenticate the user using the authentication URL (active session or specific by actor).
187
- - `addTransactionError`: Function to add a transaction error to the stack.
188
-
189
- #### Multi-Session Management Methods
190
-
191
- - `getActiveSession`: Returns the current active session object or null.
192
- - `listSessions`: Returns an array of all connected sessions.
193
- - `setActiveSession`: Switch the active session by actor name.
194
- - `switchSession`: Alias for setActiveSession.
195
- - `removeSession`: Remove a specific session by actor name.
196
- - `getAllProfiles`: Returns an array of all profiles from all connected sessions.
197
- - `getSessionById`: Get a specific session by actor name.
198
- - `getSessionByActor`: Get a specific session by actor name (same as getSessionById).
199
-
200
- ### Key Functions
201
-
202
- #### connect
203
-
204
- ```typescript
205
- connect(
206
- restore?: boolean,
207
- silent?: boolean,
208
- onSession?: (session: LinkSession) => void,
209
- onProfile?: (profile: XPRNProfile) => void
210
- ) => void
211
- ```
117
+ - `config`: `XPRProviderConfig | null` - Current provider configuration.
118
+ - `session`: `LinkSession | null` - Current active session object.
119
+ - `link`: `ProtonWebLink | Link | null` - Proton link object for the active session.
120
+ - `profile`: `XPRNKitProfile | null` - Profile data for the active session.
121
+ - `identityProof`: `XPRNKitIdentityProof | null` - Identity proof for the active session (when identity proof is configured).
122
+ - `identityProofStatus`: `XPRNKitIdentityProofStatus` - Current status of the identity proof process (`"idle"` | `"signing"` | `"verifying"` | `"validating"` | `"success"` | `"expired"` | `"error"`).
212
123
 
213
- Initiates a connection to the WebAuth wallet. The newly connected wallet automatically becomes the active session.
124
+ #### Methods
214
125
 
215
- #### disconnect
126
+ - `connect(restore?: boolean)`: Initiates a connection to the WebAuth wallet. Pass `true` to restore a previous session silently.
127
+ - `disconnect()`: Disconnects the current active session.
128
+ - `pushTransaction(actions: any[])`: Pushes a transaction with the given actions using the active session.
129
+ - `switchToSession(actor: string, permission: string)`: Switches to a different stored session by restoring it from the Proton Web SDK storage.
216
130
 
217
- ```typescript
218
- disconnect(actor?: string) => void
219
- ```
131
+ ### Basic Example
220
132
 
221
- Disconnects a session. If `actor` is provided, disconnects that specific session. Otherwise, disconnects the active session.
133
+ ```jsx
134
+ import { useXPRN } from '@rockerone/xprnkit';
222
135
 
223
- #### authenticate
136
+ function MyComponent() {
137
+ const { session, profile, connect, disconnect } = useXPRN();
224
138
 
225
- ```typescript
226
- authenticate(
227
- success: (res: any) => void,
228
- fail: (e: any) => void,
229
- actor?: string
230
- ) => void
139
+ return (
140
+ <div>
141
+ {session ? (
142
+ <div>
143
+ <p>Logged in as: {profile?.displayName}</p>
144
+ <button onClick={() => disconnect()}>Logout</button>
145
+ </div>
146
+ ) : (
147
+ <button onClick={() => connect()}>Connect</button>
148
+ )}
149
+ </div>
150
+ );
151
+ }
231
152
  ```
232
153
 
233
- Authenticates a user using the provided authentication URL. If `actor` is provided, authenticates that specific session. Otherwise, authenticates the active session.
234
-
235
- ### Multi-Session Management Methods
154
+ ### Transaction Example
236
155
 
237
- #### getActiveSession
156
+ ```jsx
157
+ import { useXPRN } from '@rockerone/xprnkit';
158
+
159
+ function TransferButton() {
160
+ const { session, pushTransaction } = useXPRN();
161
+
162
+ const handleTransfer = async () => {
163
+ if (!session) return;
164
+
165
+ await pushTransaction([
166
+ {
167
+ account: "eosio.token",
168
+ name: "transfer",
169
+ authorization: [session.auth],
170
+ data: {
171
+ from: session.auth.actor.toString(),
172
+ to: "recipient",
173
+ quantity: "1.0000 XPR",
174
+ memo: "Hello!",
175
+ },
176
+ },
177
+ ]);
178
+ };
238
179
 
239
- ```typescript
240
- getActiveSession(): XPRNSession | null
180
+ return <button onClick={handleTransfer}>Send 1 XPR</button>;
181
+ }
241
182
  ```
242
183
 
243
- Returns the complete active session object containing session, link, profile, and authentication data.
184
+ ---
244
185
 
245
- #### listSessions
186
+ # Identity Proof
246
187
 
247
- ```typescript
248
- listSessions(): XPRNSession[]
249
- ```
188
+ Identity Proof allows you to verify that a user owns a specific wallet by having them sign a message. This is useful for authentication flows where you need to confirm a user's identity on your backend.
250
189
 
251
- Returns an array of all connected sessions.
190
+ ## Configuration
252
191
 
253
- #### setActiveSession / switchSession
192
+ Add the `identityProof` configuration to your `XPRProvider`:
254
193
 
255
- ```typescript
256
- setActiveSession(actor: string): void
257
- switchSession(actor: string): void
194
+ ```tsx
195
+ const config = {
196
+ chainId: "your-chain-id",
197
+ endpoints: ["https://your-endpoint.com"],
198
+ dAppName: "MyDApp",
199
+ requesterAccount: "your-requester-account",
200
+ apiMode: "mainnet",
201
+ identityProof: {
202
+ required: true, // When true, identity proof is automatically triggered on connect
203
+ createUrl: "/api/auth/authorize", // Backend endpoint to verify signatures and return a JWT
204
+ validationUrl: "/api/auth/validate", // Backend endpoint to validate existing tokens (optional)
205
+ validationBuffer: 300, // Seconds before expiry to trigger revalidation (optional)
206
+ headers: {}, // Custom headers to send with identity proof requests (optional)
207
+ timeout: 10000, // Request timeout in milliseconds (optional)
208
+ },
209
+ };
258
210
  ```
259
211
 
260
- Switches the active session to the specified actor. Both methods are identical.
261
-
262
- #### removeSession
212
+ ### XPRNKitIdentityProofConfig
263
213
 
264
214
  ```typescript
265
- removeSession(actor: string): Promise<void>
215
+ type XPRNKitIdentityProofConfig = {
216
+ required: boolean;
217
+ createUrl: string;
218
+ validationUrl?: string;
219
+ validationBuffer?: number;
220
+ headers?: Record<string, string>;
221
+ timeout?: number;
222
+ };
266
223
  ```
267
224
 
268
- Removes a specific session by actor name. If the removed session was active, the active session is set to null.
225
+ ## How It Works
269
226
 
270
- #### getAllProfiles
227
+ 1. When `identityProof.required` is `true`, the provider automatically triggers the identity proof flow on wallet connect.
228
+ 2. The provider first checks localStorage for an existing identity proof and validates it via the `validationUrl` (if configured).
229
+ 3. If no valid proof exists, the user is prompted to sign a message in their wallet.
230
+ 4. The signed message is sent to the `createUrl` backend endpoint for verification.
231
+ 5. The backend returns a JWT token which is stored in localStorage and made available via `useXPRN().identityProof`.
271
232
 
272
- ```typescript
273
- getAllProfiles(): XPRNProfile[]
274
- ```
233
+ ## Backend Endpoints
275
234
 
276
- Returns an array of profiles from all connected sessions.
235
+ ### 1. Authorization Endpoint (`createUrl`)
277
236
 
278
- #### getSessionById / getSessionByActor
237
+ Verifies the wallet signature and returns a JWT token:
279
238
 
280
239
  ```typescript
281
- getSessionById(actor: string): XPRNSession | null
282
- getSessionByActor(actor: string): XPRNSession | null
283
- ```
284
-
285
- Retrieves a specific session by actor name. Both methods are identical.
286
-
287
- ## Types
288
-
289
- ### XPRNAuthentication
240
+ // Expected request body
241
+ {
242
+ signer: {
243
+ actor: string;
244
+ permission: string;
245
+ };
246
+ transaction: any;
247
+ signatures: string[];
248
+ chainId: string;
249
+ }
290
250
 
291
- ```typescript
292
- type XPRNAuthentication = {
293
- actor: string;
294
- publicKey: string;
295
- data?: any;
296
- };
251
+ // Response on success
252
+ {
253
+ success: true,
254
+ validated: true,
255
+ actor: string,
256
+ permission: string,
257
+ token: string, // JWT token
258
+ timestamp: string,
259
+ }
297
260
  ```
298
261
 
299
- ### XPRNProfile
300
-
301
- ```typescript
302
- type XPRNProfile = {
303
- displayName: string;
304
- avatar?: string;
305
- authentication?: XPRNAuthentication;
306
- isKyc: boolean;
307
- };
308
- ```
262
+ ### 2. Validation Endpoint (`validationUrl`)
309
263
 
310
- ### XPRNSession
264
+ Validates an existing JWT token:
311
265
 
312
266
  ```typescript
313
- type XPRNSession = {
314
- actor: string;
315
- session: LinkSession;
316
- link: ProtonWebLink | Link;
317
- profile: XPRNProfile | null;
318
- authentication: XPRNAuthentication | null;
319
- };
267
+ // Request: Authorization header with "Bearer <token>" or body { token: string }
268
+
269
+ // Response
270
+ {
271
+ valid: boolean,
272
+ actor?: string,
273
+ expiresAt?: string,
274
+ error?: string,
275
+ }
320
276
  ```
321
277
 
322
- A complete session object that encapsulates all data for a connected wallet.
323
-
324
- ## Multi-Session Support
325
-
326
- XPRNKit now supports managing multiple wallet sessions simultaneously. You can connect multiple wallets, switch between them, and manage each session independently.
278
+ ## Identity Proof Gate Component
327
279
 
328
- ### Key Concepts
280
+ Use `XPRNIdentityProofGate` to conditionally render content based on identity proof status:
329
281
 
330
- - **Active Session**: The currently selected session. All backward-compatible properties (`session`, `link`, `profile`, `authentication`) return data from the active session.
331
- - **Session Identification**: Sessions are uniquely identified by their actor name (e.g., `user1@proton`).
332
- - **Auto-Switch**: When a new wallet is connected, it automatically becomes the active session.
333
- - **Persistence**: Only the active session is persisted and restored on page refresh (when `restoreSession: true` in config).
334
-
335
- ### Multi-Session Usage Examples
336
-
337
- #### Connecting Multiple Wallets
338
-
339
- ```jsx
340
- import {useXPRN} from "xprnkit";
341
-
342
- function MultiWalletComponent() {
343
- const {connect, listSessions, session} = useXPRN();
344
-
345
- const handleConnectWallet = async () => {
346
- await connect();
347
- // Newly connected wallet is now the active session
348
- };
282
+ ```tsx
283
+ import { XPRNIdentityProofGate } from '@rockerone/xprnkit';
349
284
 
285
+ function ProtectedContent() {
350
286
  return (
351
- <div>
352
- <button onClick={handleConnectWallet}>Connect Another Wallet</button>
353
- <p>Active: {session?.auth.actor.toString()}</p>
354
- <p>Total Sessions: {listSessions().length}</p>
355
- </div>
287
+ <XPRNIdentityProofGate
288
+ fallback={<p>Please verify your identity to access this content.</p>}
289
+ loading={<p>Verifying identity...</p>}
290
+ error={<p>Verification failed. Please try again.</p>}
291
+ notConnected={<p>Please connect your wallet first.</p>}
292
+ >
293
+ <p>This content is only visible after identity verification.</p>
294
+ </XPRNIdentityProofGate>
356
295
  );
357
296
  }
358
297
  ```
359
298
 
360
- #### Listing and Switching Sessions
299
+ ### Props
300
+
301
+ | Prop | Type | Description |
302
+ | -------------- | ----------------- | ------------------------------------------------------------------------ |
303
+ | `children` | `React.ReactNode` | Content to render when identity proof is obtained. |
304
+ | `fallback` | `React.ReactNode` | Content to render when identity proof is not obtained (optional). |
305
+ | `loading` | `React.ReactNode` | Content to render while identity proof is in progress (optional). |
306
+ | `error` | `React.ReactNode` | Content to render when identity proof failed (optional, falls back to `fallback`). |
307
+ | `notConnected` | `React.ReactNode` | Content to render when no session is connected (optional, falls back to `fallback`). |
361
308
 
362
- ```jsx
363
- import {useXPRN} from "xprnkit";
309
+ ## useIdentityProofGate Hook
364
310
 
365
- function SessionSwitcher() {
366
- const {listSessions, getActiveSession, setActiveSession} = useXPRN();
311
+ Hook version of the gate component for programmatic access:
367
312
 
368
- const sessions = listSessions();
369
- const activeSession = getActiveSession();
313
+ ```tsx
314
+ import { useIdentityProofGate } from '@rockerone/xprnkit';
370
315
 
371
- return (
372
- <div>
373
- <h3>Connected Wallets</h3>
374
- {sessions.map(session => (
375
- <div key={session.actor}>
376
- <button
377
- onClick={() => setActiveSession(session.actor)}
378
- disabled={activeSession?.actor === session.actor}
379
- >
380
- {session.profile?.displayName || session.actor}
381
- {activeSession?.actor === session.actor && " (Active)"}
382
- </button>
383
- </div>
384
- ))}
385
- </div>
386
- );
316
+ function MyComponent() {
317
+ const {
318
+ isGateActive,
319
+ isConnected,
320
+ isInProgress,
321
+ hasError,
322
+ isVerified,
323
+ shouldRenderChildren,
324
+ needsIdentityProof,
325
+ identityProofStatus,
326
+ } = useIdentityProofGate();
327
+
328
+ if (!shouldRenderChildren) {
329
+ return <p>Verification required</p>;
330
+ }
331
+
332
+ return <p>Verified content</p>;
387
333
  }
388
334
  ```
389
335
 
390
- #### Managing Multiple Sessions
336
+ ## Session Storage
391
337
 
392
- ```jsx
393
- import {useXPRN} from "xprnkit";
338
+ Identity proof tokens are automatically stored in localStorage and restored on session recovery. The token is validated silently when a session is restored, and if invalid, the full authentication flow is triggered again (when `required` is enabled).
394
339
 
395
- function SessionManager() {
396
- const {listSessions, getActiveSession, removeSession, getAllProfiles} =
397
- useXPRN();
340
+ ---
398
341
 
399
- const handleRemoveSession = async (actor: string) => {
400
- await removeSession(actor);
401
- };
342
+ # Multi-Account Support
402
343
 
403
- return (
404
- <div>
405
- <h3>Session Manager</h3>
406
- {listSessions().map(session => (
407
- <div key={session.actor}>
408
- <img
409
- src={session.profile?.avatar}
410
- alt={session.profile?.displayName}
411
- />
412
- <span>{session.profile?.displayName}</span>
413
- <span>{session.actor}</span>
414
- <button onClick={() => handleRemoveSession(session.actor)}>
415
- Remove
416
- </button>
417
- </div>
418
- ))}
419
- </div>
420
- );
421
- }
422
- ```
344
+ XPRNKit supports connecting multiple wallet accounts. Session persistence and restoration is handled by the Proton Web SDK storage layer, while profile data is persisted in localStorage by XPRNKit.
423
345
 
424
- #### Authenticating Specific Sessions
346
+ ### How It Works
425
347
 
426
- ```jsx
427
- import {useXPRN} from "xprnkit";
348
+ - When a user connects a wallet, the session is stored by the Proton Web SDK and the profile is saved in localStorage.
349
+ - The provider maintains one **active session** at a time. The `session`, `link`, `profile`, and `identityProof` properties from `useXPRN()` always return data from the active session.
350
+ - Use `switchToSession(actor, permission)` to switch to a different stored account. This restores the session from the SDK storage.
351
+ - Use the `XPRNAccountList` component to provide a UI for users to switch, add, or remove accounts.
428
352
 
429
- function AuthenticateSession() {
430
- const {authenticate, listSessions} = useXPRN();
353
+ ### Switching Accounts Programmatically
431
354
 
432
- const handleAuthenticateSession = (actor: string) => {
433
- authenticate(
434
- response => {
435
- console.log(`${actor} authenticated successfully`, response);
436
- },
437
- error => {
438
- console.error(`${actor} authentication failed`, error);
439
- },
440
- actor // Authenticate specific session
441
- );
355
+ ```tsx
356
+ import { useXPRN } from '@rockerone/xprnkit';
357
+
358
+ function AccountSwitcher() {
359
+ const { session, switchToSession } = useXPRN();
360
+
361
+ const handleSwitch = async () => {
362
+ await switchToSession("otheraccount", "active");
442
363
  };
443
364
 
444
365
  return (
445
366
  <div>
446
- {listSessions().map(session => (
447
- <div key={session.actor}>
448
- <span>{session.actor}</span>
449
- <span>
450
- {session.authentication ? "✓ Authenticated" : "✗ Not Authenticated"}
451
- </span>
452
- {!session.authentication && (
453
- <button onClick={() => handleAuthenticateSession(session.actor)}>
454
- Authenticate
455
- </button>
456
- )}
457
- </div>
458
- ))}
367
+ <p>Current: {session?.auth.actor.toString()}</p>
368
+ <button onClick={handleSwitch}>Switch to otheraccount</button>
459
369
  </div>
460
370
  );
461
371
  }
462
372
  ```
463
373
 
464
- #### Disconnecting Specific Sessions
374
+ ---
465
375
 
466
- ```jsx
467
- import {useXPRN} from "xprnkit";
376
+ # Components
468
377
 
469
- function DisconnectSession() {
470
- const {disconnect, listSessions, getActiveSession} = useXPRN();
378
+ ## XPRNConnectButton
471
379
 
472
- const handleDisconnect = async (actor?: string) => {
473
- // If actor is provided, disconnect that session
474
- // Otherwise, disconnect active session
475
- await disconnect(actor);
476
- };
380
+ A customizable button for connecting to and disconnecting from a wallet session.
477
381
 
478
- return (
479
- <div>
480
- <button onClick={() => handleDisconnect()}>
481
- Disconnect Active Session
482
- </button>
483
-
484
- {listSessions().map(session => (
485
- <div key={session.actor}>
486
- <span>{session.actor}</span>
487
- <button onClick={() => handleDisconnect(session.actor)}>
488
- Disconnect
489
- </button>
490
- </div>
491
- ))}
492
- </div>
493
- );
494
- }
382
+ ### Import
383
+
384
+ ```typescript
385
+ import { XPRNConnectButton } from '@rockerone/xprnkit';
495
386
  ```
496
387
 
497
- ### Backward Compatibility
388
+ ### Props
389
+
390
+ | Prop | Type | Description |
391
+ | ----------------- | ----------------------------------------------------- | -------------------------------------------------------- |
392
+ | `className` | `string` | Additional CSS classes to apply to the button. |
393
+ | `variant` | `string` | Button variant (style). |
394
+ | `size` | `string` | Button size. |
395
+ | `asChild` | `boolean` | If true, renders the component as a child component. |
396
+ | `children` | `React.ReactNode` | Custom content for the button when not connected. |
397
+ | `onSession` | `(session: LinkSession, link: ProtonWebLink \| Link) => void` | Called when session is established. |
398
+ | `onProfile` | `(profile: XPRNKitProfile) => void` | Called when profile is fetched. |
399
+ | `onIdentityProof` | `(proof: XPRNKitIdentityProof) => void` | Called when identity proof is obtained. |
400
+ | `...props` | `React.ButtonHTMLAttributes<HTMLButtonElement>` | Any other props accepted by HTML button element. |
498
401
 
499
- All existing code continues to work without changes. The `session`, `link`, `profile`, and `authentication` properties always return data from the active session:
402
+ ### Usage
500
403
 
501
404
  ```jsx
502
- // This still works exactly as before
503
- function ExistingComponent() {
504
- const {session, profile, connect, disconnect} = useXPRN();
405
+ import { XPRNConnectButton } from '@rockerone/xprnkit';
505
406
 
506
- // session, profile etc. return active session data
407
+ function MyComponent() {
507
408
  return (
508
- <div>
509
- {session ? (
510
- <div>
511
- <p>Logged in as: {profile?.displayName}</p>
512
- <button onClick={() => disconnect()}>Logout</button>
513
- </div>
514
- ) : (
515
- <button onClick={() => connect()}>Connect</button>
516
- )}
517
- </div>
409
+ <XPRNConnectButton
410
+ className="custom-class"
411
+ onSession={(session, link) => console.log("Connected:", session.auth.actor.toString())}
412
+ onIdentityProof={(proof) => console.log("Identity verified:", proof.auth.actor)}
413
+ >
414
+ Connect Wallet
415
+ </XPRNConnectButton>
518
416
  );
519
417
  }
520
418
  ```
521
419
 
522
- ## Authentication Persistence and SSR
420
+ ### Behavior
523
421
 
524
- ### Overview
422
+ - When there's no active session, the button displays the provided `children` content and triggers the `connect()` function when clicked.
423
+ - When there's an active session, the button displays "Log out (actor)" and triggers the `disconnect()` function when clicked.
525
424
 
526
- XPRNKit automatically restores **wallet sessions** via the `restoreSession` config option, but **authentication data** (tokens, permissions, etc.) is **not automatically persisted** to give you full control over your security model.
425
+ ---
527
426
 
528
- This design is intentional:
529
- - ✅ **Wallet Connection** = Handled by XPRNKit (via Proton Web SDK)
530
- - ❌ **Authentication State** = Your responsibility (localStorage, cookies, server sessions, etc.)
427
+ ## XPRNIdentity
531
428
 
532
- ### Storage Helper Utilities
429
+ Displays user identity information with a dropdown menu and provides session management functionality.
533
430
 
534
- XPRNKit provides optional helper utilities:
431
+ ### Import
535
432
 
536
433
  ```typescript
537
- import { authStorage } from 'xprnkit';
538
-
539
- // Save authentication data
540
- authStorage.save('user@proton', {
541
- actor: 'user@proton',
542
- publicKey: 'PUB_K1_...',
543
- data: { token: 'jwt-token' },
544
- expiresAt: Date.now() + 86400000,
545
- });
546
-
547
- // Load/clear/list
548
- const auth = authStorage.load('user@proton');
549
- authStorage.clear('user@proton');
550
- authStorage.clearAll();
551
- const actors = authStorage.listActors();
434
+ import { XPRNIdentity } from '@rockerone/xprnkit';
552
435
  ```
553
436
 
554
- ### Implementation Patterns
437
+ ### Props
555
438
 
556
- #### Pattern 1: Client-Side (localStorage)
439
+ | Prop | Type | Default | Description |
440
+ | ------------------------ | ----------------------------------------------------- | ------- | -------------------------------------------------------- |
441
+ | `children` | `React.ReactNode` | - | Content to render inside the dropdown menu. |
442
+ | `className` | `string` | - | Additional CSS classes for the root element. |
443
+ | `showLogout` | `boolean` | - | Whether to show a logout link. |
444
+ | `activeSessionClassName` | `string` | - | CSS classes for the active session container. |
445
+ | `dropdownClassName` | `string` | - | CSS classes for the dropdown menu. |
446
+ | `avatarClassName` | `string` | - | CSS classes for the avatar component. |
447
+ | `matchDropdownWidth` | `boolean` | `true` | Match dropdown width to trigger width. |
448
+ | `closeOnSelect` | `boolean` | `true` | Close dropdown when children are clicked. |
449
+ | `onSession` | `(session: LinkSession, link: ProtonWebLink \| Link) => void` | - | Called when session is established. |
450
+ | `onProfile` | `(profile: XPRNKitProfile) => void` | - | Called when profile is fetched. |
451
+ | `onIdentityProof` | `(proof: XPRNKitIdentityProof) => void` | - | Called when identity proof is obtained. |
557
452
 
558
- **Use Case:** Simple apps, prototypes
453
+ ### Usage
559
454
 
560
- ```typescript
561
- import { useXPRN, authStorage } from 'xprnkit';
562
-
563
- function MyApp() {
564
- const { session, authenticate } = useXPRN();
565
-
566
- const handleAuth = () => {
567
- authenticate(
568
- (authData) => {
569
- authStorage.save(session.auth.actor.toString(), {
570
- actor: session.auth.actor.toString(),
571
- publicKey: session.publicKey.toString(),
572
- data: authData,
573
- expiresAt: Date.now() + 86400000,
574
- });
575
- },
576
- (error) => console.error(error)
577
- );
578
- };
455
+ ```jsx
456
+ import { XPRNIdentity } from '@rockerone/xprnkit';
457
+
458
+ function MyComponent() {
459
+ return (
460
+ <XPRNIdentity showLogout={true} avatarClassName="custom-avatar">
461
+ <div>Additional dropdown content</div>
462
+ </XPRNIdentity>
463
+ );
579
464
  }
580
465
  ```
581
466
 
582
- #### Pattern 2: SSR with Cookies (Next.js)
583
-
584
- **Use Case:** Next.js apps, production
467
+ ### Functionality
585
468
 
586
- **Client:**
587
- ```typescript
588
- 'use client';
589
- import { useXPRN } from 'xprnkit';
590
-
591
- function MyApp() {
592
- const { session, authenticate } = useXPRN();
593
-
594
- const handleAuth = () => {
595
- authenticate(
596
- async (authData) => {
597
- await fetch('/api/auth/session', {
598
- method: 'POST',
599
- body: JSON.stringify({ actor: session.auth.actor, authData }),
600
- });
601
- },
602
- (error) => console.error(error)
603
- );
604
- };
605
- }
606
- ```
469
+ 1. If a user session exists:
470
+ - Displays a dropdown menu with the user's avatar and session information
471
+ - Shows the user's name and actor information
472
+ - Optionally displays a logout link
473
+ - Renders any child components in the dropdown content
607
474
 
608
- **Server:**
609
- ```typescript
610
- // app/api/auth/session/route.ts
611
- import { NextResponse } from 'next/server';
612
-
613
- export async function POST(request: Request) {
614
- const body = await request.json();
615
- const response = NextResponse.json({ success: true });
616
-
617
- response.cookies.set('xprn_session', createToken(body), {
618
- httpOnly: true,
619
- secure: process.env.NODE_ENV === 'production',
620
- maxAge: 86400,
621
- });
622
-
623
- return response;
624
- }
625
- ```
475
+ 2. If no user session exists:
476
+ - Displays a "Connect" button using the `XPRNConnectButton` component
626
477
 
627
- #### Pattern 3: Server Sessions (Redis/DB)
478
+ ### Identity Sub-Components
628
479
 
629
- **Use Case:** Scalable production apps
480
+ The following components are also exported and can be used independently:
630
481
 
631
482
  ```typescript
632
- // app/api/session/create/route.ts
633
- import { redis } from '@/lib/redis';
634
- import { randomUUID } from 'crypto';
635
-
636
- export async function POST(request: Request) {
637
- const body = await request.json();
638
- const sessionId = randomUUID();
639
-
640
- await redis.setex(\`session:\${sessionId}\`, 86400, JSON.stringify(body));
641
-
642
- const response = NextResponse.json({ success: true });
643
- response.cookies.set('session_id', sessionId, { httpOnly: true });
644
- return response;
645
- }
483
+ import {
484
+ XPRNAvatar,
485
+ XPRNSessionActor,
486
+ XPRNSessionName,
487
+ } from '@rockerone/xprnkit';
646
488
  ```
647
489
 
648
- ### Comparison
649
-
650
- | Approach | Security | SSR | Best For |
651
- |----------|----------|-----|----------|
652
- | **localStorage** | Medium | ❌ | Client apps |
653
- | **Cookies** | High | ✅ | SSR apps |
654
- | **Server Sessions** | Very High | ✅ | Production |
655
-
656
- ### Full Examples
490
+ - **XPRNAvatar**: Renders the user's profile avatar.
491
+ - **XPRNSessionActor**: Displays the current session's actor (e.g., `user1@active`).
492
+ - **XPRNSessionName**: Displays the current session user's display name.
657
493
 
658
- See the `examples/` directory for complete implementations:
659
- - `auth-localstorage.example.tsx` - Client-side with localStorage
660
- - `auth-cookies-ssr.example.tsx` - SSR with httpOnly cookies
661
- - `auth-server-session.example.tsx` - Server sessions with Redis/PostgreSQL
662
-
663
- # Components Documentation
494
+ ---
664
495
 
665
- # XRPNContainer
496
+ ## XPRNAccountList
666
497
 
667
- `XRPNContainer` is a React component that conditionally renders its children based on the presence of a session.
498
+ Lists all stored accounts and allows switching between them, adding new accounts, and removing existing ones.
668
499
 
669
- ## Import
500
+ ### Import
670
501
 
671
502
  ```typescript
672
- import {XRPNContainer} from "path/to/xprn-container";
503
+ import { XPRNAccountList } from '@rockerone/xprnkit';
673
504
  ```
674
505
 
675
- ## Props
676
-
677
- The `XRPNContainer` component accepts the following props:
506
+ ### Props
678
507
 
679
- | Prop | Type | Description |
680
- | ---------------- | -------------------------- | ----------------------------------------------------------- |
681
- | `children` | `ReactNode \| ReactNode[]` | The content to be rendered when a session is present. |
682
- | `className` | `string` | Optional CSS class name(s) to be applied to the container. |
683
- | `noSessionState` | `ReactNode \| ReactNode[]` | Optional content to be rendered when no session is present. |
508
+ | Prop | Type | Default | Description |
509
+ | --------------------- | --------------------------------------------------------- | -------------- | -------------------------------------------------- |
510
+ | `showRemove` | `boolean` | `false` | Show remove button for each account. |
511
+ | `showAddAccount` | `boolean` | `false` | Show an "Add Account" button. |
512
+ | `addAccountLabel` | `string` | `"Add Account"` | Custom label for the add account button. |
513
+ | `addAccountClassName` | `string` | - | CSS class for the add account button. |
514
+ | `renderItem` | `(props: AccountItemRenderProps) => React.ReactNode` | - | Custom render function for each account item. |
515
+ | `onSelect` | `(entry: XPRNKitProfileStorageEntry) => void` | - | Called when an account is selected. |
516
+ | `onRemove` | `(entry: XPRNKitProfileStorageEntry) => void` | - | Called when an account is removed. |
517
+ | `onAddAccount` | `() => void` | - | Called when the add account button is clicked. |
518
+ | `itemClassName` | `string` | - | CSS class for account items. |
519
+ | `activeClassName` | `string` | - | CSS class for the active account item. |
520
+ | `className` | `string` | - | Additional CSS classes for the root element. |
521
+
522
+ ### AccountItemRenderProps
684
523
 
685
- Additionally, `XRPNContainer` accepts all standard HTML div element attributes.
524
+ ```typescript
525
+ type AccountItemRenderProps = {
526
+ entry: XPRNKitProfileStorageEntry;
527
+ isActive: boolean;
528
+ onSelect: () => void;
529
+ onRemove?: () => void;
530
+ };
531
+ ```
686
532
 
687
- ## Usage
533
+ ### Usage
688
534
 
689
535
  ```jsx
690
- import {XRPNContainer} from "path/to/xprn-container";
536
+ import { XPRNIdentity, XPRNAccountList } from '@rockerone/xprnkit';
691
537
 
692
- function MyComponent() {
538
+ function Navbar() {
693
539
  return (
694
- <XRPNContainer
695
- className="my-custom-class"
696
- noSessionState={<p>Please log in to view content.</p>}
697
- >
698
- <h1>Welcome, user!</h1>
699
- <p>This content is only visible when a session is present.</p>
700
- </XRPNContainer>
540
+ <XPRNIdentity showLogout>
541
+ <XPRNAccountList
542
+ showAddAccount
543
+ showRemove
544
+ onSelect={(entry) => console.log("Switched to:", entry.auth.actor)}
545
+ />
546
+ </XPRNIdentity>
701
547
  );
702
548
  }
703
549
  ```
704
550
 
705
- ## Behavior
706
-
707
- - If a session is present (determined by the `useXPRN` hook), the component renders its `children`.
708
- - If no session is present, the component renders the `noSessionState` content if provided, otherwise it renders nothing.
709
-
710
- ## Dependencies
551
+ ### Behavior
711
552
 
712
- - React
713
- - `useXPRN` hook from "../providers/XPRNProvider"
553
+ - Reads stored profiles from localStorage and displays them as a list.
554
+ - The active account is highlighted with a checkmark.
555
+ - Clicking an account calls `switchToSession` to restore that session.
556
+ - The "Add Account" button triggers a new wallet connection via `connect()`.
557
+ - Each account item shows the avatar, display name, actor, KYC badge, and identity proof badge.
714
558
 
715
- ## Notes
716
-
717
- - This component uses the "use client" directive, indicating it's designed for client-side rendering in Next.js applications.
718
- - The component leverages the `useXPRN` hook to determine the session state.
559
+ ---
719
560
 
720
- # XPRNConnectButton
561
+ ## XRPNContainer / XPRNLogged / XPRNUnlogged
721
562
 
722
- The `XPRNConnectButton` is a React component that provides a customizable button for connecting to and disconnecting from an XPRN session.
563
+ Conditional rendering components based on the presence of a session.
723
564
 
724
- ## Import
565
+ ### Import
725
566
 
726
567
  ```typescript
727
- import {XPRNConnectButton} from "packages/xprnkit/src/components/xprn-session";
568
+ import { XRPNContainer, XPRNLogged, XPRNUnlogged } from '@rockerone/xprnkit';
728
569
  ```
729
570
 
730
- ## Props
731
-
732
- The `XPRNConnectButton` accepts the following props:
571
+ ### XRPNContainer
733
572
 
734
- | Prop | Type | Description |
735
- | ----------- | ----------------------------------------------- | ------------------------------------------------------------------------------- |
736
- | `className` | `string` | Additional CSS classes to apply to the button |
737
- | `variant` | `string` | Button variant (style) |
738
- | `size` | `string` | Button size |
739
- | `asChild` | `boolean` | If true, renders the component as a child component |
740
- | `onClick` | `function` | Custom click handler (Note: internal connect/disconnect logic will still apply) |
741
- | `children` | `React.ReactNode` | Custom content for the button when not connected |
742
- | `...props` | `React.ButtonHTMLAttributes<HTMLButtonElement>` | Any other props accepted by HTML button element |
573
+ Renders `children` when a session is present, or `noSessionState` content otherwise.
743
574
 
744
- ## Usage
575
+ | Prop | Type | Description |
576
+ | ---------------- | -------------------------- | ----------------------------------------------------------- |
577
+ | `children` | `ReactNode \| ReactNode[]` | Content to render when a session is present. |
578
+ | `className` | `string` | Optional CSS class name(s). |
579
+ | `noSessionState` | `ReactNode \| ReactNode[]` | Content to render when no session is present. |
745
580
 
746
581
  ```jsx
747
- import {XPRNConnectButton} from "packages/xprnkit/src/components/xprn-session";
748
-
749
- function MyComponent() {
750
- return (
751
- <XPRNConnectButton variant="primary" size="medium" className="custom-class">
752
- Connect to XPRN
753
- </XPRNConnectButton>
754
- );
755
- }
582
+ <XRPNContainer noSessionState={<p>Please log in.</p>}>
583
+ <p>Welcome! You are connected.</p>
584
+ </XRPNContainer>
756
585
  ```
757
586
 
758
- ## Behavior
759
-
760
- - When there's no active session, the button displays the provided `children` content and triggers the `connect()` function when clicked.
761
- - When there's an active session, the button displays "Log out (actor)" and triggers the `disconnect()` function when clicked.
587
+ ### XPRNLogged
762
588
 
763
- ## Notes
589
+ Renders its children **only** when a session is present.
764
590
 
765
- - The component uses the `useXPRN` hook to access the current session state and connect/disconnect functions.
591
+ ```jsx
592
+ <XPRNLogged>
593
+ <p>This is only visible when connected.</p>
594
+ </XPRNLogged>
595
+ ```
766
596
 
767
- # XPRNIdentity Component
597
+ ### XPRNUnlogged
768
598
 
769
- ## Overview
599
+ Renders its children **only** when no session is present.
770
600
 
771
- The `XPRNIdentity` component is a React functional component that displays user identity information and provides session management functionality
601
+ ```jsx
602
+ <XPRNUnlogged>
603
+ <p>Please connect your wallet to continue.</p>
604
+ </XPRNUnlogged>
605
+ ```
772
606
 
773
- ## Props
607
+ ---
774
608
 
775
- The component accepts the following props:
609
+ ## XPRNTransaction
776
610
 
777
- - `children`: React nodes to be rendered inside the dropdown menu (optional)
778
- - `className`: Additional CSS classes for the root element (optional)
779
- - `showLogout`: Boolean to determine if the logout link should be displayed (optional)
780
- - `activeSessionClassName`: Additional CSS classes for the active session container (optional)
781
- - `dropdownClassName`: Additional CSS classes for the dropdown menu (optional)
782
- - `avatarClassName`: Additional CSS classes for the avatar component (optional)
611
+ A button component that pushes a blockchain transaction using the active session.
783
612
 
784
- ## Functionality
613
+ ### Import
785
614
 
786
- 1. If a user session exists:
615
+ ```typescript
616
+ import { XPRNTransaction } from '@rockerone/xprnkit';
617
+ ```
787
618
 
788
- - Displays a dropdown menu with the user's avatar and session information
789
- - Shows the user's name and actor information
790
- - Optionally displays a logout link
791
- - Renders any child components in the dropdown content
619
+ ### Props
792
620
 
793
- 2. If no user session exists:
794
- - Displays a "Connect" button using the `XPRNConnectButton` component
621
+ | Prop | Type | Description |
622
+ | ---------------------- | --------------------------------- | -------------------------------------------------------- |
623
+ | `actions` | `any[]` | Array of transaction actions to push. |
624
+ | `onTransactionStart` | `() => void` | Called when the transaction starts (optional). |
625
+ | `onTransactionSuccess` | `(res: TransactResult) => void` | Called when the transaction succeeds (optional). |
626
+ | `onTransactionFail` | `(e: any) => void` | Called when the transaction fails (optional). |
627
+ | `className` | `string` | Additional CSS classes. |
628
+ | `variant` | `string` | Button variant (style). |
629
+ | `size` | `string` | Button size. |
630
+ | `asChild` | `boolean` | If true, renders as a child component. |
631
+ | `children` | `React.ReactNode` | Button label content. |
795
632
 
796
- ## Usage
633
+ ### Usage
797
634
 
798
635
  ```jsx
799
- import {XPRNIdentity} from "path/to/xprn-identity";
636
+ import { XPRNTransaction } from '@rockerone/xprnkit';
800
637
 
801
- function MyComponent() {
638
+ function SwapButton({ actions }) {
802
639
  return (
803
- <XPRNIdentity showLogout={true} avatarClassName="custom-avatar">
804
- <div>Additional dropdown content</div>
805
- </XPRNIdentity>
640
+ <XPRNTransaction
641
+ actions={actions}
642
+ onTransactionSuccess={(res) => console.log("Success:", res)}
643
+ onTransactionFail={(err) => console.error("Failed:", err)}
644
+ >
645
+ Swap
646
+ </XPRNTransaction>
806
647
  );
807
648
  }
808
649
  ```
809
650
 
810
- ## Notes
811
-
812
- - The component is wrapped in a "use client" directive, indicating it's designed for client-side rendering.
813
- - It uses the `useXPRN` hook to access session information and the `disconnect` function.
814
- - The logout functionality is implemented using the `disconnect` function from the XPRN context.
651
+ ### Behavior
815
652
 
816
- ## Identity sub components
653
+ - When no session is present, displays a "Connect" button that triggers wallet connection.
654
+ - When a session is present, clicking the button pushes the transaction.
655
+ - Automatically shows loading spinner during transaction and success/fail states after completion.
817
656
 
818
- The following components are used inside XPRNIdentity:
819
-
820
- 1. **XPRNAvatar**
821
-
822
- - Exported from: `'./xprn-avatar'`
823
- - Description: A component for rendering user avatars or profile pictures.
824
-
825
- 2. **XPRNSessionActor**
826
-
827
- - Exported from: `'./xprn-session-actor'`
828
- - Description: Related to the current session's active user or actor.
829
-
830
- 3. **XPRNSessionName**
831
- - Exported from: `'./xprn-session-name'`
832
- - Description: For displaying the current session user's name.
833
-
834
- ## Usage
835
-
836
- To use these components in your project, you can import them from this file:
657
+ ---
837
658
 
838
- ```typescript
839
- import {
840
- XPRNAvatar,
841
- XPRNSessionActor,
842
- XPRNSessionName,
843
- } from "xprnkit/src/components/identity";
844
- ```
659
+ # Swap Components
845
660
 
846
- # XPRNSwap Component
661
+ ## XPRNSwap
847
662
 
848
- The `XPRNSwap` component is a React functional component that provides a user interface for XPR Network tokens swapping functionality out of the box.
663
+ The `XPRNSwap` component provides a complete token swap interface out of the box.
849
664
 
850
- ## Import
665
+ ### Import
851
666
 
852
667
  ```typescript
853
- import {XPRNSwap} from "packages/xprnkit/src/components/swap/xprn-swap";
668
+ import { XPRNSwap } from '@rockerone/xprnkit';
854
669
  ```
855
670
 
856
- ## Props
857
-
858
- The `XPRNSwap` component accepts the following props:
671
+ ### Props
859
672
 
860
673
  | Prop | Type | Description |
861
674
  | ----------- | ------------------------------- | ----------------------------------------------------------- |
@@ -865,38 +678,44 @@ The `XPRNSwap` component accepts the following props:
865
678
  | `className` | `string` | Optional. Additional CSS classes to apply to the component. |
866
679
  | `children` | `React.ReactNode` | Optional. Child elements to render within the component. |
867
680
 
868
- Additionally, the component accepts all standard HTML attributes for a `div` element.
869
-
870
- ## Usage
681
+ ### Usage
871
682
 
872
- ### Basic
683
+ #### Basic
873
684
 
874
685
  ```jsx
875
686
  <XPRNSwap />
876
687
  ```
877
688
 
878
- ### With config
689
+ #### With config
879
690
 
880
691
  ```jsx
881
692
  <XPRNSwap
882
- filters={...}
883
- sides={['buy', 'sell']}
884
- markets={['market1', 'market2']}
885
- className="custom-class"
693
+ filters={{ quoteSymbol: "XUSDC" }}
694
+ sides={['buy', 'sell']}
695
+ className="custom-class"
886
696
  />
887
697
  ```
888
698
 
889
- ### Customs using `XPRNSwapProvider`
699
+ #### Custom layout using `XPRNSwapProvider`
890
700
 
891
701
  ```jsx
702
+ import {
703
+ XPRNSwapProvider,
704
+ XPRNPairsSelector,
705
+ XPRNSwapFieldsGroup,
706
+ XPRNSwapField,
707
+ XPRNSwapSideButton,
708
+ XPRNTransaction,
709
+ } from '@rockerone/xprnkit';
710
+
892
711
  <XPRNSwapProvider
893
- config={{filters: {quoteSymbol: "SNIPS", baseSymbol: "XUSDC"}}}
712
+ config={{ filters: { quoteSymbol: "SNIPS", baseSymbol: "XUSDC" } }}
894
713
  >
895
- <div className="p4 bg-green-400 grid grid-cols-[1fr,min-content] gap-6 p-4 w-full">
714
+ <div className="grid grid-cols-[1fr,min-content] gap-6 p-4 w-full">
896
715
  <XPRNPairsSelector />
897
716
  <XPRNSwapFieldsGroup horizontal className="w-full">
898
717
  <XPRNSwapField />
899
- <XPRNSwapSideButton horizontal>Yo!</XPRNSwapSideButton>
718
+ <XPRNSwapSideButton horizontal>Swap</XPRNSwapSideButton>
900
719
  <XPRNSwapField />
901
720
  </XPRNSwapFieldsGroup>
902
721
  <XPRNTransaction>Swap</XPRNTransaction>
@@ -904,41 +723,34 @@ className="custom-class"
904
723
  </XPRNSwapProvider>
905
724
  ```
906
725
 
907
- ## Behavior
726
+ ### Behavior
908
727
 
909
728
  1. The component wraps its content in an `XPRNSwapProvider` to provide context for swap-related data and functionality.
910
729
  2. It renders an `XPRNSwapLayout` component within the provider.
911
730
  3. The component applies a default grid layout with padding and border styling.
912
- 4. Custom CSS classes can be added via the `className` prop.
913
-
914
- ## Dependencies
915
-
916
- - XPRNSwapProvider
917
- - XPRNSwapLayout
918
-
919
- ## Notes
731
+ 4. Alternatively, you can rebuild the entire swap layout using the sub-components wrapped in a `XPRNSwapProvider`.
920
732
 
921
- - Alternatively, XPRNSwap component allow you to rebuild the entire swap component layout the way you want by using it's sub components wrapped in a `XPRNSwapProvider`
733
+ ---
922
734
 
923
- # XPRNSwapProvider
735
+ ## XPRNSwapProvider
924
736
 
925
- The `XPRNSwapProvider` is a React component that provides context for managing cryptocurrency swap operations.
737
+ The `XPRNSwapProvider` is a React component that provides context for managing swap operations.
926
738
 
927
- ## Usage
739
+ ### Usage
928
740
 
929
741
  ```jsx
930
- import { XPRNSwapProvider } from 'path/to/xprn-swap-provider';
742
+ import { XPRNSwapProvider } from '@rockerone/xprnkit';
931
743
 
932
744
  function App() {
933
745
  return (
934
746
  <XPRNSwapProvider config={/* optional config */}>
935
- {/* Your app components and XPRNKit swap sub components */}
747
+ {/* Your swap sub-components */}
936
748
  </XPRNSwapProvider>
937
749
  );
938
750
  }
939
751
  ```
940
752
 
941
- ## Props
753
+ ### Props
942
754
 
943
755
  | Prop | Type | Description |
944
756
  | ---------- | -------------------------------------- | ---------------------------------------------- |
@@ -953,9 +765,18 @@ function App() {
953
765
  | `marketFilters` | `string[]` (optional) | Filters for specific markets |
954
766
  | `sides` | `XPRNSwapSide[]` (optional) | Available swap sides (e.g., "buy", "sell") |
955
767
 
956
- ## Context
768
+ ### Context (useXPRNSwap)
769
+
770
+ The `useXPRNSwap` hook provides access to the swap context:
771
+
772
+ ```jsx
773
+ import { useXPRNSwap } from '@rockerone/xprnkit';
957
774
 
958
- The `XPRNSwapProvider` creates a context with the following properties and methods:
775
+ function SwapComponent() {
776
+ const { currentSwapPair, swapSide, setSwapSide } = useXPRNSwap();
777
+ // ...
778
+ }
779
+ ```
959
780
 
960
781
  | Property/Method | Type | Description |
961
782
  | -------------------------- | ----------------------------------------------------------------------- | ------------------------------------------- |
@@ -968,7 +789,7 @@ The `XPRNSwapProvider` creates a context with the following properties and metho
968
789
  | `setCurrentSwapPair` | `(pair: XPRNMarketProviderResult) => void` | Function to set the current swap pair |
969
790
  | `currentSwapPair` | `XPRNMarketProviderResult \| null` | Currently selected swap pair |
970
791
  | `swapTransaction` | `any[]` | Current swap transaction details |
971
- | `swapSide` | `XPRNSwapSide` | Current swap side (e.g., "buy" or "sell") |
792
+ | `swapSide` | `XPRNSwapSide` | Current swap side ("buy" or "sell") |
972
793
  | `setSwapSide` | `(value: XPRNSwapSide) => void` | Function to set the swap side |
973
794
  | `swapVolume` | `number` | Current swap volume |
974
795
  | `setSwapVolume` | `(value: number) => void` | Function to set the swap volume |
@@ -976,47 +797,25 @@ The `XPRNSwapProvider` creates a context with the following properties and metho
976
797
  | `swapValues` | `XPRNSwapValues` | Current swap values |
977
798
  | `updateSwapValues` | `(base: number, quote: number, lastMutated: "base" \| "quote") => void` | Function to update swap values |
978
799
 
979
- ## Hook
980
-
981
- The `useXPRNSwap` hook can be used to access the `XPRNSwapProvider` context in child components.
800
+ ### Notes
982
801
 
983
- ### Usage
984
-
985
- ```jsx
986
- import { useXPRNSwap } from 'path/to/xprn-swap-provider';
987
-
988
- function SwapComponent() {
989
- const { currentSwapPair, swapSide, setSwapSide } = useXPRNSwap();
990
-
991
- // Use the context values and methods
992
- // ...
993
-
994
- return (
995
- // Your component JSX
996
- );
997
- }
998
- ```
999
-
1000
- ## Notes
1001
-
1002
- - The provider fetches market pairs from the selected market provider's endpoint (currently Alcor is the only supported exchange). You can edit or add new provider using the `XPRNMarketProvider` interface.
802
+ - The provider fetches market pairs from the selected market provider's endpoint (currently Alcor is the only supported exchange). You can add new providers using the `XPRNMarketProvider` interface.
1003
803
  - It manages the state of the current swap, including the selected pair, swap side, and volume.
1004
804
  - The provider automatically updates swap transactions when relevant values change.
1005
- - Error handling is implemented for network requests and configuration issues.
1006
805
 
1007
- # XPRNSwapFieldsGroup
806
+ ---
807
+
808
+ ## XPRNSwapFieldsGroup
1008
809
 
1009
- The `XPRNSwapFieldsGroup` is a React component that provides a flexible container for grouping swap fields in the XPRN swap interface. It's a utility component that flip swap fields position according to side (buy or sell)
810
+ A flexible container for grouping swap fields that flips field positions according to the swap side (buy or sell).
1010
811
 
1011
- ## Import
812
+ ### Import
1012
813
 
1013
814
  ```typescript
1014
- import {XPRNSwapFieldsGroup} from "packages/xprnkit/src/components/swap/xprn-swap-fields-group";
815
+ import { XPRNSwapFieldsGroup } from '@rockerone/xprnkit';
1015
816
  ```
1016
817
 
1017
- ## Props
1018
-
1019
- The component accepts the following props:
818
+ ### Props
1020
819
 
1021
820
  | Prop | Type | Default | Description |
1022
821
  | ------------ | ----------------- | ----------- | --------------------------------------------------------- |
@@ -1024,229 +823,181 @@ The component accepts the following props:
1024
823
  | `className` | `string` | `undefined` | Additional CSS classes to be applied to the root element. |
1025
824
  | `horizontal` | `boolean` | `false` | Determines if the fields should be arranged horizontally. |
1026
825
 
1027
- Additionally, the component accepts all standard HTML div element attributes.
1028
-
1029
- ## Usage
1030
-
1031
- ```jsx
1032
- import {XPRNSwapFieldsGroup} from "packages/xprnkit/src/components/swap/xprn-swap-fields-group";
1033
-
1034
- function SwapInterface() {
1035
- return (
1036
- <XPRNSwapFieldsGroup horizontal={true} className="custom-class">
1037
- {/* Swap field components go here */}
1038
- </XPRNSwapFieldsGroup>
1039
- );
1040
- }
1041
- ```
1042
-
1043
- ## Behavior
826
+ ### Behavior
1044
827
 
1045
- - The component uses the `useXPRNSwap` hook to access the current swap configuration.
1046
- - It dynamically applies CSS classes based on the `horizontal` prop and the current `swapSide`.
1047
828
  - The layout of child components is reversed when `swapSide` is "sell".
1048
- - The component supports both vertical (default) and horizontal layouts.
829
+ - Supports both vertical (default) and horizontal layouts.
830
+
831
+ ---
1049
832
 
1050
- # XPRNSwapSideButton
833
+ ## XPRNSwapField
1051
834
 
1052
- The `XPRNSwapSideButton` is a React component that provides a button for switching between "buy" and "sell" sides in a swap interface.
835
+ An input field for entering the amount of tokens to swap, for either the base or quote currency.
1053
836
 
1054
- ## Import
837
+ ### Import
1055
838
 
1056
839
  ```typescript
1057
- import {XPRNSwapSideButton} from "path/to/xprn-swap-side-button";
840
+ import { XPRNSwapField } from '@rockerone/xprnkit';
1058
841
  ```
1059
842
 
1060
- ## Props
1061
-
1062
- The component accepts the following props:
1063
-
1064
- | Prop | Type | Default | Description |
1065
- | ------------ | ----------------- | ----------- | --------------------------------------------------------------------------------------------- |
1066
- | `horizontal` | `boolean` | `false` | Determines the orientation of the swap icon. If `true`, a horizontal arrow icon is displayed. |
1067
- | `children` | `React.ReactNode` | `undefined` | Custom content to be rendered inside the button. If not provided, a default icon is used. |
1068
- | `className` | `string` | `undefined` | Additional CSS classes to be applied to the button. |
843
+ ### Props
1069
844
 
1070
- The component also accepts all standard HTML attributes for a `div` element.
845
+ - `type`: `"quote" | "base"` - Indicates whether this field is for the quote or base currency.
846
+ - `className`: Optional string for additional CSS classes.
1071
847
 
1072
- ## Usage
848
+ Must be wrapped in a `XPRNSwapProvider`.
1073
849
 
1074
- ```jsx
1075
- import {XPRNSwapSideButton} from "path/to/xprn-swap-side-button";
850
+ ### Usage
1076
851
 
1077
- function SwapInterface() {
1078
- return (
1079
- <div>
1080
- {/* Other swap interface components */}
1081
- <XPRNSwapSideButton horizontal={true} className="custom-class" />
1082
- </div>
1083
- );
1084
- }
852
+ ```tsx
853
+ <XPRNSwapField type="base" className="custom-class" />
1085
854
  ```
1086
855
 
1087
- ## Behavior
1088
-
1089
- - The button toggles between "buy" and "sell" sides when clicked.
1090
- - It uses the `useXPRNSwap` hook to access and modify the swap state.
1091
- - The button is not rendered if the swap configuration only has one side.
1092
- - The button has a hover effect that rotates it 180 degrees.
1093
-
1094
- ## Customization
1095
-
1096
- - You can provide custom content by passing children to the component.
1097
- - The default icon can be overridden by passing custom JSX as children.
1098
- - Additional styling can be applied using the `className` prop.
1099
-
1100
- ## Notes
1101
-
1102
- - The component is wrapped with `"use client"` directive, indicating it's a Client Component in Next.js.
1103
- - It uses React hooks (`useCallback`, `useMemo`) for performance optimization.
1104
-
1105
- # XPRNSwapField Component
1106
-
1107
- ## Overview
1108
-
1109
- The `XPRNSwapField` is a React component used in a the `XPRNSwap` interface. It provides an input field for users to enter the amount of tokens they want to swap, either for the base or quote currency of a trading pair. This component should be wrapped in a `XPRNSwapProvider`
1110
-
1111
- ## Props
1112
-
1113
- The component accepts the following props:
1114
-
1115
- - `type`: A string, either "quote" or "base", indicating whether this field is for the quote or base currency.
1116
- - `className`: An optional string for additional CSS classes.
1117
- - `children`: Optional child elements (not used in the current implementation).
856
+ ---
1118
857
 
1119
- It also accepts any other props that can be applied to a `div` element.
858
+ ## XPRNSwapSideButton
1120
859
 
1121
- ## Usage
860
+ A button for switching between "buy" and "sell" sides in the swap interface.
1122
861
 
1123
- ```tsx
1124
- import {XPRNSwapField} from "./path/to/xprn-swap-field";
862
+ ### Import
1125
863
 
1126
- <XPRNSwapField type="base" className="custom-class" />;
864
+ ```typescript
865
+ import { XPRNSwapSideButton } from '@rockerone/xprnkit';
1127
866
  ```
1128
867
 
1129
- ## Styling
1130
-
1131
- The component uses CSS classes for styling, including conditional classes based on the `className` prop and predefined classes for the input field.
1132
-
1133
- # XPRNSwapMarketsSelector
1134
-
1135
- ## Overview
868
+ ### Props
1136
869
 
1137
- `XPRNSwapMarketsSelector` is a React functional component that renders a dropdown selector for swap market providers. It uses the `Select` component from a UI library and populates it with market providers from the `useXPRNSwap` hook. The component must be wrapped in a `XPRNSwapProvider` in order to be fed by markets config provided through `XPRNSwapProvider` config.
870
+ | Prop | Type | Default | Description |
871
+ | ------------ | ----------------- | ----------- | ---------------------------------------------------------------------------------- |
872
+ | `horizontal` | `boolean` | `false` | If `true`, displays a horizontal arrow icon. |
873
+ | `children` | `React.ReactNode` | `undefined` | Custom content inside the button. If not provided, a default arrow icon is used. |
874
+ | `className` | `string` | `undefined` | Additional CSS classes. |
1138
875
 
1139
- ## Props
876
+ ### Behavior
1140
877
 
1141
- The component accepts the following props:
878
+ - Toggles between "buy" and "sell" sides when clicked.
879
+ - Not rendered if the swap configuration only has one side.
880
+ - Has a hover effect that rotates the icon 180 degrees.
1142
881
 
1143
- - `children`: React node (optional)
1144
- - `className`: string (optional)
882
+ ---
1145
883
 
1146
- These props are extended from `React.HTMLAttributes<HTMLDivElement>`.
884
+ ## XPRNSwapMarketsSelector
1147
885
 
1148
- ## Usage
886
+ A dropdown selector for swap market providers. Must be wrapped in a `XPRNSwapProvider`.
1149
887
 
1150
- ```tsx
1151
- import {XPRNSwapMarketsSelector} from "path/to/xprn-swap-markets-selector";
888
+ ### Import
1152
889
 
1153
- function MyComponent() {
1154
- return <XPRNSwapMarketsSelector className="custom-class" />;
1155
- }
890
+ ```typescript
891
+ import { XPRNSwapMarketsSelector } from '@rockerone/xprnkit';
1156
892
  ```
1157
893
 
1158
- ## Functionality
1159
-
1160
- 1. The component uses the `useXPRNSwap` hook to get `marketProviders`.
1161
- 2. It initializes `services` state with `useState`.
1162
- 3. `defaultServices` are memoized using `useMemo` and set to `DEFAULT_SWAP_SERVICES`.
1163
- 4. `defaultService` is memoized to find the first service marked as default or the first service in the list.
1164
- 5. The component renders a `Select` component
1165
-
1166
- ## Conditional Rendering
894
+ ### Props
1167
895
 
1168
- The component only renders if there is more than one market provider (`marketProviders.length > 1`).
896
+ - `className`: Optional string for additional CSS classes.
1169
897
 
1170
- ## Styling
898
+ Only renders if there is more than one market provider available.
1171
899
 
1172
- The component uses `classNames` for conditional class application. The root `div` element receives the `className` prop if provided.
900
+ ---
1173
901
 
1174
- # XPRNPairsSelector Component
902
+ ## XPRNPairsSelector
1175
903
 
1176
- The `XPRNPairsSelector` is a React component that provides a dropdown selector for available (filtered or not) trading pairs form the selected market provider. It's designed to work within the context of an `XPRNSwapProvider`.
904
+ A dropdown selector for available trading pairs from the selected market provider. Must be wrapped in a `XPRNSwapProvider`.
1177
905
 
1178
- ## Import Statement
906
+ ### Import
1179
907
 
1180
908
  ```typescript
1181
- import * as React from "react";
1182
- import classNames from "classnames";
1183
- import {useXPRNSwap} from "./xprn-swap-provider";
1184
- import {
1185
- Select,
1186
- SelectItem,
1187
- SelectContent,
1188
- SelectTrigger,
1189
- SelectValue,
1190
- } from "../ui/select";
909
+ import { XPRNPairsSelector } from '@rockerone/xprnkit';
1191
910
  ```
1192
911
 
1193
- ## Props
1194
-
1195
- The component accepts the following props:
1196
-
1197
- - `className?: string`: Additional CSS classes for the root element.
1198
- - `contentClassName?: string`: Additional CSS classes for the dropdown content.
1199
- - `itemsClassName?: string`: Additional CSS classes for the dropdown items.
912
+ ### Props
1200
913
 
1201
- These props extend the standard `HTMLDivElement` attributes.
914
+ - `className`: Optional CSS classes for the root element.
915
+ - `contentClassName`: Optional CSS classes for the dropdown content.
916
+ - `itemsClassName`: Optional CSS classes for the dropdown items.
1202
917
 
1203
- ## Functionality
918
+ ### Behavior
1204
919
 
1205
- 1. The component uses the `useXPRNSwap` hook to access swap-related data and functions.
1206
- 2. It displays a dropdown of available trading pairs when the loaded by the `XPRNSwapProvider` from the default or selected market provider.
1207
- 3. Users can select a trading pair, which updates the current swap pair inside the `XPRNSwapProvider`.
1208
- 4. The component shows loading and error states based on the `XPRNSwapProvider` loading status of the pair list.
920
+ - Displays available trading pairs from the current market provider.
921
+ - Shows loading and error states based on the pair list fetch status.
922
+ - Does not render if there is only one or zero pairs available.
1209
923
 
1210
- ## Usage
924
+ ---
1211
925
 
1212
- ```tsx
1213
- <XPRNPairsSelector
1214
- className="custom-class"
1215
- contentClassName="content-class"
1216
- itemsClassName="item-class"
1217
- />
1218
- ```
926
+ # Types Reference
1219
927
 
1220
- ## Render Logic
928
+ ```typescript
929
+ type XPRProviderConfig = {
930
+ chainId: string;
931
+ endpoints: string[];
932
+ dAppName: string;
933
+ requesterAccount: string;
934
+ requesterLogo?: string;
935
+ apiMode: "testnet" | "mainnet";
936
+ restoreSession?: boolean;
937
+ identityProof?: XPRNKitIdentityProofConfig;
938
+ };
1221
939
 
1222
- - If loading of the is "idle":
1223
- - Renders a `Select` component with the current pairs as options.
1224
- - If loading of the is "pending":
1225
- - Displays "Loading Pairs".
1226
- - If loading of the is "fail":
1227
- - Displays "Pairs shit" (consider changing this to a more appropriate error message).
940
+ type XPRNKitProfile = {
941
+ displayName: string;
942
+ avatar?: string;
943
+ isKyc: boolean;
944
+ };
1228
945
 
1229
- ## Styling
946
+ type XPRNKitIdentityProofConfig = {
947
+ required: boolean;
948
+ createUrl: string;
949
+ validationUrl?: string;
950
+ validationBuffer?: number;
951
+ headers?: Record<string, string>;
952
+ timeout?: number;
953
+ };
1230
954
 
1231
- The component uses `classNames` for conditional styling:
955
+ type XPRNKitIdentityProof = {
956
+ auth: {
957
+ actor: string;
958
+ permission: string;
959
+ };
960
+ token: string;
961
+ };
1232
962
 
1233
- - Root element: Applies the `className` prop if provided.
1234
- - Dropdown content: Applies "bg-white" and the `contentClassName` prop if provided.
1235
- - Dropdown items: Applies "text-black" and the `itemsClassName` prop if provided.
963
+ type XPRNKitIdentityProofPayload = {
964
+ signer: {
965
+ actor: string;
966
+ permission: string;
967
+ };
968
+ transaction: any;
969
+ signatures: string[];
970
+ chainId: string;
971
+ };
1236
972
 
1237
- ## Notes
973
+ type XPRNKitIdentityProofStatus =
974
+ | "idle"
975
+ | "signing"
976
+ | "verifying"
977
+ | "validating"
978
+ | "success"
979
+ | "expired"
980
+ | "error";
981
+
982
+ type XPRNKitProfileStorageEntry = {
983
+ auth: {
984
+ actor: string;
985
+ permission: string;
986
+ };
987
+ chainId: string;
988
+ profile: XPRNKitProfile;
989
+ };
990
+ ```
1238
991
 
1239
- - The component doesn't render anything if there's only one or zero market pairs available.
1240
- - The default selected value is set based on the `currentSwapPair`.
1241
- - Consider improving the error message for the "fail" state to be more user-friendly and informative.
992
+ ---
1242
993
 
1243
- # toPrecision
994
+ # Utilities
1244
995
 
1245
- ## Description
996
+ ## toPrecision
1246
997
 
1247
- The `toPrecision` function adjusts a numeric value to a specified precision, with options for rounding behavior and decimal representation. It's used to format the an arbitrary price according to the token precision.
998
+ The `toPrecision` function adjusts a numeric value to a specified precision, with options for rounding behavior and decimal representation. It's used to format an arbitrary price according to the token precision.
1248
999
 
1249
- ## Function Signature
1000
+ ### Function Signature
1250
1001
 
1251
1002
  ```typescript
1252
1003
  function toPrecision(
@@ -1257,7 +1008,7 @@ function toPrecision(
1257
1008
  ): string;
1258
1009
  ```
1259
1010
 
1260
- ## Parameters
1011
+ ### Parameters
1261
1012
 
1262
1013
  - `value` (number): The input number to be adjusted.
1263
1014
  - `precision` (number): The number of decimal places to round to.
@@ -1268,19 +1019,11 @@ function toPrecision(
1268
1019
  - 'none': Uses 'ceil' behavior (same as 'ceil').
1269
1020
  - `forceDecimal` (boolean, optional): Whether to force the output to include decimal places. Defaults to true.
1270
1021
 
1271
- ## Returns
1022
+ ### Returns
1272
1023
 
1273
1024
  - (string): The adjusted value as a string, with or without forced decimal places based on the `forceDecimal` parameter.
1274
1025
 
1275
- ## Behavior
1276
-
1277
- 1. Multiplies the input `value` by 10^`precision` to shift the decimal point.
1278
- 2. Applies the specified rounding `mode` to the shifted value.
1279
- 3. Divides the result by 10^`precision` to shift the decimal point back.
1280
- 4. If `forceDecimal` is true, returns the result with the specified number of decimal places.
1281
- 5. If `forceDecimal` is false, returns the result as a string without forcing decimal places.
1282
-
1283
- ## Example Usage
1026
+ ### Example Usage
1284
1027
 
1285
1028
  ```typescript
1286
1029
  console.log(toPrecision(3.14159, 2)); // "3.15"
@@ -1290,9 +1033,3 @@ console.log(toPrecision(3.14159, 2, "ceil", false)); // "3.15"
1290
1033
  console.log(toPrecision(3, 2, "none", true)); // "3.00"
1291
1034
  console.log(toPrecision(3, 2, "ceil", false)); // "3"
1292
1035
  ```
1293
-
1294
- ## Notes
1295
-
1296
- - The 'none' mode behaves the same as 'ceil' mode.
1297
- - When `forceDecimal` is true, the output will always have the specified number of decimal places, even if the input is an integer.
1298
- - When `forceDecimal` is false, the output may have fewer decimal places than specified if they are not needed (e.g., for whole numbers).