@lukso/transaction-view-core 0.6.3-dev.a07a66f → 0.6.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukso/transaction-view-core",
3
- "version": "0.6.3-dev.a07a66f",
3
+ "version": "0.6.3",
4
4
  "description": "Core components and hooks for LUKSO transaction display",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -31,12 +31,12 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@lit/task": "^1.0.3",
34
- "@lukso/web-components": "^1.172.18",
34
+ "@lukso/web-components": "^1.172.17",
35
35
  "@preact/signals-core": "^1.12.1",
36
36
  "ethereum-blockies-base64": "^1.0.2",
37
- "lit": "3.3.1",
38
- "@lukso/transaction-decoder": "1.3.3-dev.a07a66f",
39
- "@lukso/transaction-view-headless": "0.4.3-dev.a07a66f"
37
+ "lit": "^3.3.1",
38
+ "@lukso/transaction-decoder": "1.3.3",
39
+ "@lukso/transaction-view-headless": "0.4.3"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@tailwindcss/typography": "^0.5.19",
@@ -1,21 +1,17 @@
1
1
  import type { DecoderResult } from '@lukso/transaction-decoder'
2
2
  import {
3
3
  createTransactionPlayback,
4
- isHeaderInfoEvent,
5
4
  type PlaybackIndexResult,
6
- type TransactionHeaderInfo,
7
5
  type TransactionPlaybackState,
8
- TransactionViewEvents,
9
6
  type ViewContext,
10
7
  type ViewVariant,
11
8
  } from '@lukso/transaction-view-headless'
12
- import { html, type PropertyValues } from 'lit'
9
+ import { css, html, LitElement, type PropertyValues } from 'lit'
13
10
  import { property, state } from 'lit/decorators.js'
14
11
  import { createRef, type Ref, ref } from 'lit/directives/ref.js'
15
12
  import { when } from 'lit/directives/when.js'
16
13
  import { getGlobalLitLoader } from '../registry/lit-view-loader'
17
14
  import { safeCustomElement } from '../shared/safe-custom-element'
18
- import { CoreLitElement } from '../styles'
19
15
 
20
16
  /**
21
17
  * Lit Transaction Playback Component
@@ -38,11 +34,6 @@ import { CoreLitElement } from '../styles'
38
34
  * - context: WHERE the transaction is displayed (approval, feed, list, detail, etc.)
39
35
  * - variant: HOW the transaction should be rendered (full, collapsed, minimal, etc.)
40
36
  *
41
- * **Header Events:**
42
- * - Listens for 'header-info' events from child views
43
- * - Child views can emit header-info to override default from/to addresses
44
- * - Example: Transfer view can show transfer's from/to instead of execute's from/to
45
- *
46
37
  * @example
47
38
  * ```html
48
39
  * <!-- Activity feed: compact view -->
@@ -51,7 +42,6 @@ import { CoreLitElement } from '../styles'
51
42
  * index="1"
52
43
  * context="feed"
53
44
  * variant="compact"
54
- * @header-info="${(e) => console.log('Header:', e.detail)}"
55
45
  * ></transaction-playback>
56
46
  *
57
47
  * <!-- Approval flow: full detailed view -->
@@ -72,7 +62,7 @@ import { CoreLitElement } from '../styles'
72
62
  * ```
73
63
  */
74
64
  @safeCustomElement('transaction-playback')
