@lukso/transaction-view-core 0.3.1-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 (62) hide show
  1. package/.turbo/turbo-build.log +33 -0
  2. package/CHANGELOG.md +104 -0
  3. package/LICENSE +201 -0
  4. package/README.md +264 -0
  5. package/dist/index.cjs +4573 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +493 -0
  8. package/dist/index.d.ts +493 -0
  9. package/dist/index.js +4534 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/shared/index.cjs +2480 -0
  12. package/dist/shared/index.cjs.map +1 -0
  13. package/dist/shared/index.d.cts +887 -0
  14. package/dist/shared/index.d.ts +887 -0
  15. package/dist/shared/index.js +2437 -0
  16. package/dist/shared/index.js.map +1 -0
  17. package/dist/styles/index.cjs +58 -0
  18. package/dist/styles/index.cjs.map +1 -0
  19. package/dist/styles/index.d.cts +9 -0
  20. package/dist/styles/index.d.ts +9 -0
  21. package/dist/styles/index.js +31 -0
  22. package/dist/styles/index.js.map +1 -0
  23. package/package.json +57 -0
  24. package/publish.log +0 -0
  25. package/src/components/asset-card.ts +426 -0
  26. package/src/components/contract-card.ts +238 -0
  27. package/src/components/description-view.ts +605 -0
  28. package/src/components/index.ts +20 -0
  29. package/src/components/info-panel.ts +437 -0
  30. package/src/components/permissions-block.ts +138 -0
  31. package/src/components/transaction-playback.ts +429 -0
  32. package/src/components/universal-token-view.ts +281 -0
  33. package/src/declaration.d.ts +4 -0
  34. package/src/examples/INTEGRATION_GUIDE.md +240 -0
  35. package/src/examples/TransactionContentWithReplacement.vue +269 -0
  36. package/src/index.ts +38 -0
  37. package/src/registry/index.ts +31 -0
  38. package/src/registry/lit-view-loader.ts +191 -0
  39. package/src/shared/address-display.ts +370 -0
  40. package/src/shared/address-view.ts +385 -0
  41. package/src/shared/custom-select.ts +164 -0
  42. package/src/shared/function-name-view.ts +89 -0
  43. package/src/shared/gas-provider-view.ts +218 -0
  44. package/src/shared/icon-view.ts +288 -0
  45. package/src/shared/image-list.ts +261 -0
  46. package/src/shared/image-loader-controller.ts +160 -0
  47. package/src/shared/index.ts +34 -0
  48. package/src/shared/load-web-components.ts +56 -0
  49. package/src/shared/notification-view.ts +132 -0
  50. package/src/shared/progress-view.ts +86 -0
  51. package/src/shared/safe-custom-element.ts +35 -0
  52. package/src/shared/scroll-to-bottom-button.ts +55 -0
  53. package/src/shared/signal-controller.ts +124 -0
  54. package/src/shared/transaction-view-controller.ts +345 -0
  55. package/src/shared/url-view.ts +129 -0
  56. package/src/shared/value-view.ts +510 -0
  57. package/src/styles/index.ts +28 -0
  58. package/src/styles/styles.css +1 -0
  59. package/src/vue-entry.ts +15 -0
  60. package/tailwind.config.cjs +9 -0
  61. package/tsconfig.json +22 -0
  62. package/tsup.config.ts +90 -0
