@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.
- package/.turbo/turbo-build.log +33 -0
- package/CHANGELOG.md +104 -0
- package/LICENSE +201 -0
- package/README.md +264 -0
- package/dist/index.cjs +4573 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +493 -0
- package/dist/index.d.ts +493 -0
- package/dist/index.js +4534 -0
- package/dist/index.js.map +1 -0
- package/dist/shared/index.cjs +2480 -0
- package/dist/shared/index.cjs.map +1 -0
- package/dist/shared/index.d.cts +887 -0
- package/dist/shared/index.d.ts +887 -0
- package/dist/shared/index.js +2437 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/styles/index.cjs +58 -0
- package/dist/styles/index.cjs.map +1 -0
- package/dist/styles/index.d.cts +9 -0
- package/dist/styles/index.d.ts +9 -0
- package/dist/styles/index.js +31 -0
- package/dist/styles/index.js.map +1 -0
- package/package.json +57 -0
- package/publish.log +0 -0
- package/src/components/asset-card.ts +426 -0
- package/src/components/contract-card.ts +238 -0
- package/src/components/description-view.ts +605 -0
- package/src/components/index.ts +20 -0
- package/src/components/info-panel.ts +437 -0
- package/src/components/permissions-block.ts +138 -0
- package/src/components/transaction-playback.ts +429 -0
- package/src/components/universal-token-view.ts +281 -0
- package/src/declaration.d.ts +4 -0
- package/src/examples/INTEGRATION_GUIDE.md +240 -0
- package/src/examples/TransactionContentWithReplacement.vue +269 -0
- package/src/index.ts +38 -0
- package/src/registry/index.ts +31 -0
- package/src/registry/lit-view-loader.ts +191 -0
- package/src/shared/address-display.ts +370 -0
- package/src/shared/address-view.ts +385 -0
- package/src/shared/custom-select.ts +164 -0
- package/src/shared/function-name-view.ts +89 -0
- package/src/shared/gas-provider-view.ts +218 -0
- package/src/shared/icon-view.ts +288 -0
- package/src/shared/image-list.ts +261 -0
- package/src/shared/image-loader-controller.ts +160 -0
- package/src/shared/index.ts +34 -0
- package/src/shared/load-web-components.ts +56 -0
- package/src/shared/notification-view.ts +132 -0
- package/src/shared/progress-view.ts +86 -0
- package/src/shared/safe-custom-element.ts +35 -0
- package/src/shared/scroll-to-bottom-button.ts +55 -0
- package/src/shared/signal-controller.ts +124 -0
- package/src/shared/transaction-view-controller.ts +345 -0
- package/src/shared/url-view.ts +129 -0
- package/src/shared/value-view.ts +510 -0
- package/src/styles/index.ts +28 -0
- package/src/styles/styles.css +1 -0
- package/src/vue-entry.ts +15 -0
- package/tailwind.config.cjs +9 -0
- package/tsconfig.json +22 -0
- package/tsup.config.ts +90 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { Task } from '@lit/task'
|
|
2
|
+
import { useAddressResolver } from '@lukso/transaction-view-headless'
|
|
3
|
+
import makeBlockie from 'ethereum-blockies-base64'
|
|
4
|
+
import { html } from 'lit'
|
|
5
|
+
import { customElement, property, state } from 'lit/decorators.js'
|
|
6
|
+
import { safeCustomElement } from './safe-custom-element'
|
|
7
|
+
import './load-web-components'
|
|
8
|
+
import { CoreLitElement } from '../styles'
|
|
9
|
+
|
|
10
|
+
type GasProvider = { type: 'relayer' | 'controller'; id: string }
|
|
11
|
+
type Relayer = {
|
|
12
|
+
id: string
|
|
13
|
+
name: string
|
|
14
|
+
isCustom: boolean
|
|
15
|
+
apiUrl: string
|
|
16
|
+
chainIds: string[]
|
|
17
|
+
createdAt: number
|
|
18
|
+
website?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@safeCustomElement('gas-provider-view')
|
|
22
|
+
export class GasProviderView extends CoreLitElement {
|
|
23
|
+
@property({ type: Array, reflect: true }) allRelayers: Relayer[] = []
|
|
24
|
+
@property({ type: Number, reflect: true }) balance = 0
|
|
25
|
+
@property({ type: Object, attribute: 'selected-gas-provider', reflect: true })
|
|
26
|
+
selectedGasProvider?: GasProvider
|
|
27
|
+
@property({ attribute: 'controller-address', reflect: true })
|
|
28
|
+
controllerAddress?: string
|
|
29
|
+
@property({ attribute: 'controller-name', reflect: true })
|
|
30
|
+
controllerName?: string
|
|
31
|
+
@property({ attribute: 'symbol', reflect: true }) symbol: string = 'LYX'
|
|
32
|
+
@property({ type: Number, reflect: true }) decimals = 18
|
|
33
|
+
@property({ type: Number, attribute: 'transaction-fee', reflect: true })
|
|
34
|
+
transactionFee = 0
|
|
35
|
+
@property({ type: Number, attribute: 'relayer-available', reflect: true })
|
|
36
|
+
relayerAvailable = 0
|
|
37
|
+
@property({ type: Number, attribute: 'relayer-used', reflect: true })
|
|
38
|
+
relayerUsed = 0
|
|
39
|
+
@property({ type: Number, attribute: 'relayer-to-be-used', reflect: true })
|
|
40
|
+
relayerToBeUsed = 0
|
|
41
|
+
@property({ attribute: 'relayer-reset-date', reflect: true })
|
|
42
|
+
relayerResetDate: string = 'N/A'
|
|
43
|
+
|
|
44
|
+
private formatToken(amount: number) {
|
|
45
|
+
// naive formatting for display; consumers can override by slotting
|
|
46
|
+
return (amount / 10 ** this.decimals).toLocaleString(undefined, {
|
|
47
|
+
maximumFractionDigits: 6,
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private onSelectChanged(e: Event) {
|
|
52
|
+
const value = (e.target as any).value as string | undefined
|
|
53
|
+
if (!value) return
|
|
54
|
+
if (this.controllerAddress && value === this.controllerAddress) {
|
|
55
|
+
const next: GasProvider = {
|
|
56
|
+
type: 'controller',
|
|
57
|
+
id: this.controllerAddress,
|
|
58
|
+
}
|
|
59
|
+
if (
|
|
60
|
+
!this.selectedGasProvider ||
|
|
61
|
+
this.selectedGasProvider.id !== next.id ||
|
|
62
|
+
this.selectedGasProvider.type !== next.type
|
|
63
|
+
) {
|
|
64
|
+
this.selectedGasProvider = next
|
|
65
|
+
this.dispatchEvent(
|
|
66
|
+
new CustomEvent('on-gas-provider-change', {
|
|
67
|
+
detail: next,
|
|
68
|
+
bubbles: true,
|
|
69
|
+
})
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
// Map selection back to relayer by website/apiUrl fallback
|
|
75
|
+
const match = this.allRelayers.find(
|
|
76
|
+
(r) => r.website === value || r.apiUrl === value
|
|
77
|
+
)
|
|
78
|
+
if (match) {
|
|
79
|
+
const next: GasProvider = { type: 'relayer', id: match.id }
|
|
80
|
+
if (
|
|
81
|
+
!this.selectedGasProvider ||
|
|
82
|
+
this.selectedGasProvider.id !== next.id ||
|
|
83
|
+
this.selectedGasProvider.type !== next.type
|
|
84
|
+
) {
|
|
85
|
+
this.selectedGasProvider = next
|
|
86
|
+
this.dispatchEvent(
|
|
87
|
+
new CustomEvent('on-gas-provider-change', {
|
|
88
|
+
detail: next,
|
|
89
|
+
bubbles: true,
|
|
90
|
+
})
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private renderProgress(
|
|
98
|
+
totalAvailable: number,
|
|
99
|
+
used: number,
|
|
100
|
+
toBeUsed: number,
|
|
101
|
+
symbol: string,
|
|
102
|
+
hasError: boolean
|
|
103
|
+
) {
|
|
104
|
+
const usedPercent = totalAvailable ? (used / totalAvailable) * 100 : 0
|
|
105
|
+
const toBeUsedPercent = totalAvailable
|
|
106
|
+
? (toBeUsed / totalAvailable) * 100
|
|
107
|
+
: 0
|
|
108
|
+
const barOverHalf = usedPercent > 50
|
|
109
|
+
return html`<progress-view
|
|
110
|
+
class=${hasError ? 'error' : ''}
|
|
111
|
+
.data=${[
|
|
112
|
+
{
|
|
113
|
+
value: usedPercent,
|
|
114
|
+
color: 'var(--green-54)',
|
|
115
|
+
title: `${usedPercent}%`,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
value: toBeUsedPercent,
|
|
119
|
+
color: 'var(--neutral-60)',
|
|
120
|
+
title: `${toBeUsedPercent}%`,
|
|
121
|
+
},
|
|
122
|
+
]}
|
|
123
|
+
label-position=${barOverHalf ? 'left' : 'right'}
|
|
124
|
+
.label=${`${toBeUsed} / ${String(totalAvailable)} ${symbol}`}
|
|
125
|
+
>
|
|
126
|
+
</progress-view>`
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private renderControllerProgress() {
|
|
130
|
+
return this.renderProgress(
|
|
131
|
+
this.balance,
|
|
132
|
+
0,
|
|
133
|
+
this.transactionFee,
|
|
134
|
+
this.symbol,
|
|
135
|
+
this.transactionFee > this.balance
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private renderRelayerProgress() {
|
|
140
|
+
return this.renderProgress(
|
|
141
|
+
this.relayerAvailable,
|
|
142
|
+
this.relayerUsed,
|
|
143
|
+
this.relayerToBeUsed,
|
|
144
|
+
'M GAS',
|
|
145
|
+
this.relayerToBeUsed > this.relayerAvailable
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private displayRelayerResetDate() {
|
|
150
|
+
const date = new Date(this.relayerResetDate)
|
|
151
|
+
return isNaN(date.getTime()) ? 'N/A' : date.toLocaleDateString()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
override render() {
|
|
155
|
+
const formatted = this.formatToken(this.balance)
|
|
156
|
+
|
|
157
|
+
// Build select options: relayers first, then controller
|
|
158
|
+
const relayerOptions = this.allRelayers.map((r) => ({
|
|
159
|
+
value: r.website || r.apiUrl || `relayer:${r.id}`,
|
|
160
|
+
label: r.name,
|
|
161
|
+
disabled: false,
|
|
162
|
+
}))
|
|
163
|
+
const controllerOption = this.controllerAddress
|
|
164
|
+
? [
|
|
165
|
+
{
|
|
166
|
+
value: this.controllerAddress,
|
|
167
|
+
label: this.controllerName
|
|
168
|
+
? `${this.controllerName} (${formatted} ${this.symbol})`
|
|
169
|
+
: `UP Browser Extension (${formatted} ${this.symbol})`,
|
|
170
|
+
disabled: false,
|
|
171
|
+
},
|
|
172
|
+
]
|
|
173
|
+
: []
|
|
174
|
+
const options = [...relayerOptions, ...controllerOption]
|
|
175
|
+
|
|
176
|
+
const selectedValue = this.selectedGasProvider
|
|
177
|
+
? this.selectedGasProvider.type === 'controller'
|
|
178
|
+
? this.controllerAddress
|
|
179
|
+
: (() => {
|
|
180
|
+
const r = this.allRelayers.find(
|
|
181
|
+
(x) => x.id === this.selectedGasProvider!.id
|
|
182
|
+
)
|
|
183
|
+
return (
|
|
184
|
+
r?.website ||
|
|
185
|
+
r?.apiUrl ||
|
|
186
|
+
`relayer:${this.selectedGasProvider!.id}`
|
|
187
|
+
)
|
|
188
|
+
})()
|
|
189
|
+
: undefined
|
|
190
|
+
|
|
191
|
+
return html`
|
|
192
|
+
<div class="w-full">
|
|
193
|
+
<custom-select .value=${selectedValue} .options=${options} @change=${this.onSelectChanged}></custom-select>
|
|
194
|
+
${
|
|
195
|
+
this.selectedGasProvider
|
|
196
|
+
? html`<div class="mt-2">
|
|
197
|
+
${this.selectedGasProvider?.type === 'controller' ? this.renderControllerProgress() : this.renderRelayerProgress()}
|
|
198
|
+
${
|
|
199
|
+
this.selectedGasProvider?.type === 'relayer'
|
|
200
|
+
? html`<span class="text-[12px] text-neutral-60 mt-2 block">
|
|
201
|
+
Your total of ${this.relayerAvailable}M resets on ${this.displayRelayerResetDate()}.
|
|
202
|
+
</span>`
|
|
203
|
+
: html``
|
|
204
|
+
}
|
|
205
|
+
</div>`
|
|
206
|
+
: html``
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
</div>
|
|
210
|
+
`
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
declare global {
|
|
215
|
+
interface HTMLElementTagNameMap {
|
|
216
|
+
'gas-provider-view': GasProviderView
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { Task } from '@lit/task'
|
|
2
|
+
import {
|
|
3
|
+
useAddressResolver,
|
|
4
|
+
useImageLoader,
|
|
5
|
+
} from '@lukso/transaction-view-headless'
|
|
6
|
+
import { html } from 'lit'
|
|
7
|
+
import { customElement, property, state } from 'lit/decorators.js'
|
|
8
|
+
import { CoreLitElement } from '../styles'
|
|
9
|
+
import { safeCustomElement } from './safe-custom-element'
|
|
10
|
+
|
|
11
|
+
// LUKSO web components are loaded dynamically via plugin
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Address data interface for display
|
|
15
|
+
*/
|
|
16
|
+
export interface AddressData {
|
|
17
|
+
address: string
|
|
18
|
+
name?: string
|
|
19
|
+
lsp4TokenName?: string
|
|
20
|
+
lsp4TokenSymbol?: string
|
|
21
|
+
baseAsset?: {
|
|
22
|
+
lsp4TokenName?: string
|
|
23
|
+
lsp4TokenSymbol?: string
|
|
24
|
+
}
|
|
25
|
+
profileImages?: any[]
|
|
26
|
+
avatar?: any[]
|
|
27
|
+
icon?: any[]
|
|
28
|
+
images?: any[]
|
|
29
|
+
__gqltype?: string
|
|
30
|
+
__identity?: string
|
|
31
|
+
identity?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Icon/Avatar display component for addresses
|
|
36
|
+
*
|
|
37
|
+
* Displays just the profile image/avatar for an address with proper styling.
|
|
38
|
+
* Supports both Universal Profiles and contract addresses.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```html
|
|
42
|
+
* <icon-view
|
|
43
|
+
* address="0x1234..."
|
|
44
|
+
* .resolved="${resolvedData}"
|
|
45
|
+
* size="medium"
|
|
46
|
+
* ></icon-view>
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
@safeCustomElement('icon-view')
|
|
50
|
+
export class IconView extends CoreLitElement {
|
|
51
|
+
/**
|
|
52
|
+
* The address to display (required)
|
|
53
|
+
*/
|
|
54
|
+
@property() address!: string
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Resolved address data (profile, images, etc.)
|
|
58
|
+
*/
|
|
59
|
+
@property({ type: Object }) resolved?: AddressData
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Display size
|
|
63
|
+
*/
|
|
64
|
+
@property() size: 'x-small' | 'small' | 'medium' | 'large' | '2x-large' =
|
|
65
|
+
'small'
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Optional label to display above the icon
|
|
69
|
+
*/
|
|
70
|
+
@property() label?: string
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Whether to show the resolved display name below/beside the icon
|
|
74
|
+
*/
|
|
75
|
+
@property({ type: Boolean, attribute: 'show-name' }) showName = true
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Name placement relative to the icon: 'below' (stacked) or 'beside' (inline)
|
|
79
|
+
*/
|
|
80
|
+
@property({ attribute: 'name-position' }) namePosition: 'below' | 'beside' =
|
|
81
|
+
'below'
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Maximum width for the name label (pixels)
|
|
85
|
+
*/
|
|
86
|
+
@property({ type: Number, attribute: 'max-width' }) maxWidth = 200
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Whether to show small identicon badge on the avatar
|
|
90
|
+
*/
|
|
91
|
+
@property({ type: Boolean, attribute: 'show-icon-identicon' })
|
|
92
|
+
showIconIdenticon = true
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Whether to show small identicon badge on the label
|
|
96
|
+
*/
|
|
97
|
+
@property({ type: Boolean, attribute: 'show-label-identicon' })
|
|
98
|
+
showLabelIdenticon = false
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Force unresolved display (for testing)
|
|
102
|
+
*/
|
|
103
|
+
@property({ type: Boolean, attribute: 'force-unresolved' }) forceUnresolved =
|
|
104
|
+
false
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Property name to use for loading images (e.g., 'images', 'icons', 'profileImages')
|
|
108
|
+
* If not set, uses default image loading logic
|
|
109
|
+
*/
|
|
110
|
+
@property({ type: String, attribute: 'image-hint' }) imageHint?: string
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Index to use when loading from an image array (e.g., images[0])
|
|
114
|
+
* Only used when imageHint points to an array property
|
|
115
|
+
*/
|
|
116
|
+
@property({ type: Number, attribute: 'image-index' }) imageIndex?: number
|
|
117
|
+
|
|
118
|
+
// Internal state
|
|
119
|
+
@state() private imageData?: { src: string }
|
|
120
|
+
@state() private isLoadingImage = false
|
|
121
|
+
@state() private isLoadingAddress = false
|
|
122
|
+
|
|
123
|
+
// Composables
|
|
124
|
+
private imageLoader = useImageLoader()
|
|
125
|
+
private addressResolver = useAddressResolver()
|
|
126
|
+
|
|
127
|
+
// Task for resolving address data
|
|
128
|
+
private addressTask = new Task(this, {
|
|
129
|
+
task: async ([address], { signal }) => {
|
|
130
|
+
if (!address) return null
|
|
131
|
+
|
|
132
|
+
this.isLoadingAddress = true
|
|
133
|
+
try {
|
|
134
|
+
// Pass the full compound address to resolver (e.g., "0x123...-0x456...")
|
|
135
|
+
const resolved = await this.addressResolver.resolveAddress(address)
|
|
136
|
+
this.requestUpdate() // Force re-render after resolution
|
|
137
|
+
return resolved
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.warn('❌ IconView: Failed to resolve address:', error)
|
|
140
|
+
return null
|
|
141
|
+
} finally {
|
|
142
|
+
this.isLoadingAddress = false
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
args: () => [this.address],
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
// Task for loading profile image
|
|
149
|
+
private imageTask = new Task(this, {
|
|
150
|
+
task: async ([resolved], { signal }) => {
|
|
151
|
+
if (!resolved) return null
|
|
152
|
+
|
|
153
|
+
this.isLoadingImage = true
|
|
154
|
+
try {
|
|
155
|
+
let image
|
|
156
|
+
|
|
157
|
+
// If imageHint is specified, load directly from that property
|
|
158
|
+
if (this.imageHint && (resolved as any)[this.imageHint]) {
|
|
159
|
+
const imageArray = (resolved as any)[this.imageHint]
|
|
160
|
+
if (Array.isArray(imageArray) && imageArray.length > 0) {
|
|
161
|
+
image = await this.imageLoader.loadImage(imageArray, {
|
|
162
|
+
width: this.getSizePixels(),
|
|
163
|
+
height: this.getSizePixels(),
|
|
164
|
+
dpr: window.devicePixelRatio || 1,
|
|
165
|
+
index: this.imageIndex,
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
// Use default profile image loading logic
|
|
170
|
+
image = await this.imageLoader.loadProfileImage(resolved, {
|
|
171
|
+
width: this.getSizePixels(),
|
|
172
|
+
height: this.getSizePixels(),
|
|
173
|
+
dpr: window.devicePixelRatio || 1,
|
|
174
|
+
index: this.imageIndex,
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return image || this.imageLoader.getFallbackImage(resolved)
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.warn('Failed to load address image:', error)
|
|
181
|
+
return this.imageLoader.getFallbackImage(resolved || {})
|
|
182
|
+
} finally {
|
|
183
|
+
this.isLoadingImage = false
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
args: () => [this.addressTask.value],
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get pixel size for the current size setting
|
|
191
|
+
*/
|
|
192
|
+
private getSizePixels(): number {
|
|
193
|
+
switch (this.size) {
|
|
194
|
+
case 'x-small':
|
|
195
|
+
return 16
|
|
196
|
+
case 'small':
|
|
197
|
+
return 24
|
|
198
|
+
case 'medium':
|
|
199
|
+
return 32
|
|
200
|
+
case 'large':
|
|
201
|
+
return 48
|
|
202
|
+
case '2x-large':
|
|
203
|
+
return 124
|
|
204
|
+
default:
|
|
205
|
+
return 24
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Check if this is a contract address (shows square icon)
|
|
211
|
+
*/
|
|
212
|
+
private get isContract(): boolean {
|
|
213
|
+
const resolved = this.addressTask.value
|
|
214
|
+
return resolved ? this.imageLoader.isContractAddress(resolved) : false
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Handle icon click
|
|
219
|
+
*/
|
|
220
|
+
private handleClick() {
|
|
221
|
+
this.dispatchEvent(
|
|
222
|
+
new CustomEvent('address-click', {
|
|
223
|
+
detail: {
|
|
224
|
+
address: this.address,
|
|
225
|
+
resolved: this.addressTask.value,
|
|
226
|
+
},
|
|
227
|
+
bubbles: true,
|
|
228
|
+
})
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
override render() {
|
|
233
|
+
const imageResult = this.imageTask.value
|
|
234
|
+
|
|
235
|
+
const containerClass = this.namePosition === 'beside' ? 'row' : 'column'
|
|
236
|
+
return html`
|
|
237
|
+
<div class="${
|
|
238
|
+
containerClass === 'row'
|
|
239
|
+
? 'flex items-start gap-1'
|
|
240
|
+
: 'flex flex-col items-center gap-1'
|
|
241
|
+
}">
|
|
242
|
+
${
|
|
243
|
+
this.label
|
|
244
|
+
? html`<div class="text-[12px] text-neutral-60 font-medium">${
|
|
245
|
+
this.label
|
|
246
|
+
}</div>`
|
|
247
|
+
: ''
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
<div class="${
|
|
251
|
+
this.namePosition === 'beside'
|
|
252
|
+
? 'inline-flex flex-row items-center gap-2'
|
|
253
|
+
: 'inline-flex flex-col items-center gap-1.5'
|
|
254
|
+
}">
|
|
255
|
+
<lukso-profile
|
|
256
|
+
size=${this.size}
|
|
257
|
+
profile-address=${this.address}
|
|
258
|
+
profile-url=${imageResult?.src || ''}
|
|
259
|
+
?has-identicon=${this.showIconIdenticon}
|
|
260
|
+
?is-square=${this.isContract}
|
|
261
|
+
class="inline-flex items-center cursor-pointer transition-transform duration-200 hover:scale-105"
|
|
262
|
+
@click=${this.handleClick}
|
|
263
|
+
></lukso-profile>
|
|
264
|
+
|
|
265
|
+
${
|
|
266
|
+
this.showName
|
|
267
|
+
? html`
|
|
268
|
+
<address-view
|
|
269
|
+
class="leading-none"
|
|
270
|
+
address=${this.address}
|
|
271
|
+
.showIdenticon=${this.showLabelIdenticon}
|
|
272
|
+
size=${this.size}
|
|
273
|
+
max-width=${this.maxWidth}
|
|
274
|
+
></address-view>
|
|
275
|
+
`
|
|
276
|
+
: ''
|
|
277
|
+
}
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
`
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
declare global {
|
|
285
|
+
interface HTMLElementTagNameMap {
|
|
286
|
+
'icon-view': IconView
|
|
287
|
+
}
|
|
288
|
+
}
|