@stellar-expert/ui-framework 1.16.8 → 1.19.0
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/README.md +1168 -3
- package/account/account-address.js +127 -127
- package/account/available-balance.js +22 -22
- package/account/identicon.js +90 -90
- package/account/signer-key.js +65 -64
- package/api/explorer-api-hooks.js +209 -202
- package/api/explorer-api-paginated-list-hooks.js +441 -440
- package/api/explorer-batch-info-loader.js +111 -85
- package/api/explorer-tx-api.js +28 -28
- package/api/ledger-stream.js +15 -0
- package/asset/amount.js +56 -56
- package/asset/asset-icon.js +41 -41
- package/asset/asset-issuer.js +21 -21
- package/asset/asset-link.js +107 -107
- package/asset/asset-list-hooks.js +59 -59
- package/asset/asset-meta-hooks.js +88 -88
- package/asset/asset-selector.js +72 -71
- package/claimable-balance/claimable-balance-claimants.js +23 -18
- package/contract/contract-api.js +15 -0
- package/contract/invocation-info-view.js +10 -2
- package/contract/sc-val.js +131 -107
- package/controls/button-group.js +25 -19
- package/controls/button.js +93 -78
- package/controls/code-block.js +42 -34
- package/controls/dropdown.js +318 -287
- package/controls/external-link.js +10 -4
- package/controls/info-tooltip.js +23 -16
- package/controls/slider.js +29 -19
- package/controls/tabs.js +94 -94
- package/controls/tooltip.js +244 -240
- package/controls/update-highlighter.js +32 -27
- package/date/date-selector.js +56 -54
- package/date/elapsed-time.js +28 -21
- package/dex/price-dynamic.js +53 -44
- package/directory/directory-hooks.js +109 -97
- package/effect/effect-description.js +346 -344
- package/errors/error-boundary.js +110 -97
- package/filter/editors/account-filter-view.js +20 -0
- package/filter/editors/asset-filter-view.js +9 -0
- package/filter/editors/timestamp-filter-view.js +34 -0
- package/filter/editors/type-filter-view.js +148 -0
- package/filter/filter-editors.js +102 -0
- package/filter/filter-view.js +218 -0
- package/filter/filter.scss +57 -0
- package/horizon/horizon-account-helpers.js +104 -104
- package/horizon/horizon-ledger-helpers.js +35 -35
- package/horizon/horizon-trades-helper.js +88 -88
- package/horizon/horizon-transaction-helpers.js +36 -36
- package/index.d.ts +1271 -0
- package/index.js +95 -93
- package/interaction/accordion.js +43 -35
- package/interaction/autofocus.js +13 -9
- package/interaction/block-select.js +64 -53
- package/interaction/copy-to-clipboard.js +25 -18
- package/interaction/inline-progress.js +20 -15
- package/interaction/qr-code.js +34 -34
- package/interaction/responsive.js +20 -20
- package/interaction/spoiler.js +52 -39
- package/interaction/theme-selector.js +13 -10
- package/ledger/ledger-entry-href-formatter.js +27 -26
- package/ledger/ledger-entry-link.js +93 -58
- package/ledger/ledger-info-parser.js +46 -18
- package/meta/page-meta-tags.js +243 -238
- package/module/dynamic-module.js +47 -47
- package/package.json +71 -40
- package/state/on-screen-hooks.js +22 -22
- package/state/page-visibility-helpers.js +29 -16
- package/state/page-visibility-hooks.js +13 -11
- package/state/screen-orientation-hooks.js +19 -15
- package/state/state-hooks.js +76 -76
- package/state/stellar-network-hooks.js +56 -44
- package/state/theme.js +29 -28
- package/stellar/key-type.js +92 -91
- package/stellar/ledger-generic-id.js +39 -39
- package/stellar/signature-hint-utils.js +65 -65
- package/toast/toast-notifications-block.js +59 -59
- package/tx/op-description-view.js +945 -942
- package/tx/op-icon.js +98 -98
- package/tx/parser/op-balance-changes.js +66 -66
- package/tx/parser/op-descriptor.js +51 -48
- package/tx/parser/tx-details-parser.js +81 -81
- package/tx/parser/tx-matcher.js +371 -371
- package/tx/parser/type-filter-matcher.js +126 -126
- package/tx/tx-list-hooks.js +32 -18
- package/tx/tx-operations-list.js +117 -116
|
@@ -1,85 +1,111 @@
|
|
|
1
|
-
import {throttle} from 'throttle-debounce'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
for (const {key, finished} of batch) {
|
|
79
|
-
finished
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
1
|
+
import {throttle} from 'throttle-debounce'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Batches multiple individual load requests into single API calls for efficiency.
|
|
5
|
+
* Accumulates requests over a short window and sends them together.
|
|
6
|
+
*/
|
|
7
|
+
export class ExplorerBatchInfoLoader {
|
|
8
|
+
/**
|
|
9
|
+
* @param {function(string[]): Promise<{_embedded: {records: Object[]}}>} fetchCallback - Fetches a batch of entries by their keys
|
|
10
|
+
* @param {function(Object): {key: string, info: *}} processResponseCallback - Extracts key and info from each response record
|
|
11
|
+
*/
|
|
12
|
+
constructor(fetchCallback, processResponseCallback) {
|
|
13
|
+
this.pendingRequests = {}
|
|
14
|
+
this.requestsQueue = []
|
|
15
|
+
this.fetchDataFromServer = throttle(500, this.fetchDataFromServer, {noLeading: true})
|
|
16
|
+
this.fetchCallback = fetchCallback
|
|
17
|
+
this.processResponseCallback = processResponseCallback
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @type {{}}
|
|
22
|
+
* @private
|
|
23
|
+
*/
|
|
24
|
+
pendingRequests
|
|
25
|
+
/**
|
|
26
|
+
* @type {[]}
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
requestsQueue = []
|
|
30
|
+
/**
|
|
31
|
+
* @type {function}
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
fetchCallback
|
|
35
|
+
/**
|
|
36
|
+
* @type {function}
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
processResponseCallback
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Load a single entry by key, batching the request with other pending loads
|
|
43
|
+
* @param {string} key - Entry identifier
|
|
44
|
+
* @return {Promise<*>} Resolves with the entry data or null if not found
|
|
45
|
+
*/
|
|
46
|
+
loadEntry(key) {
|
|
47
|
+
//check whether the same address is being fetched right now
|
|
48
|
+
const pending = this.pendingRequests[key]
|
|
49
|
+
if (pending) return pending
|
|
50
|
+
const promise = new Promise(resolve => {
|
|
51
|
+
this.requestsQueue.push({
|
|
52
|
+
key,
|
|
53
|
+
finished: data => {
|
|
54
|
+
delete this.pendingRequests[key]
|
|
55
|
+
resolve(data)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
this.fetchDataFromServer()
|
|
59
|
+
})
|
|
60
|
+
this.pendingRequests[key] = promise
|
|
61
|
+
return promise
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fetchDataFromServer() {
|
|
65
|
+
if (!this.requestsQueue.length) return
|
|
66
|
+
const batch = this.requestsQueue.splice(0, 50)
|
|
67
|
+
if (!batch.length) return
|
|
68
|
+
return this.fetchCallback(batch.map(e => e.key))
|
|
69
|
+
.then(data => {
|
|
70
|
+
if (data.error)
|
|
71
|
+
return //TODO: handle errors in a more elegant way, with retries
|
|
72
|
+
//reschedule another batch fetch if the queue is not empty
|
|
73
|
+
if (this.requestsQueue.length) {
|
|
74
|
+
setTimeout(() => this.fetchDataFromServer(), 400)
|
|
75
|
+
}
|
|
76
|
+
//remap batch array to an object for the faster elements access
|
|
77
|
+
const batchMap = {}
|
|
78
|
+
for (const {key, finished} of batch) {
|
|
79
|
+
batchMap[key] = finished
|
|
80
|
+
}
|
|
81
|
+
for (const entry of data._embedded.records) {
|
|
82
|
+
const {key} = this.processResponseCallback(entry)
|
|
83
|
+
const finalizeRequest = batchMap[key]
|
|
84
|
+
if (finalizeRequest) {
|
|
85
|
+
finalizeRequest(entry)
|
|
86
|
+
}
|
|
87
|
+
//cleanup promise reference
|
|
88
|
+
delete batchMap[key]
|
|
89
|
+
delete this.pendingRequests[key]
|
|
90
|
+
}
|
|
91
|
+
//return null for all keys that have not been found
|
|
92
|
+
for (const key of Object.keys(batchMap)) {
|
|
93
|
+
const finalizeRequest = batchMap[key]
|
|
94
|
+
if (finalizeRequest) {
|
|
95
|
+
finalizeRequest(null)
|
|
96
|
+
}
|
|
97
|
+
//cleanup promise reference
|
|
98
|
+
delete this.pendingRequests[key]
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
.catch(err => {
|
|
102
|
+
console.error(err)
|
|
103
|
+
//finalize all pending promises with nulls
|
|
104
|
+
for (const {key, finished} of batch) {
|
|
105
|
+
finished(null)
|
|
106
|
+
//cleanup promise reference
|
|
107
|
+
delete this.pendingRequests[key]
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
}
|
package/api/explorer-tx-api.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import {parseStellarGenericId} from '../stellar/ledger-generic-id'
|
|
2
|
-
import {getCurrentStellarNetwork} from '../state/stellar-network-hooks'
|
|
3
|
-
import {fetchExplorerApi} from './explorer-api-call'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Load transaction from API
|
|
7
|
-
* @param {
|
|
8
|
-
* @return {Promise<Object>}
|
|
9
|
-
*/
|
|
10
|
-
export function loadTransaction(txHashOrId) {
|
|
11
|
-
if (/^\d+$/.test(txHashOrId)) { //treat as generic tx id
|
|
12
|
-
const {type} = parseStellarGenericId(txHashOrId)
|
|
13
|
-
if (type !== 'transaction')
|
|
14
|
-
return Promise.reject(new Error('Invalid transaction id: ' + txHashOrId))
|
|
15
|
-
} else if (!/^[a-fA-F0-9]{64}$/.test(txHashOrId))
|
|
16
|
-
return Promise.reject(new Error('Invalid transaction hash or id: ' + txHashOrId))
|
|
17
|
-
|
|
18
|
-
return fetchExplorerApi(getCurrentStellarNetwork() + '/tx/' + txHashOrId)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Load transactions included into the ledger
|
|
24
|
-
* @param {
|
|
25
|
-
* @return {Promise<Array<Object>>}
|
|
26
|
-
*/
|
|
27
|
-
export function loadLedgerTransactions(sequence) {
|
|
28
|
-
return fetchExplorerApi(getCurrentStellarNetwork() + '/ledger/' + sequence + '/tx')
|
|
1
|
+
import {parseStellarGenericId} from '../stellar/ledger-generic-id'
|
|
2
|
+
import {getCurrentStellarNetwork} from '../state/stellar-network-hooks'
|
|
3
|
+
import {fetchExplorerApi} from './explorer-api-call'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Load transaction from API
|
|
7
|
+
* @param {string} txHashOrId - Transaction hash or generic id
|
|
8
|
+
* @return {Promise<Object>}
|
|
9
|
+
*/
|
|
10
|
+
export function loadTransaction(txHashOrId) {
|
|
11
|
+
if (/^\d+$/.test(txHashOrId)) { //treat as generic tx id
|
|
12
|
+
const {type} = parseStellarGenericId(txHashOrId)
|
|
13
|
+
if (type !== 'transaction')
|
|
14
|
+
return Promise.reject(new Error('Invalid transaction id: ' + txHashOrId))
|
|
15
|
+
} else if (!/^[a-fA-F0-9]{64}$/.test(txHashOrId))
|
|
16
|
+
return Promise.reject(new Error('Invalid transaction hash or id: ' + txHashOrId))
|
|
17
|
+
|
|
18
|
+
return fetchExplorerApi(getCurrentStellarNetwork() + '/tx/' + txHashOrId)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Load transactions included into the ledger
|
|
24
|
+
* @param {number} sequence - Ledger sequence
|
|
25
|
+
* @return {Promise<Array<Object>>}
|
|
26
|
+
*/
|
|
27
|
+
export function loadLedgerTransactions(sequence) {
|
|
28
|
+
return fetchExplorerApi(getCurrentStellarNetwork() + '/ledger/' + sequence + '/tx')
|
|
29
29
|
}
|
package/api/ledger-stream.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {getCurrentStellarNetwork} from '../state/stellar-network-hooks'
|
|
2
2
|
import {fetchExplorerApi} from './explorer-api-call'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Long-polling stream that notifies listeners about new ledgers
|
|
6
|
+
*/
|
|
4
7
|
class LedgerStream {
|
|
5
8
|
constructor() {
|
|
6
9
|
this.listeners = new Set()
|
|
@@ -89,13 +92,25 @@ class LedgerStream {
|
|
|
89
92
|
}
|
|
90
93
|
}
|
|
91
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Fetch the most recent ledger info from the API
|
|
97
|
+
* @return {Promise<Object>}
|
|
98
|
+
*/
|
|
92
99
|
async getLast() {
|
|
93
100
|
return fetchExplorerApi(getCurrentStellarNetwork() + '/ledger/last')
|
|
94
101
|
}
|
|
95
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Fetch the sequence number of the most recent ledger
|
|
105
|
+
* @return {Promise<number>}
|
|
106
|
+
*/
|
|
96
107
|
async getLastSequence() {
|
|
97
108
|
return (await this.getLast()).sequence
|
|
98
109
|
}
|
|
99
110
|
}
|
|
100
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Singleton ledger stream instance for subscribing to new ledger notifications
|
|
114
|
+
* @type {LedgerStream}
|
|
115
|
+
*/
|
|
101
116
|
export const ledgerStream = new LedgerStream()
|
package/asset/amount.js
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {formatWithPrecision, formatWithAutoPrecision, fromStroops} from '@stellar-expert/formatter'
|
|
3
|
-
import {AssetDescriptor, isAssetValid, isValidPoolId} from '@stellar-expert/asset-descriptor'
|
|
4
|
-
import {useAssetMeta} from './asset-meta-hooks'
|
|
5
|
-
import {AssetLink} from './asset-link'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Formatted tokens amount
|
|
9
|
-
* @param {
|
|
10
|
-
* @param {
|
|
11
|
-
* @param {
|
|
12
|
-
* @param {
|
|
13
|
-
* @param {
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {
|
|
16
|
-
* @constructor
|
|
17
|
-
*/
|
|
18
|
-
export const Amount = React.memo(function Amount({amount, asset, decimals, adjust, round, issuer, icon}) {
|
|
19
|
-
const meta = useAssetMeta(asset)
|
|
20
|
-
if (amount === undefined || amount === null)
|
|
21
|
-
return null
|
|
22
|
-
if (adjust === true) {
|
|
23
|
-
try {
|
|
24
|
-
amount = fromStroops(amount, meta?.decimals ?? 7)
|
|
25
|
-
} catch (e) {
|
|
26
|
-
console.error(e)
|
|
27
|
-
return null
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (round) {
|
|
31
|
-
let [int, fract] = (typeof amount === 'number' ? amount.toFixed(7) : amount).split('.')
|
|
32
|
-
if (fract > 0) {
|
|
33
|
-
int = parseFloat(int)
|
|
34
|
-
fract = parseFloat('0.' + fract)
|
|
35
|
-
if (amount < 0) {
|
|
36
|
-
fract *= -1
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const rounded = round === 'floor' ? Math.floor(fract) : Math.round(fract)
|
|
40
|
-
amount = int + rounded
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
try {
|
|
44
|
-
amount = decimals === 'auto' ? formatWithAutoPrecision(amount) : formatWithPrecision(amount, decimals)
|
|
45
|
-
} catch (e) {
|
|
46
|
-
console.error(e)
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
49
|
-
return <span className="amount nowrap condensed">
|
|
50
|
-
{amount}
|
|
51
|
-
{!!asset && <>
|
|
52
|
-
{' '}{isAssetValid(asset) || isValidPoolId(asset) ?
|
|
53
|
-
<AssetLink asset={asset} icon={icon} issuer={issuer}/> :
|
|
54
|
-
asset.toString()}
|
|
55
|
-
</>}
|
|
56
|
-
</span>
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {formatWithPrecision, formatWithAutoPrecision, fromStroops} from '@stellar-expert/formatter'
|
|
3
|
+
import {AssetDescriptor, isAssetValid, isValidPoolId} from '@stellar-expert/asset-descriptor'
|
|
4
|
+
import {useAssetMeta} from './asset-meta-hooks'
|
|
5
|
+
import {AssetLink} from './asset-link'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Formatted tokens amount
|
|
9
|
+
* @param {string|number} amount - Amount of tokens
|
|
10
|
+
* @param {string|AssetDescriptor|Asset} asset - Asset name/descriptor
|
|
11
|
+
* @param {string|number|'auto'} decimals - Number of decimals to show for a formatted numeric value
|
|
12
|
+
* @param {boolean} [adjust] - Treat amount value as raw Int64 stroops amount
|
|
13
|
+
* @param {boolean|'floor'} [round] - Round the amount
|
|
14
|
+
* @param {boolean} [issuer] - Whether to show asset issuer
|
|
15
|
+
* @param {boolean} [icon] - Whether to show asset icon
|
|
16
|
+
* @constructor
|
|
17
|
+
*/
|
|
18
|
+
export const Amount = React.memo(function Amount({amount, asset, decimals, adjust, round, issuer, icon}) {
|
|
19
|
+
const meta = useAssetMeta(asset)
|
|
20
|
+
if (amount === undefined || amount === null)
|
|
21
|
+
return null
|
|
22
|
+
if (adjust === true) {
|
|
23
|
+
try {
|
|
24
|
+
amount = fromStroops(amount, meta?.decimals ?? 7)
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.error(e)
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (round) {
|
|
31
|
+
let [int, fract] = (typeof amount === 'number' ? amount.toFixed(7) : amount).split('.')
|
|
32
|
+
if (fract > 0) {
|
|
33
|
+
int = parseFloat(int)
|
|
34
|
+
fract = parseFloat('0.' + fract)
|
|
35
|
+
if (amount < 0) {
|
|
36
|
+
fract *= -1
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const rounded = round === 'floor' ? Math.floor(fract) : Math.round(fract)
|
|
40
|
+
amount = int + rounded
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
amount = decimals === 'auto' ? formatWithAutoPrecision(amount) : formatWithPrecision(amount, decimals)
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.error(e)
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
return <span className="amount nowrap condensed">
|
|
50
|
+
{amount}
|
|
51
|
+
{!!asset && <>
|
|
52
|
+
{' '}{isAssetValid(asset) || isValidPoolId(asset) ?
|
|
53
|
+
<AssetLink asset={asset} icon={icon} issuer={issuer}/> :
|
|
54
|
+
asset.toString()}
|
|
55
|
+
</>}
|
|
56
|
+
</span>
|
|
57
57
|
})
|
package/asset/asset-icon.js
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {AssetDescriptor} from '@stellar-expert/asset-descriptor'
|
|
3
|
-
import {drawIdenticon} from '../account/identicon'
|
|
4
|
-
import {useAssetMeta} from './asset-meta-hooks'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Inline asset icon
|
|
8
|
-
* @param {
|
|
9
|
-
* @param {
|
|
10
|
-
* @param {{}} [style] - Optional CSS inline style
|
|
11
|
-
* @param {*} [children] - Optional inner text
|
|
12
|
-
* @constructor
|
|
13
|
-
*/
|
|
14
|
-
export const AssetIcon = React.memo(function AssetIcon({asset, className, style, children}) {
|
|
15
|
-
const meta = useAssetMeta(asset)
|
|
16
|
-
if (typeof asset === 'string') {
|
|
17
|
-
asset = AssetDescriptor.parse(asset)
|
|
18
|
-
}
|
|
19
|
-
const icon = meta?.toml_info?.image || meta?.toml_info?.orgLogo
|
|
20
|
-
const classes = ['asset-icon']
|
|
21
|
-
if (!style) {
|
|
22
|
-
style = {}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (className) {
|
|
26
|
-
classes.push(className)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (asset.isNative) { // native asset
|
|
30
|
-
classes.push('icon icon-stellar')
|
|
31
|
-
} else if (icon) { // asset with an icon
|
|
32
|
-
style.backgroundImage = `url('${icon}')`
|
|
33
|
-
} else if (asset.isContract) {
|
|
34
|
-
style.backgroundImage = `url('${'data:image/svg+xml;charset=utf-8,' + drawIdenticon(asset.toString())}')`
|
|
35
|
-
style.borderRadius = '50%'
|
|
36
|
-
} else { // asset without metadata
|
|
37
|
-
classes.push('icon icon-empty-circle')
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return <span className={classes.join(' ')} style={style}>{children}</span>
|
|
41
|
-
})
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {AssetDescriptor} from '@stellar-expert/asset-descriptor'
|
|
3
|
+
import {drawIdenticon} from '../account/identicon'
|
|
4
|
+
import {useAssetMeta} from './asset-meta-hooks'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Inline asset icon
|
|
8
|
+
* @param {string|AssetDescriptor|Asset} asset - Asset name/descriptor
|
|
9
|
+
* @param {string} [className] - Optional CSS class name
|
|
10
|
+
* @param {{}} [style] - Optional CSS inline style
|
|
11
|
+
* @param {*} [children] - Optional inner text
|
|
12
|
+
* @constructor
|
|
13
|
+
*/
|
|
14
|
+
export const AssetIcon = React.memo(function AssetIcon({asset, className, style, children}) {
|
|
15
|
+
const meta = useAssetMeta(asset)
|
|
16
|
+
if (typeof asset === 'string') {
|
|
17
|
+
asset = AssetDescriptor.parse(asset)
|
|
18
|
+
}
|
|
19
|
+
const icon = meta?.toml_info?.image || meta?.toml_info?.orgLogo
|
|
20
|
+
const classes = ['asset-icon']
|
|
21
|
+
if (!style) {
|
|
22
|
+
style = {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (className) {
|
|
26
|
+
classes.push(className)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (asset.isNative) { // native asset
|
|
30
|
+
classes.push('icon icon-stellar')
|
|
31
|
+
} else if (icon) { // asset with an icon
|
|
32
|
+
style.backgroundImage = `url('${icon}')`
|
|
33
|
+
} else if (asset.isContract) {
|
|
34
|
+
style.backgroundImage = `url('${'data:image/svg+xml;charset=utf-8,' + drawIdenticon(asset.toString())}')`
|
|
35
|
+
style.borderRadius = '50%'
|
|
36
|
+
} else { // asset without metadata
|
|
37
|
+
classes.push('icon icon-empty-circle')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return <span className={classes.join(' ')} style={style}>{children}</span>
|
|
41
|
+
})
|
package/asset/asset-issuer.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {AssetDescriptor} from '@stellar-expert/asset-descriptor'
|
|
3
|
-
import {AccountAddress} from '../account/account-address'
|
|
4
|
-
import {useAssetMeta} from './asset-meta-hooks'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Inline asset issuer
|
|
8
|
-
* @param {
|
|
9
|
-
* @constructor
|
|
10
|
-
*/
|
|
11
|
-
export const AssetIssuer = React.memo(function AssetIssuer({asset}) {
|
|
12
|
-
let meta = useAssetMeta(asset)
|
|
13
|
-
if (asset === 'XLM' || asset.isNative) {
|
|
14
|
-
meta = {domain: 'stellar.org'}
|
|
15
|
-
}
|
|
16
|
-
asset = AssetDescriptor.parse(asset)
|
|
17
|
-
return <span className="asset-issuer condensed">
|
|
18
|
-
{meta?.domain ?
|
|
19
|
-
<>{meta.domain}</> :
|
|
20
|
-
<><AccountAddress account={asset.issuer} link={false} chars={8} icon={false}/></>}
|
|
21
|
-
</span>
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {AssetDescriptor} from '@stellar-expert/asset-descriptor'
|
|
3
|
+
import {AccountAddress} from '../account/account-address'
|
|
4
|
+
import {useAssetMeta} from './asset-meta-hooks'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Inline asset issuer
|
|
8
|
+
* @param {string|AssetDescriptor|Asset} asset - Asset name/descriptor
|
|
9
|
+
* @constructor
|
|
10
|
+
*/
|
|
11
|
+
export const AssetIssuer = React.memo(function AssetIssuer({asset}) {
|
|
12
|
+
let meta = useAssetMeta(asset)
|
|
13
|
+
if (asset === 'XLM' || asset.isNative) {
|
|
14
|
+
meta = {domain: 'stellar.org'}
|
|
15
|
+
}
|
|
16
|
+
asset = AssetDescriptor.parse(asset)
|
|
17
|
+
return <span className="asset-issuer condensed">
|
|
18
|
+
{meta?.domain ?
|
|
19
|
+
<>{meta.domain}</> :
|
|
20
|
+
<><AccountAddress account={asset.issuer} link={false} chars={8} icon={false}/></>}
|
|
21
|
+
</span>
|
|
22
22
|
})
|