@@ -0,0 +1,605 @@
1
+ import { css, html, LitElement } from 'lit'
2
+ import { property } from 'lit/decorators.js'
3
+ import { repeat } from 'lit/directives/repeat.js'
4
+ import { when } from 'lit/directives/when.js'
5
+ import { safeCustomElement } from '../shared/safe-custom-element'
6
+
7
+ // Import the EnhancedInfo type from the decoder package
8
+ type EnhancedInfo = {
9
+ address: `0x${string}`
10
+ standard?: string
11
+ tokenId?: `0x${string}`
12
+ name?: string
13
+ __gqltype?: 'Profile' | 'Asset' | 'Token'
14
+ [key: string]: unknown
15
+ }
16
+
17
+ export interface TransactionInfo {
18
+ /** Transaction hash */
19
+ hash?: string
20
+ /** Block number */
21
+ blockNumber?: bigint | string
22
+ /** Block timestamp */
23
+ timestamp?: bigint | string | Date
24
+ /** Gas used */
25
+ gasUsed?: bigint | string
26
+ /** Gas price */
27
+ gasPrice?: bigint | string
28
+ /** Transaction status */
29
+ status?: 'success' | 'failed' | 'pending'
30
+ /** Network/chain name */
31
+ network?: string
32
+ }
33
+
34
+ export interface DescriptionItem {
35
+ /** Label for the description item */
36
+ label: string
37
+ /** Value to display */
38
+ value: string
39
+ /** Optional secondary value or subtitle */
40
+ subtitle?: string
41
+ /** Whether this item is highlighted */
42
+ highlighted?: boolean
43
+ /** Whether to show copy button */
44
+ copyable?: boolean
45
+ /** Custom icon for this item */
46
+ icon?: string
47
+ /** Link URL if this item should be clickable */
48
+ link?: string
49
+ }
50
+
51
+ export interface DescriptionViewData {
52
+ /** Main title/heading */
53
+ title?: string
54
+ /** Main description text */
55
+ description?: string
56
+ /** Address key (format: "ADDRESS" or "ADDRESS-TOKENID") */
57
+ address?: string
58
+ /** Value being transferred */
59
+ value?: bigint | string
60
+ /** Raw transaction object */
61
+ transaction?: any // DecoderResult type from decoder package
62
+ /** Enhanced info from decoder (contains metadata) */
63
+ enhancedInfo?: EnhancedInfo
64
+ /** Transaction-specific information */
65
+ transactionInfo?: TransactionInfo
66
+ /** Additional custom items to display */
67
+ customItems?: DescriptionItem[]
68
+ /** Transaction type for styling */
69
+ type?: 'transfer' | 'mint' | 'burn' | 'approve' | 'execute' | 'deploy'
70
+ /** Loading state */
71
+ loading?: boolean
72
+ }
73
+
74
+ /**
75
+ * Description view component for displaying transaction details and metadata
76
+ * Provides flexible key-value display with support for various transaction types
77
+ */
78
+ @safeCustomElement('description-view')
79
+ export class DescriptionView extends LitElement {
80
+ @property({ type: Object })
81
+ data: DescriptionViewData = {}
82
+
83
+ @property({ type: String })
84
+ variant: 'default' | 'compact' | 'detailed' = 'default'
85
+
86
+ static styles = css`
87
+ :host {
88
+ display: block;
89
+ font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;
90
+ }
91
+
92
+ .description-container {
93
+ background: white;
94
+ border-radius: 12px;
95
+ padding: 16px;
96
+ border: 1px solid #e5e7eb;
97
+ }
98
+
99
+ .compact .description-container {
100
+ padding: 12px;
101
+ border-radius: 8px;
102
+ }
103
+
104
+ .detailed .description-container {
105
+ padding: 20px;
106
+ border-radius: 16px;
107
+ }
108
+
109
+ .header {
110
+ margin-bottom: 16px;
111
+ }
112
+
113
+ .compact .header {
114
+ margin-bottom: 12px;
115
+ }
116
+
117
+ .detailed .header {
118
+ margin-bottom: 20px;
119
+ }
120
+
121
+ .title {
122
+ font-size: 16px;
123
+ font-weight: 600;
124
+ color: #111827;
125
+ margin: 0 0 8px 0;
126
+ display: flex;
127
+ align-items: center;
128
+ gap: 8px;
129
+ }
130
+
131
+ .compact .title {
132
+ font-size: 14px;
133
+ margin-bottom: 6px;
134
+ }
135
+
136
+ .detailed .title {
137
+ font-size: 18px;
138
+ margin-bottom: 12px;
139
+ }
140
+
141
+ .type-badge {
142
+ display: inline-flex;
143
+ align-items: center;
144
+ padding: 4px 8px;
145
+ border-radius: 12px;
146
+ font-size: 11px;
147
+ font-weight: 600;
148
+ text-transform: uppercase;
149
+ letter-spacing: 0.5px;
150
+ }
151
+
152
+ .type-badge.transfer {
153
+ background: #dbeafe;
154
+ color: #1d4ed8;
155
+ }
156
+
157
+ .type-badge.mint {
158
+ background: #d1fae5;
159
+ color: #059669;
160
+ }
161
+
162
+ .type-badge.burn {
163
+ background: #fee2e2;
164
+ color: #dc2626;
165
+ }
166
+
167
+ .type-badge.approve {
168
+ background: #fef3c7;
169
+ color: #d97706;
170
+ }
171
+
172
+ .type-badge.execute {
173
+ background: #e0e7ff;
174
+ color: #4338ca;
175
+ }
176
+
177
+ .type-badge.deploy {
178
+ background: #f3e8ff;
179
+ color: #7c3aed;
180
+ }
181
+
182
+ .description {
183
+ font-size: 14px;
184
+ line-height: 1.5;
185
+ color: #6b7280;
186
+ margin: 0;
187
+ }
188
+
189
+ .compact .description {
190
+ font-size: 13px;
191
+ }
192
+
193
+ .detailed .description {
194
+ font-size: 15px;
195
+ line-height: 1.6;
196
+ }
197
+
198
+ .items-list {
199
+ display: flex;
200
+ flex-direction: column;
201
+ gap: 12px;
202
+ margin-top: 16px;
203
+ }
204
+
205
+ .compact .items-list {
206
+ gap: 8px;
207
+ margin-top: 12px;
208
+ }
209
+
210
+ .detailed .items-list {
211
+ gap: 16px;
212
+ margin-top: 20px;
213
+ }
214
+
215
+ .description-item {
216
+ display: flex;
217
+ justify-content: space-between;
218
+ align-items: flex-start;
219
+ padding: 12px;
220
+ background: #f9fafb;
221
+ border-radius: 8px;
222
+ border: 1px solid #e5e7eb;
223
+ transition: all 0.2s ease;
224
+ }
225
+
226
+ .compact .description-item {
227
+ padding: 8px;
228
+ border-radius: 6px;
229
+ }
230
+
231
+ .detailed .description-item {
232
+ padding: 16px;
233
+ border-radius: 12px;
234
+ }
235
+
236
+ .description-item.highlighted {
237
+ background: #eff6ff;
238
+ border-color: #3b82f6;
239
+ box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.1);
240
+ }
241
+
242
+ .description-item.clickable {
243
+ cursor: pointer;
244
+ }
245
+
246
+ .description-item.clickable:hover {
247
+ background: #f3f4f6;
248
+ border-color: #d1d5db;
249
+ }
250
+
251
+ .description-item.highlighted.clickable:hover {
252
+ background: #dbeafe;
253
+ }
254
+
255
+ .item-label {
256
+ display: flex;
257
+ align-items: center;
258
+ gap: 8px;
259
+ font-size: 13px;
260
+ font-weight: 500;
261
+ color: #374151;
262
+ flex-shrink: 0;
263
+ min-width: 0;
264
+ }
265
+
266
+ .compact .item-label {
267
+ font-size: 12px;
268
+ gap: 6px;
269
+ }
270
+
271
+ .detailed .item-label {
272
+ font-size: 14px;
273
+ }
274
+
275
+ .item-icon {
276
+ font-size: 14px;
277
+ flex-shrink: 0;
278
+ }
279
+
280
+ .item-value-section {
281
+ display: flex;
282
+ flex-direction: column;
283
+ align-items: flex-end;
284
+ gap: 4px;
285
+ min-width: 0;
286
+ flex: 1;
287
+ margin-left: 12px;
288
+ }
289
+
290
+ .item-value {
291
+ font-size: 14px;
292
+ font-weight: 500;
293
+ color: #111827;
294
+ word-break: break-all;
295
+ text-align: right;
296
+ }
297
+
298
+ .compact .item-value {
299
+ font-size: 13px;
300
+ }
301
+
302
+ .detailed .item-value {
303
+ font-size: 15px;
304
+ }
305
+
306
+ .item-subtitle {
307
+ font-size: 12px;
308
+ color: #6b7280;
309
+ text-align: right;
310
+ }
311
+
312
+ .compact .item-subtitle {
313
+ font-size: 11px;
314
+ }
315
+
316
+ .item-actions {
317
+ display: flex;
318
+ align-items: center;
319
+ gap: 4px;
320
+ margin-left: 8px;
321
+ }
322
+
323
+ .copy-button {
324
+ background: none;
325
+ border: none;
326
+ cursor: pointer;
327
+ padding: 4px;
328
+ border-radius: 4px;
329
+ color: #6b7280;
330
+ transition: all 0.2s ease;
331
+ font-size: 14px;
332
+ }
333
+
334
+ .copy-button:hover {
335
+ background-color: #e5e7eb;
336
+ color: #374151;
337
+ }
338
+
339
+ .external-link {
340
+ color: #3b82f6;
341
+ text-decoration: none;
342
+ font-size: 14px;
343
+ }
344
+
345
+ .external-link:hover {
346
+ text-decoration: underline;
347
+ }
348
+
349
+ .loading-state {
350
+ display: flex;
351
+ flex-direction: column;
352
+ align-items: center;
353
+ justify-content: center;
354
+ padding: 40px 20px;
355
+ color: #6b7280;
356
+ }
357
+
358
+ .loading-spinner {
359
+ font-size: 24px;
360
+ margin-bottom: 12px;
361
+ }
362
+
363
+ .loading-text {
364
+ font-size: 14px;
365
+ }
366
+ `
367
+
368
+ private _copyToClipboard(text: string) {
369
+ if (navigator.clipboard) {
370
+ navigator.clipboard.writeText(text)
371
+ this.dispatchEvent(
372
+ new CustomEvent('copied', {
373
+ detail: { text },
374
+ })
375
+ )
376
+ }
377
+ }
378
+
379
+ private _handleItemClick(item: DescriptionItem) {
380
+ if (item.link) {
381
+ window.open(item.link, '_blank', 'noopener,noreferrer')
382
+ }
383
+ this.dispatchEvent(
384
+ new CustomEvent('item-click', {
385
+ detail: { item },
386
+ })
387
+ )
388
+ }
389
+
390
+ private _renderHeader() {
391
+ if (!this.data.title && !this.data.description && !this.data.type) return ''
392
+
393
+ return html`
394
+ <div class="header">
395
+ ${when(
396
+ this.data.title,
397
+ () => html`
398
+ <h2 class="title">
399
+ ${this.data.title}
400
+ ${when(
401
+ this.data.type,
402
+ () => html`
403
+ <span class="type-badge ${this.data.type}">
404
+ ${this.data.type}
405
+ </span>
406
+ `
407
+ )}
408
+ </h2>
409
+ `
410
+ )}
411
+
412
+ ${when(
413
+ this.data.description,
414
+ () => html`
415
+ <p class="description">${this.data.description}</p>
416
+ `
417
+ )}
418
+ </div>
419
+ `
420
+ }
421
+
422
+ private _renderItems() {
423
+ // Build items from various data sources
424
+ const items: DescriptionItem[] = []
425
+
426
+ // Add address information
427
+ if (this.data.address) {
428
+ const [contractAddress, tokenId] = this.data.address.split('-')
429
+
430
+ items.push({
431
+ label: 'Contract Address',
432
+ value: contractAddress,
433
+ icon: '📄',
434
+ copyable: true,
435
+ })
436
+
437
+ if (tokenId) {
438
+ items.push({
439
+ label: 'Token ID',
440
+ value: `#${tokenId}`,
441
+ subtitle: tokenId,
442
+ icon: '🏷️',
443
+ copyable: true,
444
+ })
445
+ }
446
+ }
447
+
448
+ // Add value information
449
+ if (this.data.value) {
450
+ items.push({
451
+ label: 'Amount',
452
+ value: this.data.value.toString(),
453
+ icon: '💰',
454
+ highlighted: true,
455
+ })
456
+ }
457
+
458
+ // Add transaction information
459
+ if (this.data.transactionInfo) {
460
+ const txInfo = this.data.transactionInfo
461
+
462
+ if (txInfo.hash) {
463
+ items.push({
464
+ label: 'Transaction Hash',
465
+ value: txInfo.hash,
466
+ icon: '🔗',
467
+ copyable: true,
468
+ })
469
+ }
470
+
471
+ if (txInfo.blockNumber) {
472
+ items.push({
473
+ label: 'Block Number',
474
+ value: txInfo.blockNumber.toString(),
475
+ icon: '🧱',
476
+ })
477
+ }
478
+
479
+ if (txInfo.status) {
480
+ items.push({
481
+ label: 'Status',
482
+ value: txInfo.status.charAt(0).toUpperCase() + txInfo.status.slice(1),
483
+ icon:
484
+ txInfo.status === 'success'
485
+ ? '✅'
486
+ : txInfo.status === 'failed'
487
+ ? '❌'
488
+ : '⏳',
489
+ highlighted: txInfo.status !== 'success',
490
+ })
491
+ }
492
+ }
493
+
494
+ // Add enhanced info metadata
495
+ if (this.data.enhancedInfo) {
496
+ const info = this.data.enhancedInfo
497
+
498
+ if (info.name) {
499
+ items.push({
500
+ label: 'Asset Name',
501
+ value: info.name,
502
+ icon: '🏷️',
503
+ })
504
+ }
505
+
506
+ if (info.standard) {
507
+ items.push({
508
+ label: 'Standard',
509
+ value: info.standard,
510
+ icon: '📋',
511
+ })
512
+ }
513
+ }
514
+
515
+ // Add custom items
516
+ if (this.data.customItems?.length) {
517
+ items.push(...this.data.customItems)
518
+ }
519
+
520
+ if (!items.length) return ''
521
+
522
+ return html`
523
+ <div class="items-list">
524
+ ${repeat(
525
+ items,
526
+ (item) => `${item.label}-${item.value}`,
527
+ (item) => html`
528
+ <div
529
+ class="description-item ${item.highlighted ? 'highlighted' : ''} ${item.link ? 'clickable' : ''}"
530
+ @click=${item.link ? () => this._handleItemClick(item) : undefined}
531
+ >
532
+ <div class="item-label">
533
+ ${when(
534
+ item.icon,
535
+ () => html`<span class="item-icon">${item.icon}</span>`
536
+ )}
537
+ ${item.label}
538
+ </div>
539
+
540
+ <div class="item-value-section">
541
+ <div class="item-value">
542
+ ${
543
+ item.link
544
+ ? html`<a class="external-link" href="${item.link}" target="_blank" rel="noopener noreferrer">${item.value}</a>`
545
+ : item.value
546
+ }
547
+ </div>
548
+ ${when(
549
+ item.subtitle,
550
+ () => html`<div class="item-subtitle">${item.subtitle}</div>`
551
+ )}
552
+ </div>
553
+
554
+ <div class="item-actions">
555
+ ${when(
556
+ item.copyable,
557
+ () => html`
558
+ <button
559
+ class="copy-button"
560
+ @click=${(e: Event) => {
561
+ e.stopPropagation()
562
+ this._copyToClipboard(item.value)
563
+ }}
564
+ title="Copy to clipboard"
565
+ >
566
+ 📋
567
+ </button>
568
+ `
569
+ )}
570
+ </div>
571
+ </div>
572
+ `
573
+ )}
574
+ </div>
575
+ `
576
+ }
577
+
578
+ render() {
579
+ if (this.data.loading) {
580
+ return html`
581
+ <div class="description-container">
582
+ <div class="loading-state">
583
+ <div class="loading-spinner">⏳</div>
584
+ <div class="loading-text">Loading details...</div>
585
+ </div>
586
+ </div>
587
+ `
588
+ }
589
+
590
+ return html`
591
+ <div class="${this.variant} description-view">
592
+ <div class="description-container">
593
+ ${this._renderHeader()}
594
+ ${this._renderItems()}
595
+ </div>
596
+ </div>
597
+ `
598
+ }
599
+ }
600
+
601
+ declare global {
602
+ interface HTMLElementTagNameMap {
603
+ 'description-view': DescriptionView
604
+ }
605
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Components index - imports all components to ensure they are registered as custom elements
3
+ */
4
+
5
+ // Import all Lit components to ensure they are defined as custom elements
6
+ import './universal-token-view.js'
7
+ import './asset-card.js'
8
+ import './info-panel.js'
9
+ import './description-view.js'
10
+ import './contract-card.js'
11
+ import './transaction-playback.js'
12
+ import './permissions-block.js'
13
+
14
+ // Import shared components
15
+ import '../shared/address-display.js'
16
+ import '../shared/address-view.js'
17
+ import '../shared/value-view.js'
18
+
19
+ // This file is imported dynamically to ensure all web components are registered
20
+ // when the transaction view system is initialized