@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.
Files changed (76) hide show
  1. package/.turbo/turbo-build.log +51 -0
  2. package/CHANGELOG.md +88 -0
  3. package/COMPONENT_ARCHITECTURE.md +190 -0
  4. package/COMPONENT_CONVERSION_ANALYSIS.md +371 -0
  5. package/CONTEXT_VARIANT_GUIDE.md +425 -0
  6. package/LAZY_LOADING_GUIDE.md +534 -0
  7. package/LICENSE +201 -0
  8. package/PLAYBACK_EXAMPLES.md +658 -0
  9. package/PLAYBACK_GUIDE.md +402 -0
  10. package/README.md +43 -0
  11. package/REGISTRY_SUMMARY.md +638 -0
  12. package/SUFFERING_ECONOMICS.md +346 -0
  13. package/SUFFERING_ECONOMICS.zip +0 -0
  14. package/VIEW_REGISTRATION_GUIDE.md +795 -0
  15. package/dist/composables/index.cjs +1321 -0
  16. package/dist/composables/index.cjs.map +1 -0
  17. package/dist/composables/index.d.cts +6 -0
  18. package/dist/composables/index.d.ts +6 -0
  19. package/dist/composables/index.js +1276 -0
  20. package/dist/composables/index.js.map +1 -0
  21. package/dist/index-CMLU1hKL.d.ts +374 -0
  22. package/dist/index-CSDjhiKV.d.cts +374 -0
  23. package/dist/index.cjs +1534 -0
  24. package/dist/index.cjs.map +1 -0
  25. package/dist/index.d.cts +93 -0
  26. package/dist/index.d.ts +93 -0
  27. package/dist/index.js +1463 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/registry/index.cjs +522 -0
  30. package/dist/registry/index.cjs.map +1 -0
  31. package/dist/registry/index.d.cts +46 -0
  32. package/dist/registry/index.d.ts +46 -0
  33. package/dist/registry/index.js +487 -0
  34. package/dist/registry/index.js.map +1 -0
  35. package/dist/types/index.cjs +19 -0
  36. package/dist/types/index.cjs.map +1 -0
  37. package/dist/types/index.d.cts +203 -0
  38. package/dist/types/index.d.ts +203 -0
  39. package/dist/types/index.js +1 -0
  40. package/dist/types/index.js.map +1 -0
  41. package/dist/utils/index.cjs +217 -0
  42. package/dist/utils/index.cjs.map +1 -0
  43. package/dist/utils/index.d.cts +47 -0
  44. package/dist/utils/index.d.ts +47 -0
  45. package/dist/utils/index.js +188 -0
  46. package/dist/utils/index.js.map +1 -0
  47. package/dist/view-loader-dD86QAlQ.d.cts +121 -0
  48. package/dist/view-loader-ii8AxiQR.d.ts +121 -0
  49. package/package.json +64 -0
  50. package/publish.log +0 -0
  51. package/src/composables/index.ts +59 -0
  52. package/src/composables/use-image-loader.ts +315 -0
  53. package/src/composables/use-transaction-playback.ts +396 -0
  54. package/src/composables/use-transaction-view.ts +309 -0
  55. package/src/config/lukso-config.ts +171 -0
  56. package/src/examples/context-aware-views.ts +300 -0
  57. package/src/examples/example-views.ts +197 -0
  58. package/src/examples/lit-plus-rn-strategy.ts +448 -0
  59. package/src/examples/lsp7-custom-matcher-examples.ts +174 -0
  60. package/src/examples/opt-in-context-examples.ts +372 -0
  61. package/src/examples/optimized-view-definitions.ts +408 -0
  62. package/src/examples/vue-to-lit-compilation.ts +358 -0
  63. package/src/hooks/useAddressQuery.ts +135 -0
  64. package/src/hooks/useAddressResolution.ts +437 -0
  65. package/src/index.ts +36 -0
  66. package/src/registry/index.ts +13 -0
  67. package/src/registry/view-loader.ts +305 -0
  68. package/src/registry/view-registry.ts +135 -0
  69. package/src/types/index.ts +16 -0
  70. package/src/types/view-contexts.ts +72 -0
  71. package/src/types/view-matching.ts +173 -0
  72. package/src/utils/context-matcher.ts +165 -0
  73. package/src/utils/index.ts +5 -0
  74. package/src/utils/view-matcher.ts +338 -0
  75. package/tsconfig.json +20 -0
  76. package/tsup.config.ts +34 -0