75
- export class TransactionPlayback extends CoreLitElement {
65
+ export class TransactionPlayback extends LitElement {
76
66
  /** The root transaction to display */
77
67
  @property({ type: Object })
78
68
  transaction?: DecoderResult
@@ -81,9 +71,9 @@ export class TransactionPlayback extends CoreLitElement {
81
71
  @property({ type: Number })
82
72
  index = 1 // Default to index 1 (main transaction, skips batch summary)
83
73
 
84
- /** Fallback view ID if no match found (optional - fallback-screen is registered with lowest priority) */
74
+ /** Fallback view ID if no match found */
85
75
  @property({ type: String })
86
- fallbackViewId?: string
76
+ fallbackViewId = 'universal-execute'
87
77
 
88
78
  /** Context: WHERE the transaction is displayed */
89
79
  @property({ type: String })
@@ -112,12 +102,123 @@ export class TransactionPlayback extends CoreLitElement {
112
102
  @state()
113
103
  private loadedComponent?: HTMLElement
114
104
 
115
- @state()
116
- private headerInfo?: TransactionHeaderInfo
117
-
118
105
  private componentContainerRef: Ref<HTMLDivElement> = createRef()
119
106
  private loader = getGlobalLitLoader()
120
107
 
108
+ static styles = css`
109
+ :host {
110
+ display: block;
111
+ font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;
112
+ }
113
+
114
+ .playback-container {
115
+ position: relative;
116
+ }
117
+
118
+ .loading-state {
119
+ display: flex;
120
+ flex-direction: column;
121
+ align-items: center;
122
+ justify-content: center;
123
+ padding: 60px 20px;
124
+ color: #6b7280;
125
+ }
126
+
127
+ .loading-spinner {
128
+ font-size: 32px;
129
+ margin-bottom: 16px;
130
+ animation: spin 2s linear infinite;
131
+ }
132
+
133
+ @keyframes spin {
134
+ from {
135
+ transform: rotate(0deg);
136
+ }
137
+ to {
138
+ transform: rotate(360deg);
139
+ }
140
+ }
141
+
142
+ .loading-text {
143
+ font-size: 16px;
144
+ font-weight: 500;
145
+ }
146
+
147
+ .error-state {
148
+ display: flex;
149
+ flex-direction: column;
150
+ align-items: center;
151
+ justify-content: center;
152
+ padding: 60px 20px;
153
+ color: #dc2626;
154
+ background: #fef2f2;
155
+ border: 1px solid #fecaca;
156
+ border-radius: 12px;
157
+ margin: 20px;
158
+ }
159
+
160
+ .error-icon {
161
+ font-size: 48px;
162
+ margin-bottom: 16px;
163
+ }
164
+
165
+ .error-title {
166
+ font-size: 18px;
167
+ font-weight: 600;
168
+ margin-bottom: 8px;
169
+ }
170
+
171
+ .error-message {
172
+ font-size: 14px;
173
+ text-align: center;
174
+ line-height: 1.4;
175
+ }
176
+
177
+ .debug-panel {
178
+ margin-top: 16px;
179
+ padding: 12px;
180
+ background: #f9fafb;
181
+ border: 1px solid #e5e7eb;
182
+ border-radius: 8px;
183
+ font-size: 12px;
184
+ font-family: 'Monaco', 'Menlo', monospace;
185
+ }
186
+
187
+ .debug-title {
188
+ font-weight: 600;
189
+ margin-bottom: 8px;
190
+ color: #374151;
191
+ }
192
+
193
+ .debug-item {
194
+ display: flex;
195
+ gap: 8px;
196
+ margin-bottom: 4px;
197
+ }
198
+
199
+ .debug-label {
200
+ font-weight: 500;
201
+ color: #6b7280;
202
+ }
203
+
204
+ .debug-value {
205
+ color: #111827;
206
+ }
207
+
208
+ .debug-valid {
209
+ color: #059669;
210
+ }
211
+
212
+ .debug-invalid {
213
+ color: #dc2626;
214
+ }
215
+
216
+ /* Component container for dynamically loaded content */
217
+ .component-container {
218
+ display: contents;
219
+ }
220
+ `
221
+
121
222
  protected willUpdate(changedProperties: PropertyValues): void {
122
223
  // Reload when transaction, index, context, or variant changes
123
224
  if (
@@ -140,38 +241,6 @@ export class TransactionPlayback extends CoreLitElement {
140
241
  }
141
242
  }
142
243
 
143
- connectedCallback(): void {
144
- super.connectedCallback()
145
- // Listen for header-info events from child views
146
- this.addEventListener(
147
- TransactionViewEvents.HEADER_INFO,
148
- this.handleHeaderInfo as EventListener
149
- )
150
- }
151
-
152
- disconnectedCallback(): void {
153
- super.disconnectedCallback()
154
- this.removeEventListener(
155
- TransactionViewEvents.HEADER_INFO,
156
- this.handleHeaderInfo as EventListener
157
- )
158
- }
159
-
160
- private handleHeaderInfo = (event: Event): void => {
161
- if (isHeaderInfoEvent(event)) {
162
- this.headerInfo = event.detail
163
-
164
- // Re-emit the event so parent containers can also listen
165
- this.dispatchEvent(
166
- new CustomEvent(TransactionViewEvents.HEADER_INFO, {
167
- bubbles: true,
168
- composed: true,
169
- detail: event.detail,
170
- })
171
- )
172
- }
173
- }
174
-
175
244
  private async loadView() {
176
245
  if (!this.transaction) {
177
246
  this.error = 'No transaction provided'
@@ -181,7 +250,6 @@ export class TransactionPlayback extends CoreLitElement {
181
250
  this.isLoading = true
182
251
  this.error = undefined
183
252
  this.loadedComponent = undefined
184
- this.headerInfo = undefined // Reset header info on new load
185
253
 
186
254
  try {
187
255
  // Create playback state
@@ -213,11 +281,13 @@ export class TransactionPlayback extends CoreLitElement {
213
281
  )
214
282
 
215
283
  // Create component instance with transaction data
216
- // Pass transaction (required) and context/variant (optional) for context-aware rendering
217
284
  this.loadedComponent = this.loader.createInstance(componentClass, {
218
285
  transaction: this.currentResult.transaction,
219
- ...(this.context && { context: this.context }),
220
- ...(this.variant && { variant: this.variant }),
286
+ address: (this.currentResult.transaction as any).address,
287
+ value: (this.currentResult.transaction as any).value,
288
+ enhancedInfo: (this.currentResult.transaction as any).enhancedInfo,
289
+ title: this.generateTitle(this.currentResult),
290
+ standard: (this.currentResult.transaction as any).standard,
221
291
  })
222
292
 
223
293
  this.isLoading = false
@@ -229,92 +299,87 @@ export class TransactionPlayback extends CoreLitElement {
229
299
  }
230
300
  }
231
301
 
302
+ private generateTitle(result: PlaybackIndexResult): string {
303
+ if (result.indexInfo.isBatchSummary) {
304
+ const childCount = result.batchInfo.childCount
305
+ return `Batch Operation (${childCount} ${childCount === 1 ? 'transaction' : 'transactions'})`
306
+ }
307
+
308
+ const transaction = result.transaction
309
+ if (!transaction) return 'Transaction'
310
+
311
+ const resultType = transaction.resultType
312
+
313
+ if (!resultType) return 'Transaction'
314
+
315
+ switch (resultType) {
316
+ case 'setData':
317
+ case 'setDataBatch':
318
+ return 'Set Data'
319
+ case 'execute':
320
+ case 'executeBatch':
321
+ return 'Execute'
322
+ case 'create':
323
+ return 'Contract Deployment'
324
+ default:
325
+ if (resultType.includes('transfer')) {
326
+ return 'Transfer'
327
+ }
328
+ return resultType.charAt(0).toUpperCase() + resultType.slice(1)
329
+ }
330
+ }
331
+
232
332
  private renderDebugPanel() {
233
333
  if (!this.debug || !this.playbackState || !this.currentResult) {
234
334
  return html``
235
335
  }
236
336
 
237
337
  return html`
238
- <div class="mt-4 p-3 bg-neutral-10 border border-neutral-20 rounded-lg text-12 font-mono">
239
- <div class="font-600 mb-2 text-neutral-80">🐛 Playback Debug Info</div>
240
- <div class="flex gap-2 mb-1">
241
- <span class="font-500 text-neutral-60">Requested Index:</span>
242
- <span class="text-neutral-100">${this.currentResult.indexInfo.requested}</span>
338
+ <div class="debug-panel">
339
+ <div class="debug-title">🐛 Playback Debug Info</div>
340
+ <div class="debug-item">
341
+ <span class="debug-label">Requested Index:</span>
342
+ <span class="debug-value">${this.currentResult.indexInfo.requested}</span>
243
343
  </div>
244
- <div class="flex gap-2 mb-1">
245
- <span class="font-500 text-neutral-60">Is Valid:</span>
246
- <span class="${this.currentResult.indexInfo.isValid ? 'text-green-600' : 'text-red-600'}">
344
+ <div class="debug-item">
345
+ <span class="debug-label">Is Valid:</span>
346
+ <span class="${this.currentResult.indexInfo.isValid ? 'debug-valid' : 'debug-invalid'}">
247
347
  ${this.currentResult.indexInfo.isValid ? '✓ Yes' : '✗ No'}
248
348
  </span>
249
349
  </div>
250
- <div class="flex gap-2 mb-1">
251
- <span class="font-500 text-neutral-60">Is Batch:</span>
252
- <span class="text-neutral-100">
350
+ <div class="debug-item">
351
+ <span class="debug-label">Is Batch:</span>
352
+ <span class="debug-value">
253
353
  ${this.playbackState.isBatch ? 'Yes' : 'No'}
254
354
  </span>
255
355
  </div>
256
- <div class="flex gap-2 mb-1">
257
- <span class="font-500 text-neutral-60">Is Batch Summary:</span>
258
- <span class="text-neutral-100">
356
+ <div class="debug-item">
357
+ <span class="debug-label">Is Batch Summary:</span>
358
+ <span class="debug-value">
259
359
  ${this.currentResult.indexInfo.isBatchSummary ? 'Yes' : 'No'}
260
360
  </span>
261
361
  </div>
262
362
  ${when(
263
363
  this.currentResult.indexInfo.childIndex != null,
264
364
  () => html`
265
- <div class="flex gap-2 mb-1">
266
- <span class="font-500 text-neutral-60">Child Index:</span>
267
- <span class="text-neutral-100">${this.currentResult?.indexInfo.childIndex}</span>
365
+ <div class="debug-item">
366
+ <span class="debug-label">Child Index:</span>
367
+ <span class="debug-value">${this.currentResult?.indexInfo.childIndex}</span>
268
368
  </div>
269
369
  `
270
370
  )}
271
- <div class="flex gap-2 mb-1">
272
- <span class="font-500 text-neutral-60">Available Indices:</span>
273
- <span class="text-neutral-100">
371
+ <div class="debug-item">
372
+ <span class="debug-label">Available Indices:</span>
373
+ <span class="debug-value">
274
374
  [${this.playbackState?.batchInfo.availableIndices.join(', ')}]
275
375
  </span>
276
376
  </div>
277
377
  ${when(
278
378
  this.currentResult.match,
279
379
  () => html`
280
- <div class="flex gap-2 mb-1">
281
- <span class="font-500 text-neutral-60">Matched View:</span>
282
- <span class="text-neutral-100">${this.currentResult?.match?.view.id}</span>
283
- </div>
284
- `
285
- )}
286
- ${when(
287
- this.headerInfo,
288
- () => html`
289
- <div class="mt-2 pt-2 border-t border-neutral-20">
290
- <div class="font-600 mb-1 text-neutral-80">📋 Header Info</div>
291
- ${when(
292
- this.headerInfo?.from,
293
- () => html`
294
- <div class="flex gap-2 mb-1">
295
- <span class="font-500 text-neutral-60">From:</span>
296
- <span class="text-neutral-100">${this.headerInfo?.from}</span>
297
- </div>
298
- `
299
- )}
300
- ${when(
301
- this.headerInfo?.to,
302
- () => html`
303
- <div class="flex gap-2 mb-1">
304
- <span class="font-500 text-neutral-60">To:</span>
305
- <span class="text-neutral-100">${this.headerInfo?.to}</span>
306
- </div>
307
- `
308
- )}
309
- ${when(
310
- this.headerInfo?.title,
311
- () => html`
312
- <div class="flex gap-2 mb-1">
313
- <span class="font-500 text-neutral-60">Title:</span>
314
- <span class="text-neutral-100">${this.headerInfo?.title}</span>
315
- </div>
316
- `
317
- )}
380
+ <div class="debug-item">
381
+ <span class="debug-label">Matched View:</span>
382
+ <span class="debug-value">${this.currentResult?.match?.view.id}</span>
318
383
  </div>
319
384
  `
320
385
  )}
@@ -326,9 +391,9 @@ export class TransactionPlayback extends CoreLitElement {
326
391
  // Loading state
327
392
  if (this.isLoading) {
328
393
  return html`
329
- <div class="flex flex-col items-center justify-center py-15 px-5 text-neutral-60">
330
- <div class="text-32 mb-4 animate-spin">⏳</div>
331
- <div class="text-16 font-500">Loading transaction view...</div>
394
+ <div class="loading-state">
395
+ <div class="loading-spinner">⏳</div>
396
+ <div class="loading-text">Loading transaction view...</div>
332
397
  </div>
333
398
  `
334
399
  }
@@ -336,42 +401,19 @@ export class TransactionPlayback extends CoreLitElement {
336
401
  // Error state
337
402
  if (this.error) {
338
403
  return html`
339
- <div class="flex flex-col items-center justify-center py-15 px-5 text-red-600 bg-red-50 border border-red-200 rounded-xl m-5">
340
- <div class="text-48 mb-4">❌</div>
341
- <div class="text-18 font-600 mb-2">Error</div>
342
- <div class="text-14 text-center leading-normal">${this.error}</div>
404
+ <div class="error-state">
405
+ <div class="error-icon">❌</div>
406
+ <div class="error-title">Error</div>
407
+ <div class="error-message">${this.error}</div>
343
408
  </div>
344
409
  ${this.renderDebugPanel()}
345
410
  `
346
411
  }
347
412
 
348
- // Batch summary rendering (index 0 of executeBatch)
349
- if (this.currentResult?.indexInfo.isBatchSummary && this.transaction) {
350
- const children = (this.transaction as any).children || []
351
- return html`
352
- <div class="relative">
353
- <div class="flex flex-col gap-4">
354
- ${children.map(
355
- (child: any) => html`
356
- <transaction-playback
357
- .transaction=${child}
358
- .index=${1}
359
- context="summary"
360
- .variant=${this.variant}
361
- ?debug=${this.debug}
362
- ></transaction-playback>
363
- `
364
- )}
365
- </div>
366
- ${this.renderDebugPanel()}
367
- </div>
368
- `
369
- }
370
-
371
- // Render loaded component (single transaction or batch child)
413
+ // Render loaded component
372
414
  return html`
373
- <div class="relative">
374
- <div class="contents" ${ref(this.componentContainerRef)}>
415
+ <div class="playback-container">
416
+ <div class="component-container" ${ref(this.componentContainerRef)}>
375
417
  <!-- Component will be mounted here via updated() lifecycle -->
376
418
  </div>
377
419
  ${this.renderDebugPanel()}
package/src/index.ts CHANGED
@@ -18,7 +18,6 @@ import './components/description-view.js'
18
18
  import './components/universal-token-view.js'
19
19
  import './components/contract-card.js'
20
20
  import './components/permissions-block.js'
21
- import './components/transaction-playback.js'
22
21
 
23
22
  // Explicit import/export for fonts to ensure d.ts generation doesn't tree-shake it
24
23