@lukso/transaction-view-core 0.4.1 → 0.5.0-dev.5916302
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 +20 -20
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +15 -0
- package/dist/index.cjs +131 -220
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -10
- package/dist/index.d.ts +1 -10
- package/dist/index.js +158 -252
- package/dist/index.js.map +1 -1
- package/dist/shared/index.cjs +31 -64
- package/dist/shared/index.cjs.map +1 -1
- package/dist/shared/index.d.cts +8 -20
- package/dist/shared/index.d.ts +8 -20
- package/dist/shared/index.js +43 -76
- package/dist/shared/index.js.map +1 -1
- package/dist/styles/index.cjs +1 -1
- package/dist/styles/index.cjs.map +1 -1
- package/dist/styles/index.js +1 -1
- package/dist/styles/index.js.map +1 -1
- package/package.json +5 -4
- package/src/components/asset-card.ts +63 -80
- package/src/components/contract-card.ts +2 -67
- package/src/components/info-panel.ts +1 -21
- package/src/components/permissions-block.ts +7 -5
- package/src/components/transaction-playback.ts +4 -4
- package/src/index.ts +1 -1
- package/src/shared/address-display.ts +3 -6
- package/src/shared/address-view.ts +2 -18
- package/src/shared/custom-select.ts +1 -1
- package/src/shared/function-name-view.ts +1 -1
- package/src/shared/gas-provider-view.ts +4 -7
- package/src/shared/icon-view.ts +7 -9
- package/src/shared/image-list.ts +3 -4
- package/src/shared/load-web-components.ts +3 -2
- package/src/shared/notification-view.ts +3 -3
- package/src/shared/progress-view.ts +1 -10
- package/src/shared/scroll-to-bottom-button.ts +1 -1
- package/src/shared/signal-controller.ts +3 -1
- package/src/shared/transaction-view-controller.ts +1 -1
- package/src/shared/url-view.ts +3 -3
- package/src/shared/value-view.ts +10 -30
- package/src/styles/styles.css +1 -1
- package/src/utils.test.ts +47 -0
- package/src/utils.ts +82 -0
- package/src/vue-entry.ts +0 -1
- package/tsup.config.ts +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { html } from 'lit'
|
|
2
|
-
import {
|
|
2
|
+
import { property, state } from 'lit/decorators.js'
|
|
3
3
|
import { safeCustomElement } from './safe-custom-element'
|
|
4
4
|
import './load-web-components'
|
|
5
5
|
import { CoreLitElement } from '../styles'
|
|
@@ -58,7 +58,7 @@ export class NotificationView extends CoreLitElement {
|
|
|
58
58
|
return html`
|
|
59
59
|
<div class="grid grid-cols-[24px_1fr] items-start gap-3 p-3 rounded-xl text-neutral-10 leading-snug ${this.getVariantBackgroundClass()}">
|
|
60
60
|
<div class="flex items-center justify-center text-[16px] text-neutral-20 self-center" aria-hidden="true">
|
|
61
|
-
<lukso-icon name="${this.renderIcon()}" size="
|
|
61
|
+
<lukso-icon name="${this.renderIcon()}" size="small" color="${this.getVariantColor()}"></lukso-icon>
|
|
62
62
|
</div>
|
|
63
63
|
<div class="text-[14px] flex flex-col gap-1.5">
|
|
64
64
|
${
|
|
@@ -66,7 +66,7 @@ export class NotificationView extends CoreLitElement {
|
|
|
66
66
|
? html`<div class="font-semibold text-neutral-20 paragraph-inter-14-semi-bold">${this.title}</div>`
|
|
67
67
|
: ''
|
|
68
68
|
}
|
|
69
|
-
<div class="text-neutral-
|
|
69
|
+
<div class="text-neutral-20"><slot>${this.message}</slot></div>
|
|
70
70
|
${
|
|
71
71
|
this.acknowledgeable
|
|
72
72
|
? html`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { html } from 'lit'
|
|
2
|
-
import {
|
|
2
|
+
import { property } from 'lit/decorators.js'
|
|
3
3
|
import { CoreLitElement } from '../styles'
|
|
4
4
|
import { safeCustomElement } from './safe-custom-element'
|
|
5
5
|
|
|
@@ -42,15 +42,6 @@ export class ProgressView extends CoreLitElement {
|
|
|
42
42
|
`
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
private renderAddressLabel() {
|
|
46
|
-
return html`
|
|
47
|
-
<value-view
|
|
48
|
-
.value=${this.address}
|
|
49
|
-
.unit=${this.unit}
|
|
50
|
-
></value-view>
|
|
51
|
-
`
|
|
52
|
-
}
|
|
53
|
-
|
|
54
45
|
override render() {
|
|
55
46
|
const isError = (this.className || '').split(/\s+/).includes('error')
|
|
56
47
|
return html`
|
|
@@ -90,7 +90,9 @@ export class MultiSignalController implements ReactiveController {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
hostDisconnected() {
|
|
93
|
-
this.unsubscribes.forEach((unsubscribe) =>
|
|
93
|
+
this.unsubscribes.forEach((unsubscribe) => {
|
|
94
|
+
unsubscribe()
|
|
95
|
+
})
|
|
94
96
|
this.unsubscribes = []
|
|
95
97
|
}
|
|
96
98
|
|
|
@@ -255,7 +255,7 @@ export function useTransactionView(
|
|
|
255
255
|
/**
|
|
256
256
|
* Controller for working with transaction signals from the decoder
|
|
257
257
|
*/
|
|
258
|
-
export class TransactionSignalController<
|
|
258
|
+
export class TransactionSignalController<_T = any>
|
|
259
259
|
implements ReactiveController
|
|
260
260
|
{
|
|
261
261
|
private host: ReactiveControllerHost
|
package/src/shared/url-view.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { html } from 'lit'
|
|
2
|
-
import {
|
|
2
|
+
import { property, state } from 'lit/decorators.js'
|
|
3
3
|
import { safeCustomElement } from './safe-custom-element'
|
|
4
4
|
import './load-web-components'
|
|
5
5
|
import { CoreLitElement } from '../styles'
|
|
@@ -56,7 +56,7 @@ export class UrlView extends CoreLitElement {
|
|
|
56
56
|
.replace(/-/g, ' ')
|
|
57
57
|
.replace(/\b\w/g, (c) => c.toUpperCase())
|
|
58
58
|
|
|
59
|
-
if (this.label
|
|
59
|
+
if (this.label?.trim()) {
|
|
60
60
|
this.displayName = this.label.trim()
|
|
61
61
|
} else {
|
|
62
62
|
this.displayName = hostnamePretty || this.url
|
|
@@ -64,7 +64,7 @@ export class UrlView extends CoreLitElement {
|
|
|
64
64
|
} catch {
|
|
65
65
|
this.favicon = undefined
|
|
66
66
|
// Fallback to raw string if URL parse fails
|
|
67
|
-
this.displayName = this.label
|
|
67
|
+
this.displayName = this.label?.trim() ? this.label : this.url
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
package/src/shared/value-view.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Task } from '@lit/task'
|
|
2
2
|
import { useAddressResolver } from '@lukso/transaction-view-headless'
|
|
3
|
-
import {
|
|
3
|
+
import { html, type TemplateResult } from 'lit'
|
|
4
4
|
import { property, state } from 'lit/decorators.js'
|
|
5
5
|
import { when } from 'lit/directives/when.js'
|
|
6
6
|
import { safeCustomElement } from './safe-custom-element'
|
|
@@ -8,21 +8,7 @@ import { safeCustomElement } from './safe-custom-element'
|
|
|
8
8
|
// Import LUKSO web components
|
|
9
9
|
import './load-web-components'
|
|
10
10
|
import { CoreLitElement } from '../styles'
|
|
11
|
-
|
|
12
|
-
// Value formatting utilities
|
|
13
|
-
function formatUnits(value: bigint, decimals = 18): string {
|
|
14
|
-
const divisor = 10n ** BigInt(decimals)
|
|
15
|
-
const quotient = value / divisor
|
|
16
|
-
const remainder = value % divisor
|
|
17
|
-
|
|
18
|
-
if (remainder === 0n) {
|
|
19
|
-
return quotient.toString()
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const remainderStr = remainder.toString().padStart(decimals, '0')
|
|
23
|
-
const trimmed = remainderStr.replace(/0+$/, '')
|
|
24
|
-
return `${quotient}.${trimmed}`
|
|
25
|
-
}
|
|
11
|
+
import { formatUnits } from '../utils'
|
|
26
12
|
|
|
27
13
|
/**
|
|
28
14
|
* Value display component
|
|
@@ -47,7 +33,7 @@ export class ValueView extends CoreLitElement {
|
|
|
47
33
|
* The value to display (required)
|
|
48
34
|
* Can be string, number, boolean, or bigint
|
|
49
35
|
*/
|
|
50
|
-
@property() value?: string | number | boolean | bigint | null
|
|
36
|
+
@property() value?: TemplateResult | string | number | boolean | bigint | null
|
|
51
37
|
|
|
52
38
|
/**
|
|
53
39
|
* The key name (used for special formatting logic)
|
|
@@ -98,7 +84,7 @@ export class ValueView extends CoreLitElement {
|
|
|
98
84
|
/**
|
|
99
85
|
* Optional label to show in card header
|
|
100
86
|
*/
|
|
101
|
-
@property() label?: string
|
|
87
|
+
@property() label?: string | TemplateResult
|
|
102
88
|
|
|
103
89
|
/**
|
|
104
90
|
* Maximum width for truncation
|
|
@@ -111,13 +97,6 @@ export class ValueView extends CoreLitElement {
|
|
|
111
97
|
*/
|
|
112
98
|
@property() address?: string
|
|
113
99
|
|
|
114
|
-
// Internal state for resolved metadata
|
|
115
|
-
@state() private resolvedMetadata?: {
|
|
116
|
-
symbol?: string
|
|
117
|
-
decimals?: number
|
|
118
|
-
name?: string
|
|
119
|
-
}
|
|
120
|
-
|
|
121
100
|
// Tracks whether the component has any slotted content
|
|
122
101
|
@state() private _hasSlotContent = false
|
|
123
102
|
|
|
@@ -219,15 +198,16 @@ export class ValueView extends CoreLitElement {
|
|
|
219
198
|
if (value === undefined) return 'undefined'
|
|
220
199
|
|
|
221
200
|
switch (effectiveType) {
|
|
222
|
-
case 'currency':
|
|
201
|
+
case 'currency': {
|
|
223
202
|
const { numeric, symbol } = this.getCurrencyParts()
|
|
224
203
|
return `${numeric} ${symbol}`
|
|
204
|
+
}
|
|
225
205
|
|
|
226
206
|
case 'bigint':
|
|
227
207
|
if (typeof value === 'bigint') {
|
|
228
|
-
return value.toString()
|
|
208
|
+
return `${value.toString()}n`
|
|
229
209
|
}
|
|
230
|
-
return String(value)
|
|
210
|
+
return `${String(value)}n`
|
|
231
211
|
|
|
232
212
|
case 'boolean':
|
|
233
213
|
return value ? 'true' : 'false'
|
|
@@ -270,7 +250,7 @@ export class ValueView extends CoreLitElement {
|
|
|
270
250
|
try {
|
|
271
251
|
if (typeof value === 'bigint') {
|
|
272
252
|
numeric = formatUnits(value, effectiveDecimals)
|
|
273
|
-
} else if (typeof value === 'string' && !isNaN(Number(value))) {
|
|
253
|
+
} else if (typeof value === 'string' && !Number.isNaN(Number(value))) {
|
|
274
254
|
const bigintValue = BigInt(value)
|
|
275
255
|
numeric = formatUnits(bigintValue, effectiveDecimals)
|
|
276
256
|
}
|
|
@@ -386,7 +366,7 @@ export class ValueView extends CoreLitElement {
|
|
|
386
366
|
|
|
387
367
|
if (effectiveType === 'currency') {
|
|
388
368
|
const { numeric, symbol } = this.getCurrencyParts()
|
|
389
|
-
if (this.label
|
|
369
|
+
if (this.label) {
|
|
390
370
|
headerText = this.label
|
|
391
371
|
contentTemplate = html`
|
|
392
372
|
<span class="inline-block overflow-hidden text-ellipsis whitespace-nowrap min-w-0 ${this.getNumericClass()}">${numeric}</span>
|
package/src/styles/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@import "@lukso/web-components/
|
|
1
|
+
@import "@lukso/web-components/tools/styles/main.css";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { formatUnits, parseBigInt } from './utils.js'
|
|
3
|
+
|
|
4
|
+
describe('formatUnits', () => {
|
|
5
|
+
it('returns integer string when remainder is zero', () => {
|
|
6
|
+
expect(formatUnits(1000000000000000000n)).toBe('1')
|
|
7
|
+
expect(formatUnits(5000n, 3)).toBe('5')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('formats values with fractional part respecting decimals', () => {
|
|
11
|
+
expect(formatUnits(123000000000000000n)).toBe('0.123')
|
|
12
|
+
expect(formatUnits(987654321n, 6)).toBe('987.654321')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('trims trailing zeros in fractional part', () => {
|
|
16
|
+
expect(formatUnits(120n, 2)).toBe('1.2')
|
|
17
|
+
expect(formatUnits(1001000n, 6)).toBe('1.001')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('handles zero value', () => {
|
|
21
|
+
expect(formatUnits(0n)).toBe('0')
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe('parseBigInt', () => {
|
|
26
|
+
it('parses decimal and hex strings with optional suffix', () => {
|
|
27
|
+
expect(parseBigInt('42')).toBe(42n)
|
|
28
|
+
expect(parseBigInt('0x10')).toBe(16n)
|
|
29
|
+
expect(parseBigInt('21n')).toBe(21n)
|
|
30
|
+
expect(parseBigInt(' 0xFFn ')).toBe(255n)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('returns bigint directly or from integer numbers', () => {
|
|
34
|
+
const value = 123n
|
|
35
|
+
expect(parseBigInt(value)).toBe(value)
|
|
36
|
+
expect(parseBigInt(9007199254740991)).toBe(9007199254740991n)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('returns undefined for invalid inputs', () => {
|
|
40
|
+
expect(parseBigInt('')).toBeUndefined()
|
|
41
|
+
expect(parseBigInt('1.5')).toBeUndefined()
|
|
42
|
+
expect(parseBigInt('0xG')).toBeUndefined()
|
|
43
|
+
expect(parseBigInt(1.1)).toBeUndefined()
|
|
44
|
+
expect(parseBigInt(null)).toBeUndefined()
|
|
45
|
+
expect(parseBigInt(undefined)).toBeUndefined()
|
|
46
|
+
})
|
|
47
|
+
})
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Value formatting utilities
|
|
2
|
+
/**
|
|
3
|
+
* Convert a token amount from base units (bigint) to a decimal string.
|
|
4
|
+
*
|
|
5
|
+
* - Handles arbitrary `decimals` without floating point precision loss.
|
|
6
|
+
* - Trims trailing zeros in the fractional part.
|
|
7
|
+
* - Returns only the integer part when remainder is zero.
|
|
8
|
+
*
|
|
9
|
+
* @param value - The amount in base units as a bigint (e.g., wei for ETH).
|
|
10
|
+
* @param decimals - Number of decimal places the token uses (default 18).
|
|
11
|
+
* @returns A human-readable decimal string.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // 1 ether in wei
|
|
15
|
+
* formatUnits(1000000000000000000n) // '1'
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // 1.23 tokens with 2 decimals
|
|
19
|
+
* formatUnits(123n, 2) // '1.23'
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // No remainder: return integer part only
|
|
23
|
+
* formatUnits(2000000000000000000n) // '2'
|
|
24
|
+
*/
|
|
25
|
+
export function formatUnits(value: bigint, decimals = 18): string {
|
|
26
|
+
const divisor = 10n ** BigInt(decimals)
|
|
27
|
+
const quotient = value / divisor
|
|
28
|
+
const remainder = value % divisor
|
|
29
|
+
|
|
30
|
+
if (remainder === 0n) {
|
|
31
|
+
return quotient.toString()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const remainderStr = remainder.toString().padStart(decimals, '0')
|
|
35
|
+
const trimmed = remainderStr.replace(/0+$/, '')
|
|
36
|
+
return `${quotient}.${trimmed}`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isBigIntString(str: string): boolean {
|
|
40
|
+
const trimmed = str.trim()
|
|
41
|
+
if (trimmed.endsWith('n'))
|
|
42
|
+
return /^[0-9]+n$/.test(trimmed) || /^0x[0-9a-fA-F]+n$/.test(trimmed)
|
|
43
|
+
return /^[0-9]+$/.test(trimmed) || /^0x[0-9a-fA-F]+$/.test(trimmed)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parse loose bigint inputs coming from attributes, JSON, or user input.
|
|
48
|
+
*
|
|
49
|
+
* - Accepts bigint literals (`123n`), decimal/hex strings, and integers.
|
|
50
|
+
* - Trims whitespace and optional trailing `n` suffix.
|
|
51
|
+
* - Returns `undefined` for invalid formats (floats, empty strings, non-numeric text).
|
|
52
|
+
*
|
|
53
|
+
* @param value - Source value to parse (string | number | bigint | null | undefined).
|
|
54
|
+
* @returns BigInt when parsing succeeds, otherwise `undefined`.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* parseBigInt('42') // 42n
|
|
58
|
+
* @example
|
|
59
|
+
* parseBigInt('0x10n') // 16n
|
|
60
|
+
* @example
|
|
61
|
+
* parseBigInt(1000n) // 1000n (passthrough)
|
|
62
|
+
* @example
|
|
63
|
+
* parseBigInt('1.5') // undefined (decimals not allowed)
|
|
64
|
+
*/
|
|
65
|
+
export function parseBigInt(
|
|
66
|
+
value: string | number | bigint | null | undefined
|
|
67
|
+
): bigint | undefined {
|
|
68
|
+
if (!value) return undefined
|
|
69
|
+
if (typeof value === 'bigint') return value
|
|
70
|
+
if (typeof value === 'number') {
|
|
71
|
+
if (!Number.isInteger(value)) return undefined
|
|
72
|
+
return BigInt(value)
|
|
73
|
+
}
|
|
74
|
+
const trimmed = value.trim()
|
|
75
|
+
const cleaned = trimmed.endsWith('n') ? trimmed.slice(0, -1) : trimmed
|
|
76
|
+
if (!isBigIntString(cleaned)) return undefined
|
|
77
|
+
try {
|
|
78
|
+
return BigInt(cleaned)
|
|
79
|
+
} catch {
|
|
80
|
+
return undefined
|
|
81
|
+
}
|
|
82
|
+
}
|
package/src/vue-entry.ts
CHANGED
package/tsup.config.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, resolve } from 'node:path'
|
|
1
3
|
import autoprefixer from 'autoprefixer'
|
|
2
|
-
import { readFileSync } from 'fs'
|
|
3
|
-
import { dirname, resolve } from 'path'
|
|
4
4
|
import postcss from 'postcss'
|
|
5
5
|
import postcssImport from 'postcss-import'
|
|
6
6
|
import tailwindcss from 'tailwindcss'
|
|
@@ -37,7 +37,7 @@ export default defineConfig({
|
|
|
37
37
|
// Return with a special virtual path marker that the onLoad hook can recognize
|
|
38
38
|
// Use 'file' namespace to ensure esbuild calls our onLoad handler
|
|
39
39
|
return {
|
|
40
|
-
path: resolvedPath
|
|
40
|
+
path: `${resolvedPath}?__raw__`,
|
|
41
41
|
namespace: 'file',
|
|
42
42
|
}
|
|
43
43
|
})
|