@@ -0,0 +1,534 @@
1
+ # Lazy Loading Views - Complete Guide
2
+
3
+ ## Overview
4
+
5
+ View loaders support **lazy loading via callbacks**, preventing components from being bundled until they're actually needed. This reduces initial bundle size and improves app startup performance.
6
+
7
+ ## Lazy Loading Syntax
8
+
9
+ ### String Path (Static, Bundled)
10
+ ```typescript
11
+ loader: { type: 'dynamic-import', path: './Component.vue' }
12
+ ```
13
+ Component is bundled with your app.
14
+
15
+ ### Callback (Lazy, On-Demand)
16
+ ```typescript
17
+ loader: { type: 'dynamic-import', path: () => import('./Component.vue') }
18
+ ```
19
+ Component is loaded only when needed.
20
+
21
+ ## Helper Functions
22
+
23
+ ### Vue Components
24
+
25
+ ```typescript
26
+ import { LoaderHelpers } from '@lukso/transaction-view-headless'
27
+
28
+ // Static (bundled)
29
+ LoaderHelpers.vueComponent('./CustomView.vue')
30
+
31
+ // Lazy (loaded on demand) ✅ RECOMMENDED
32
+ LoaderHelpers.vueComponent(() => import('./CustomView.vue'))
33
+ ```
34
+
35
+ ### React Native Components
36
+
37
+ ```typescript
38
+ // Static
39
+ LoaderHelpers.rnComponent('./CustomView.tsx')
40
+
41
+ // Lazy ✅ RECOMMENDED
42
+ LoaderHelpers.rnComponent(() => import('./CustomView.tsx'))
43
+ ```
44
+
45
+ ### Lit Components
46
+
47
+ ```typescript
48
+ // Lit uses custom elements (always lazy by nature)
49
+ LoaderHelpers.litComponent('custom-view')
50
+ ```
51
+
52
+ ## Complete Examples
53
+
54
+ ### 1. Basic Lazy-Loaded Vue View
55
+
56
+ ```typescript
57
+ import { LoaderHelpers } from '@lukso/transaction-view-headless'
58
+ import type { ViewDefinition } from '@lukso/transaction-view-headless'
59
+
60
+ const lazyViews: ViewDefinition[] = [
61
+ {
62
+ id: 'lsp7-transfer-vue',
63
+ name: 'LSP7 Transfer (Vue)',
64
+ priority: 120,
65
+ criteria: {
66
+ standard: 'LSP7',
67
+ recordType: 'lsp7-transfer'
68
+ },
69
+ frameworks: {
70
+ lit: {
71
+ loader: LoaderHelpers.litComponent('lsp7-transfer-lit'),
72
+ component: 'lsp7-transfer-lit'
73
+ },
74
+ vue: {
75
+ // Lazy loaded! Only downloads when LSP7 transfer is rendered
76
+ loader: LoaderHelpers.vueComponent(() => import('./views/LSP7Transfer.vue')),
77
+ component: 'LSP7Transfer'
78
+ }
79
+ }
80
+ }
81
+ ]
82
+ ```
83
+
84
+ ### 2. Multiple Views with Different Loading Strategies
85
+
86
+ ```typescript
87
+ const mixedViews: ViewDefinition[] = [
88
+ // Common view: bundled (used frequently)
89
+ {
90
+ id: 'common-transfer',
91
+ name: 'Common Transfer',
92
+ priority: 100,
93
+ criteria: { recordType: 'transfer' },
94
+ frameworks: {
95
+ vue: {
96
+ loader: LoaderHelpers.vueComponent('./views/CommonTransfer.vue'),
97
+ component: 'CommonTransfer'
98
+ }
99
+ }
100
+ },
101
+
102
+ // Rare view: lazy loaded (used infrequently)
103
+ {
104
+ id: 'rare-contract-deployment',
105
+ name: 'Contract Deployment',
106
+ priority: 110,
107
+ criteria: { recordType: 'create' },
108
+ frameworks: {
109
+ vue: {
110
+ loader: LoaderHelpers.vueComponent(() => import('./views/ContractDeploy.vue')),
111
+ component: 'ContractDeploy'
112
+ }
113
+ }
114
+ },
115
+
116
+ // Heavy view: lazy loaded (large bundle)
117
+ {
118
+ id: 'heavy-analytics-view',
119
+ name: 'Analytics View',
120
+ priority: 90,
121
+ criteria: { recordType: 'analytics' },
122
+ frameworks: {
123
+ vue: {
124
+ loader: LoaderHelpers.vueComponent(() => import(
125
+ /* webpackChunkName: "analytics" */
126
+ './views/AnalyticsView.vue'
127
+ )),
128
+ component: 'AnalyticsView'
129
+ }
130
+ }
131
+ }
132
+ ]
133
+ ```
134
+
135
+ ### 3. Context-Specific Lazy Loading
136
+
137
+ ```typescript
138
+ const contextViews: ViewDefinition[] = [
139
+ // Approval view: bundled (critical path)
140
+ {
141
+ id: 'approval-view',
142
+ name: 'Approval View',
143
+ priority: 150,
144
+ criteria: {
145
+ recordType: 'lsp7-transfer',
146
+ context: 'approval'
147
+ },
148
+ frameworks: {
149
+ vue: {
150
+ loader: LoaderHelpers.vueComponent('./views/ApprovalView.vue'),
151
+ component: 'ApprovalView'
152
+ }
153
+ }
154
+ },
155
+
156
+ // Detail view: lazy (not critical)
157
+ {
158
+ id: 'detail-view',
159
+ name: 'Detail View',
160
+ priority: 100,
161
+ criteria: {
162
+ recordType: 'lsp7-transfer',
163
+ context: 'detail'
164
+ },
165
+ frameworks: {
166
+ vue: {
167
+ loader: LoaderHelpers.vueComponent(() => import('./views/DetailView.vue')),
168
+ component: 'DetailView'
169
+ }
170
+ }
171
+ }
172
+ ]
173
+ ```
174
+
175
+ ### 4. Chain-Specific Lazy Loading
176
+
177
+ ```typescript
178
+ const chainViews: ViewDefinition[] = [
179
+ // Mainnet: bundled (primary network)
180
+ {
181
+ id: 'mainnet-view',
182
+ name: 'Mainnet View',
183
+ priority: 120,
184
+ criteria: {
185
+ recordType: 'special-transaction',
186
+ chainId: 42
187
+ },
188
+ frameworks: {
189
+ vue: {
190
+ loader: LoaderHelpers.vueComponent('./views/MainnetView.vue'),
191
+ component: 'MainnetView'
192
+ }
193
+ }
194
+ },
195
+
196
+ // Testnet: lazy (less common)
197
+ {
198
+ id: 'testnet-view',
199
+ name: 'Testnet View',
200
+ priority: 120,
201
+ criteria: {
202
+ recordType: 'special-transaction',
203
+ chainId: 4201
204
+ },
205
+ frameworks: {
206
+ vue: {
207
+ loader: LoaderHelpers.vueComponent(() => import('./views/TestnetView.vue')),
208
+ component: 'TestnetView'
209
+ }
210
+ }
211
+ }
212
+ ]
213
+ ```
214
+
215
+ ## Advanced Patterns
216
+
217
+ ### 1. Conditional Lazy Loading
218
+
219
+ ```typescript
220
+ function createViews(isDevelopment: boolean): ViewDefinition[] {
221
+ return [
222
+ {
223
+ id: 'debug-view',
224
+ name: 'Debug View',
225
+ priority: 200,
226
+ criteria: { recordType: 'debug' },
227
+ frameworks: {
228
+ vue: {
229
+ // Only bundle in development, lazy in production
230
+ loader: isDevelopment
231
+ ? LoaderHelpers.vueComponent('./views/DebugView.vue')
232
+ : LoaderHelpers.vueComponent(() => import('./views/DebugView.vue')),
233
+ component: 'DebugView'
234
+ }
235
+ }
236
+ }
237
+ ]
238
+ }
239
+ ```
240
+
241
+ ### 2. Route-Based Lazy Loading
242
+
243
+ ```typescript
244
+ // App initialization
245
+ const registry = getGlobalRegistry()
246
+
247
+ // Register common views immediately
248
+ registry.registerMany(commonViews)
249
+
250
+ // Lazy register route-specific views
251
+ router.beforeEach(async (to, from, next) => {
252
+ if (to.path === '/transactions' && !transactionViewsLoaded) {
253
+ const transactionViews = await import('./views/transaction-views')
254
+ registry.registerMany(transactionViews.default)
255
+ transactionViewsLoaded = true
256
+ }
257
+ next()
258
+ })
259
+ ```
260
+
261
+ ### 3. Dynamic Import with Webpack Magic Comments
262
+
263
+ ```typescript
264
+ const optimizedViews: ViewDefinition[] = [
265
+ {
266
+ id: 'heavy-view',
267
+ name: 'Heavy View',
268
+ priority: 100,
269
+ criteria: { recordType: 'heavy' },
270
+ frameworks: {
271
+ vue: {
272
+ loader: LoaderHelpers.vueComponent(() => import(
273
+ /* webpackChunkName: "heavy-view" */
274
+ /* webpackPrefetch: true */
275
+ './views/HeavyView.vue'
276
+ )),
277
+ component: 'HeavyView'
278
+ }
279
+ }
280
+ }
281
+ ]
282
+ ```
283
+
284
+ ## Bundle Splitting Strategies
285
+
286
+ ### Small Apps (< 100KB total)
287
+ **Bundle everything** - lazy loading overhead isn't worth it.
288
+
289
+ ```typescript
290
+ // Bundle all views
291
+ LoaderHelpers.vueComponent('./AllViews.vue')
292
+ ```
293
+
294
+ ### Medium Apps (100KB - 1MB)
295
+ **Lazy load rare views** - common views bundled.
296
+
297
+ ```typescript
298
+ // Common: bundled
299
+ LoaderHelpers.vueComponent('./CommonView.vue')
300
+
301
+ // Rare: lazy
302
+ LoaderHelpers.vueComponent(() => import('./RareView.vue'))
303
+ ```
304
+
305
+ ### Large Apps (> 1MB)
306
+ **Lazy load everything except critical path**.
307
+
308
+ ```typescript
309
+ // Critical (approval flow): bundled
310
+ LoaderHelpers.vueComponent('./ApprovalView.vue')
311
+
312
+ // Everything else: lazy
313
+ LoaderHelpers.vueComponent(() => import('./DetailView.vue'))
314
+ LoaderHelpers.vueComponent(() => import('./HistoryView.vue'))
315
+ LoaderHelpers.vueComponent(() => import('./AnalyticsView.vue'))
316
+ ```
317
+
318
+ ## Custom Package with Lazy Loading
319
+
320
+ ```typescript
321
+ // @myorg/custom-views/src/registry/view-definitions.ts
322
+ import { LoaderHelpers } from '@lukso/transaction-view-headless'
323
+ import type { ViewDefinition } from '@lukso/transaction-view-headless'
324
+
325
+ export const customViews: ViewDefinition[] = [
326
+ {
327
+ id: 'custom-token-view',
328
+ name: 'Custom Token View',
329
+ priority: 130,
330
+ criteria: {
331
+ standard: 'CustomToken',
332
+ contractAddress: '0x123...'
333
+ },
334
+ frameworks: {
335
+ lit: {
336
+ loader: LoaderHelpers.litComponent('custom-token-view'),
337
+ component: 'custom-token-view'
338
+ },
339
+ vue: {
340
+ // Lazy loaded - only downloads when custom token is encountered
341
+ loader: LoaderHelpers.vueComponent(() => import('../views/vue/CustomTokenView.vue')),
342
+ component: 'CustomTokenView',
343
+ package: '@myorg/custom-views'
344
+ },
345
+ rn: {
346
+ // Lazy loaded for React Native
347
+ loader: LoaderHelpers.rnComponent(() => import('../views/rn/CustomTokenView.tsx')),
348
+ component: 'CustomTokenView',
349
+ package: '@myorg/custom-views'
350
+ }
351
+ }
352
+ }
353
+ ]
354
+ ```
355
+
356
+ ## Performance Comparison
357
+
358
+ ### Without Lazy Loading
359
+ ```
360
+ Initial Bundle: 2.5 MB
361
+ - Common views: 500 KB
362
+ - Rare views: 2 MB ❌ (rarely used!)
363
+
364
+ Time to Interactive: 3.5s
365
+ ```
366
+
367
+ ### With Lazy Loading
368
+ ```
369
+ Initial Bundle: 500 KB
370
+ - Common views: 500 KB
371
+
372
+ Loaded on demand:
373
+ - Rare view 1: 300 KB (when needed)
374
+ - Rare view 2: 400 KB (when needed)
375
+ - etc.
376
+
377
+ Time to Interactive: 1.2s ✅ (66% faster!)
378
+ ```
379
+
380
+ ## Best Practices
381
+
382
+ ### 1. Bundle Critical Path, Lazy Load Everything Else
383
+
384
+ ```typescript
385
+ // Approval flow (critical): bundle
386
+ ✅ LoaderHelpers.vueComponent('./ApprovalView.vue')
387
+
388
+ // History view (not critical): lazy
389
+ ✅ LoaderHelpers.vueComponent(() => import('./HistoryView.vue'))
390
+ ```
391
+
392
+ ### 2. Use Webpack Magic Comments
393
+
394
+ ```typescript
395
+ LoaderHelpers.vueComponent(() => import(
396
+ /* webpackChunkName: "transaction-history" */
397
+ /* webpackPrefetch: true */ // Prefetch during idle time
398
+ './HistoryView.vue'
399
+ ))
400
+ ```
401
+
402
+ ### 3. Group Related Views
403
+
404
+ ```typescript
405
+ // Group LSP8 views in one chunk
406
+ LoaderHelpers.vueComponent(() => import(
407
+ /* webpackChunkName: "lsp8-views" */
408
+ './views/lsp8/LSP8Transfer.vue'
409
+ ))
410
+
411
+ LoaderHelpers.vueComponent(() => import(
412
+ /* webpackChunkName: "lsp8-views" */ // Same chunk name
413
+ './views/lsp8/LSP8Mint.vue'
414
+ ))
415
+ ```
416
+
417
+ ### 4. Measure Impact
418
+
419
+ ```typescript
420
+ // Before lazy loading
421
+ console.time('initial-load')
422
+ import '@myorg/custom-views'
423
+ console.timeEnd('initial-load') // 2500ms
424
+
425
+ // After lazy loading
426
+ console.time('initial-load')
427
+ import '@myorg/custom-views/registry' // Only definitions, not components
428
+ console.timeEnd('initial-load') // 50ms ✅ (98% faster!)
429
+ ```
430
+
431
+ ## Migration Guide
432
+
433
+ ### Before (Static Imports)
434
+ ```typescript
435
+ // Old: Everything bundled
436
+ import LSP7View from './LSP7View.vue'
437
+ import LSP8View from './LSP8View.vue'
438
+ import RareView from './RareView.vue'
439
+
440
+ const views: ViewDefinition[] = [
441
+ {
442
+ id: 'lsp7-view',
443
+ frameworks: {
444
+ vue: {
445
+ loader: { type: 'static-import', path: './LSP7View.vue' },
446
+ component: 'LSP7View'
447
+ }
448
+ }
449
+ }
450
+ ]
451
+ ```
452
+
453
+ ### After (Lazy Loading)
454
+ ```typescript
455
+ // New: Lazy loaded
456
+ const views: ViewDefinition[] = [
457
+ {
458
+ id: 'lsp7-view',
459
+ frameworks: {
460
+ vue: {
461
+ loader: LoaderHelpers.vueComponent(() => import('./LSP7View.vue')),
462
+ component: 'LSP7View'
463
+ }
464
+ }
465
+ }
466
+ ]
467
+ ```
468
+
469
+ ## Troubleshooting
470
+
471
+ ### Issue: Module not found
472
+ ```
473
+ Error: Cannot find module './Component.vue'
474
+ ```
475
+
476
+ **Solution:** Ensure path is relative to the file defining the loader:
477
+ ```typescript
478
+ // ✅ Correct (relative to current file)
479
+ () => import('./views/Component.vue')
480
+
481
+ // ❌ Wrong (absolute path doesn't work in dynamic import)
482
+ () => import('/absolute/path/Component.vue')
483
+ ```
484
+
485
+ ### Issue: Loader not working
486
+ ```
487
+ Error: Failed to load component
488
+ ```
489
+
490
+ **Solution:** Ensure callback returns a Promise:
491
+ ```typescript
492
+ // ✅ Correct
493
+ () => import('./Component.vue')
494
+
495
+ // ❌ Wrong (not a function)
496
+ './Component.vue'
497
+
498
+ // ❌ Wrong (not returning Promise)
499
+ () => './Component.vue'
500
+ ```
501
+
502
+ ### Issue: TypeScript errors
503
+
504
+ **Solution:** Add proper types:
505
+ ```typescript
506
+ import type { ViewDefinition } from '@lukso/transaction-view-headless'
507
+
508
+ const views: ViewDefinition[] = [
509
+ {
510
+ // TypeScript knows path can be string | (() => Promise<any>)
511
+ loader: LoaderHelpers.vueComponent(() => import('./Component.vue'))
512
+ }
513
+ ]
514
+ ```
515
+
516
+ ## Summary
517
+
518
+ **Lazy loading views** dramatically improves app performance by:
519
+ 1. Reducing initial bundle size (50-90% smaller)
520
+ 2. Faster time to interactive (2-3x faster)
521
+ 3. Loading components only when needed
522
+ 4. Better code splitting and caching
523
+
524
+ **Use callbacks everywhere**:
525
+ ```typescript
526
+ // ✅ Recommended
527
+ LoaderHelpers.vueComponent(() => import('./View.vue'))
528
+ LoaderHelpers.rnComponent(() => import('./View.tsx'))
529
+
530
+ // Only bundle if truly critical:
531
+ LoaderHelpers.vueComponent('./ApprovalView.vue')
532
+ ```
533
+
534
+ This is the recommended pattern for all production apps!