@lukso/transaction-view-headless 0.2.2-dev.a8c9315
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/.turbo/turbo-build.log +51 -0
- package/CHANGELOG.md +88 -0
- package/COMPONENT_ARCHITECTURE.md +190 -0
- package/COMPONENT_CONVERSION_ANALYSIS.md +371 -0
- package/CONTEXT_VARIANT_GUIDE.md +425 -0
- package/LAZY_LOADING_GUIDE.md +534 -0
- package/LICENSE +201 -0
- package/PLAYBACK_EXAMPLES.md +658 -0
- package/PLAYBACK_GUIDE.md +402 -0
- package/README.md +43 -0
- package/REGISTRY_SUMMARY.md +638 -0
- package/SUFFERING_ECONOMICS.md +346 -0
- package/SUFFERING_ECONOMICS.zip +0 -0
- package/VIEW_REGISTRATION_GUIDE.md +795 -0
- package/dist/composables/index.cjs +1321 -0
- package/dist/composables/index.cjs.map +1 -0
- package/dist/composables/index.d.cts +6 -0
- package/dist/composables/index.d.ts +6 -0
- package/dist/composables/index.js +1276 -0
- package/dist/composables/index.js.map +1 -0
- package/dist/index-CMLU1hKL.d.ts +374 -0
- package/dist/index-CSDjhiKV.d.cts +374 -0
- package/dist/index.cjs +1534 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +93 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +1463 -0
- package/dist/index.js.map +1 -0
- package/dist/registry/index.cjs +522 -0
- package/dist/registry/index.cjs.map +1 -0
- package/dist/registry/index.d.cts +46 -0
- package/dist/registry/index.d.ts +46 -0
- package/dist/registry/index.js +487 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/types/index.cjs +19 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +203 -0
- package/dist/types/index.d.ts +203 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.cjs +217 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +47 -0
- package/dist/utils/index.d.ts +47 -0
- package/dist/utils/index.js +188 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/view-loader-dD86QAlQ.d.cts +121 -0
- package/dist/view-loader-ii8AxiQR.d.ts +121 -0
- package/package.json +64 -0
- package/publish.log +0 -0
- package/src/composables/index.ts +59 -0
- package/src/composables/use-image-loader.ts +315 -0
- package/src/composables/use-transaction-playback.ts +396 -0
- package/src/composables/use-transaction-view.ts +309 -0
- package/src/config/lukso-config.ts +171 -0
- package/src/examples/context-aware-views.ts +300 -0
- package/src/examples/example-views.ts +197 -0
- package/src/examples/lit-plus-rn-strategy.ts +448 -0
- package/src/examples/lsp7-custom-matcher-examples.ts +174 -0
- package/src/examples/opt-in-context-examples.ts +372 -0
- package/src/examples/optimized-view-definitions.ts +408 -0
- package/src/examples/vue-to-lit-compilation.ts +358 -0
- package/src/hooks/useAddressQuery.ts +135 -0
- package/src/hooks/useAddressResolution.ts +437 -0
- package/src/index.ts +36 -0
- package/src/registry/index.ts +13 -0
- package/src/registry/view-loader.ts +305 -0
- package/src/registry/view-registry.ts +135 -0
- package/src/types/index.ts +16 -0
- package/src/types/view-contexts.ts +72 -0
- package/src/types/view-matching.ts +173 -0
- package/src/utils/context-matcher.ts +165 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/view-matcher.ts +338 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +34 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# Context and Variant Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to use **Context** and **Variant** to register and match transaction views for different display scenarios.
|
|
4
|
+
|
|
5
|
+
## Core Concepts
|
|
6
|
+
|
|
7
|
+
### Context: WHERE to Display
|
|
8
|
+
|
|
9
|
+
**Context** defines WHERE a transaction view is being displayed, which affects the environment, user intent, and interaction patterns.
|
|
10
|
+
|
|
11
|
+
Available contexts:
|
|
12
|
+
- `approval` - Transaction approval flow (security-focused)
|
|
13
|
+
- `feed` - Activity feed (compact summaries)
|
|
14
|
+
- `list` - Transaction lists (scannable format)
|
|
15
|
+
- `detail` - Full transaction detail (comprehensive)
|
|
16
|
+
- `review` - Pre-submission review (verification-focused)
|
|
17
|
+
- `notification` - Push notifications (minimal info)
|
|
18
|
+
- `embed` - Embedded in other interfaces
|
|
19
|
+
- `batch-summary` - Inside a batch summary display
|
|
20
|
+
|
|
21
|
+
### Variant: HOW to Display
|
|
22
|
+
|
|
23
|
+
**Variant** defines HOW a transaction view should be rendered within a given context.
|
|
24
|
+
|
|
25
|
+
Available variants:
|
|
26
|
+
- `full` - Complete detailed view
|
|
27
|
+
- `collapsed` - Collapsed/summary view
|
|
28
|
+
- `minimal` - Minimal information only
|
|
29
|
+
- `icon-only` - Just icon/avatar
|
|
30
|
+
- `compact` - Compact single-line format
|
|
31
|
+
- `expanded` - Expanded with all details
|
|
32
|
+
- Custom strings allowed
|
|
33
|
+
|
|
34
|
+
## Why Separate Context and Variant?
|
|
35
|
+
|
|
36
|
+
The same variant can mean different things in different contexts:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// "collapsed" in feed - might show "3 transfers"
|
|
40
|
+
context: 'feed', variant: 'collapsed'
|
|
41
|
+
|
|
42
|
+
// "collapsed" in approval - still shows critical security info
|
|
43
|
+
context: 'approval', variant: 'collapsed'
|
|
44
|
+
|
|
45
|
+
// "collapsed" in batch-summary - might skip unimportant transactions
|
|
46
|
+
context: 'batch-summary', variant: 'collapsed'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Registering Views
|
|
50
|
+
|
|
51
|
+
### Single Context and Variant
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
registry.register({
|
|
55
|
+
id: 'lsp7-transfer-feed-collapsed',
|
|
56
|
+
name: 'LSP7 Transfer (Feed Collapsed)',
|
|
57
|
+
criteria: {
|
|
58
|
+
standard: 'LSP7',
|
|
59
|
+
functionName: 'transfer',
|
|
60
|
+
context: 'feed', // Only matches feed
|
|
61
|
+
variant: 'collapsed', // Only matches collapsed
|
|
62
|
+
},
|
|
63
|
+
priority: 100,
|
|
64
|
+
frameworks: {
|
|
65
|
+
lit: {
|
|
66
|
+
loader: { type: 'dynamic-import', path: () => import('./LSP7TransferCollapsed.lit') },
|
|
67
|
+
component: 'lsp7-transfer-collapsed',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Multiple Contexts
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
registry.register({
|
|
77
|
+
id: 'lsp7-transfer-compact',
|
|
78
|
+
name: 'LSP7 Transfer (Compact)',
|
|
79
|
+
criteria: {
|
|
80
|
+
standard: 'LSP7',
|
|
81
|
+
functionName: 'transfer',
|
|
82
|
+
context: ['feed', 'list'], // Matches both feed and list
|
|
83
|
+
variant: 'compact',
|
|
84
|
+
},
|
|
85
|
+
priority: 90,
|
|
86
|
+
frameworks: { /* ... */ },
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Universal View (No Context/Variant)
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
registry.register({
|
|
94
|
+
id: 'lsp7-transfer-universal',
|
|
95
|
+
name: 'LSP7 Transfer (Universal)',
|
|
96
|
+
criteria: {
|
|
97
|
+
standard: 'LSP7',
|
|
98
|
+
functionName: 'transfer',
|
|
99
|
+
// No context or variant = matches any context/variant
|
|
100
|
+
},
|
|
101
|
+
priority: 50, // Lower priority as fallback
|
|
102
|
+
frameworks: { /* ... */ },
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Matching Views
|
|
107
|
+
|
|
108
|
+
### Basic Matching
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// Find views for a transaction in feed context with collapsed variant
|
|
112
|
+
const matches = registry.findMatches(transaction, {
|
|
113
|
+
framework: 'lit',
|
|
114
|
+
context: 'feed',
|
|
115
|
+
variant: 'collapsed',
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Variant is Optional
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// Without variant - matches views without variant requirement
|
|
123
|
+
const matches = registry.findMatches(transaction, {
|
|
124
|
+
framework: 'lit',
|
|
125
|
+
context: 'approval', // Just context, no variant
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Scoring
|
|
130
|
+
|
|
131
|
+
Views are scored based on how well they match:
|
|
132
|
+
|
|
133
|
+
| Criteria | Weight |
|
|
134
|
+
|----------|--------|
|
|
135
|
+
| recordType | 0.20 |
|
|
136
|
+
| context | 0.15 |
|
|
137
|
+
| variant | 0.15 |
|
|
138
|
+
| customMatcher | 0.15 |
|
|
139
|
+
| functionName | 0.12 |
|
|
140
|
+
| standard | 0.10 |
|
|
141
|
+
| contractAddress | 0.08 |
|
|
142
|
+
| contextRequirements | 0.03 |
|
|
143
|
+
| chainId | 0.02 |
|
|
144
|
+
|
|
145
|
+
**Example:**
|
|
146
|
+
```typescript
|
|
147
|
+
// View A: context='feed', variant='collapsed' (exact matches)
|
|
148
|
+
// Score: 0.15 + 0.15 = 0.30
|
|
149
|
+
|
|
150
|
+
// View B: no context/variant specified (universal fallback)
|
|
151
|
+
// Score: 0.00 (matches but scores lower)
|
|
152
|
+
|
|
153
|
+
// Result: View A wins!
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Custom Matchers
|
|
157
|
+
|
|
158
|
+
For complex matching logic, use `customMatcher` (weighted equally to context/variant at 0.15):
|
|
159
|
+
|
|
160
|
+
### Example: LSP7 Decimals Check
|
|
161
|
+
|
|
162
|
+
LSP7 tokens with `decimals() == 0` are NFT-like and should display differently than fungible tokens:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// NFT-like LSP7 (decimals = 0)
|
|
166
|
+
registry.register({
|
|
167
|
+
id: 'lsp7-nft-transfer',
|
|
168
|
+
name: 'LSP7 NFT Transfer',
|
|
169
|
+
criteria: {
|
|
170
|
+
standard: 'LSP7',
|
|
171
|
+
functionName: 'transfer',
|
|
172
|
+
customMatcher: (tx) => {
|
|
173
|
+
// Check if this LSP7 has decimals = 0 (NFT-like)
|
|
174
|
+
const decimals = tx.enhancedInfo?.decimals
|
|
175
|
+
return decimals === 0 || decimals === '0'
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
priority: 100,
|
|
179
|
+
frameworks: {
|
|
180
|
+
lit: {
|
|
181
|
+
loader: { type: 'dynamic-import', path: () => import('./LSP7NFTTransfer.lit') },
|
|
182
|
+
component: 'lsp7-nft-transfer',
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
// Fungible LSP7 (decimals > 0)
|
|
188
|
+
registry.register({
|
|
189
|
+
id: 'lsp7-token-transfer',
|
|
190
|
+
name: 'LSP7 Token Transfer',
|
|
191
|
+
criteria: {
|
|
192
|
+
standard: 'LSP7',
|
|
193
|
+
functionName: 'transfer',
|
|
194
|
+
customMatcher: (tx) => {
|
|
195
|
+
// Check if this LSP7 has decimals > 0 (fungible)
|
|
196
|
+
const decimals = tx.enhancedInfo?.decimals
|
|
197
|
+
return decimals !== undefined && decimals !== 0 && decimals !== '0'
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
priority: 100,
|
|
201
|
+
frameworks: {
|
|
202
|
+
lit: {
|
|
203
|
+
loader: { type: 'dynamic-import', path: () => import('./LSP7TokenTransfer.lit') },
|
|
204
|
+
component: 'lsp7-token-transfer',
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
// Universal fallback (no customMatcher)
|
|
210
|
+
registry.register({
|
|
211
|
+
id: 'lsp7-transfer-fallback',
|
|
212
|
+
criteria: {
|
|
213
|
+
standard: 'LSP7',
|
|
214
|
+
functionName: 'transfer',
|
|
215
|
+
// No customMatcher = matches any LSP7 transfer
|
|
216
|
+
},
|
|
217
|
+
priority: 50, // Lower priority
|
|
218
|
+
frameworks: { /* ... */ },
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Other customMatcher Use Cases
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// Check transaction value
|
|
226
|
+
customMatcher: (tx) => BigInt(tx.value || '0') > BigInt('1000000000000000000') // > 1 ETH
|
|
227
|
+
|
|
228
|
+
// Check specific parameter
|
|
229
|
+
customMatcher: (tx) => {
|
|
230
|
+
const amount = tx.namedArgs?.find(arg => arg.name === 'amount')
|
|
231
|
+
return amount && BigInt(amount.value) > BigInt('1000000')
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Check array length
|
|
235
|
+
customMatcher: (tx) => {
|
|
236
|
+
const recipients = tx.namedArgs?.find(arg => arg.name === 'recipients')
|
|
237
|
+
return recipients && Array.isArray(recipients.value) && recipients.value.length > 5
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Complex logic
|
|
241
|
+
customMatcher: (tx) => {
|
|
242
|
+
const isHighValue = BigInt(tx.value || '0') > BigInt('1000000000000000000')
|
|
243
|
+
const isKnownAddress = KNOWN_ADDRESSES.includes(tx.to)
|
|
244
|
+
return isHighValue && isKnownAddress
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Common Patterns
|
|
249
|
+
|
|
250
|
+
### Pattern 1: Batch Summary with Collapsed Children
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
// Register a collapsed view for batch summaries
|
|
254
|
+
registry.register({
|
|
255
|
+
id: 'approve-collapsed-batch',
|
|
256
|
+
criteria: {
|
|
257
|
+
standard: 'LSP7',
|
|
258
|
+
context: 'batch-summary',
|
|
259
|
+
variant: 'collapsed',
|
|
260
|
+
},
|
|
261
|
+
// ...
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
// Use it
|
|
265
|
+
const matches = registry.findMatches(childTransaction, {
|
|
266
|
+
framework: 'lit',
|
|
267
|
+
context: 'batch-summary',
|
|
268
|
+
variant: 'collapsed',
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Pattern 2: Context-Specific Full Views
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// Approval needs full security details
|
|
276
|
+
registry.register({
|
|
277
|
+
id: 'approve-full',
|
|
278
|
+
criteria: {
|
|
279
|
+
context: 'approval',
|
|
280
|
+
variant: 'full',
|
|
281
|
+
},
|
|
282
|
+
// ...
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
// Feed needs compact summaries
|
|
286
|
+
registry.register({
|
|
287
|
+
id: 'feed-compact',
|
|
288
|
+
criteria: {
|
|
289
|
+
context: 'feed',
|
|
290
|
+
variant: 'compact',
|
|
291
|
+
},
|
|
292
|
+
// ...
|
|
293
|
+
})
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Pattern 3: Fallback Chain
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// Most specific (high priority)
|
|
300
|
+
registry.register({
|
|
301
|
+
id: 'specific',
|
|
302
|
+
criteria: {
|
|
303
|
+
standard: 'LSP7',
|
|
304
|
+
context: 'feed',
|
|
305
|
+
variant: 'collapsed',
|
|
306
|
+
},
|
|
307
|
+
priority: 100,
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
// Less specific (medium priority)
|
|
311
|
+
registry.register({
|
|
312
|
+
id: 'generic-feed',
|
|
313
|
+
criteria: {
|
|
314
|
+
standard: 'LSP7',
|
|
315
|
+
context: 'feed',
|
|
316
|
+
},
|
|
317
|
+
priority: 75,
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
// Universal fallback (low priority)
|
|
321
|
+
registry.register({
|
|
322
|
+
id: 'universal',
|
|
323
|
+
criteria: {
|
|
324
|
+
standard: 'LSP7',
|
|
325
|
+
},
|
|
326
|
+
priority: 50,
|
|
327
|
+
})
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Real-World Example: LSP7 Transfer
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
// 1. Feed - collapsed (show "Transfer 100 tokens")
|
|
334
|
+
registry.register({
|
|
335
|
+
id: 'lsp7-transfer-feed-collapsed',
|
|
336
|
+
criteria: {
|
|
337
|
+
standard: 'LSP7',
|
|
338
|
+
functionName: 'transfer',
|
|
339
|
+
context: 'feed',
|
|
340
|
+
variant: 'collapsed',
|
|
341
|
+
},
|
|
342
|
+
priority: 100,
|
|
343
|
+
frameworks: {
|
|
344
|
+
lit: {
|
|
345
|
+
loader: { type: 'dynamic-import', path: () => import('./FeedCollapsed.lit') },
|
|
346
|
+
component: 'lsp7-transfer-feed-collapsed',
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
// 2. Approval - full (show all security details)
|
|
352
|
+
registry.register({
|
|
353
|
+
id: 'lsp7-transfer-approval-full',
|
|
354
|
+
criteria: {
|
|
355
|
+
standard: 'LSP7',
|
|
356
|
+
functionName: 'transfer',
|
|
357
|
+
context: 'approval',
|
|
358
|
+
variant: 'full',
|
|
359
|
+
},
|
|
360
|
+
priority: 100,
|
|
361
|
+
frameworks: {
|
|
362
|
+
lit: {
|
|
363
|
+
loader: { type: 'dynamic-import', path: () => import('./ApprovalFull.lit') },
|
|
364
|
+
component: 'lsp7-transfer-approval-full',
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
// 3. Batch summary - minimal (show icon + amount)
|
|
370
|
+
registry.register({
|
|
371
|
+
id: 'lsp7-transfer-batch-minimal',
|
|
372
|
+
criteria: {
|
|
373
|
+
standard: 'LSP7',
|
|
374
|
+
functionName: 'transfer',
|
|
375
|
+
context: 'batch-summary',
|
|
376
|
+
variant: 'minimal',
|
|
377
|
+
},
|
|
378
|
+
priority: 100,
|
|
379
|
+
frameworks: {
|
|
380
|
+
lit: {
|
|
381
|
+
loader: { type: 'dynamic-import', path: () => import('./BatchMinimal.lit') },
|
|
382
|
+
component: 'lsp7-transfer-batch-minimal',
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
// 4. Universal fallback
|
|
388
|
+
registry.register({
|
|
389
|
+
id: 'lsp7-transfer-universal',
|
|
390
|
+
criteria: {
|
|
391
|
+
standard: 'LSP7',
|
|
392
|
+
functionName: 'transfer',
|
|
393
|
+
// No context/variant
|
|
394
|
+
},
|
|
395
|
+
priority: 50,
|
|
396
|
+
frameworks: {
|
|
397
|
+
lit: {
|
|
398
|
+
loader: { type: 'dynamic-import', path: () => import('./Universal.lit') },
|
|
399
|
+
component: 'lsp7-transfer',
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
})
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Best Practices
|
|
406
|
+
|
|
407
|
+
1. **Always provide a universal fallback** - Register a view without context/variant constraints
|
|
408
|
+
2. **Use specific contexts** - Don't overuse `embed`, be specific about WHERE
|
|
409
|
+
3. **Variant is optional** - Only specify variant when you have multiple display modes
|
|
410
|
+
4. **Higher priority for specific views** - More specific views should have higher priority
|
|
411
|
+
5. **Test fallback chains** - Ensure there's always a view that matches
|
|
412
|
+
|
|
413
|
+
## Testing
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
// Test that your view matches the expected context/variant
|
|
417
|
+
const matches = registry.findMatches(mockTransaction, {
|
|
418
|
+
framework: 'lit',
|
|
419
|
+
context: 'feed',
|
|
420
|
+
variant: 'collapsed',
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
expect(matches[0].view.id).toBe('lsp7-transfer-feed-collapsed')
|
|
424
|
+
expect(matches[0].score).toBeGreaterThan(0.8)
|
|
425
|
+
```
|