@stellar-expert/ui-framework 1.9.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/.npmrc +1 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/account/account-address.js +127 -0
- package/account/account-address.scss +20 -0
- package/account/available-balance.js +21 -0
- package/account/identicon.js +91 -0
- package/account/identicon.scss +6 -0
- package/account/signer-key.js +65 -0
- package/api/api-cache.js +5 -0
- package/api/explorer-api-call.js +37 -0
- package/api/explorer-api-hooks.js +202 -0
- package/api/explorer-api-paginated-list-hooks.js +439 -0
- package/api/explorer-batch-info-loader.js +85 -0
- package/api/explorer-tx-api.js +29 -0
- package/asset/amount.js +53 -0
- package/asset/asset-icon.js +34 -0
- package/asset/asset-issuer.js +22 -0
- package/asset/asset-link.js +93 -0
- package/asset/asset-link.scss +26 -0
- package/asset/asset-list-hooks.js +60 -0
- package/asset/asset-meta-hooks.js +78 -0
- package/asset/asset-selector.js +72 -0
- package/asset/asset-selector.scss +41 -0
- package/basic-styles/base.scss +53 -0
- package/basic-styles/form.scss +90 -0
- package/basic-styles/grid.scss +388 -0
- package/basic-styles/link.scss +17 -0
- package/basic-styles/lists.scss +68 -0
- package/basic-styles/loader.scss +22 -0
- package/basic-styles/responsive.scss +29 -0
- package/basic-styles/scrollbars.scss +19 -0
- package/basic-styles/spacing.scss +50 -0
- package/basic-styles/table.scss +104 -0
- package/basic-styles/themes.scss +59 -0
- package/basic-styles/typography.scss +191 -0
- package/basic-styles/variables.scss +26 -0
- package/claimable-balance/claimable-balance-claimants.js +12 -0
- package/contract/sc-val.js +70 -0
- package/contract/wasm-section-parser.js +159 -0
- package/contract/wasm-section-reader.js +79 -0
- package/contract/xdr-reader.js +148 -0
- package/controls/active-icon.scss +23 -0
- package/controls/button-group.js +20 -0
- package/controls/button-group.scss +48 -0
- package/controls/button.js +74 -0
- package/controls/button.scss +148 -0
- package/controls/code-block.js +35 -0
- package/controls/code-block.scss +74 -0
- package/controls/dropdown.js +281 -0
- package/controls/dropdown.scss +161 -0
- package/controls/external-link.js +5 -0
- package/controls/info-tooltip.js +17 -0
- package/controls/info-tooltip.scss +4 -0
- package/controls/slider.js +20 -0
- package/controls/slider.scss +22 -0
- package/controls/tabs.js +94 -0
- package/controls/tabs.scss +73 -0
- package/controls/tooltip.js +214 -0
- package/controls/tooltip.scss +97 -0
- package/controls/update-highlighter.js +28 -0
- package/controls/update-highlighter.scss +10 -0
- package/date/date-selector.js +44 -0
- package/date/elapsed-time.js +22 -0
- package/date/utc-timestamp.js +23 -0
- package/dex/price-dynamic.js +45 -0
- package/dex/price-dynamic.scss +36 -0
- package/directory/directory-hooks.js +89 -0
- package/effect/effect-description.js +289 -0
- package/effect/op-effects-view.js +11 -0
- package/effect/op-effects.scss +8 -0
- package/errors/error-boundary.js +98 -0
- package/fonts/font.scss +23 -0
- package/fonts/icons/config.json +1858 -0
- package/fonts/icons/icons-embedded.scss +644 -0
- package/horizon/horizon-account-helpers.js +104 -0
- package/horizon/horizon-client-helpers.js +52 -0
- package/horizon/horizon-ledger-helpers.js +36 -0
- package/horizon/horizon-orderbook-helpers.js +14 -0
- package/horizon/horizon-trades-helper.js +89 -0
- package/horizon/horizon-transaction-helpers.js +36 -0
- package/index.js +85 -0
- package/index.scss +16 -0
- package/interaction/autofocus.js +9 -0
- package/interaction/block-select.js +54 -0
- package/interaction/block-select.scss +24 -0
- package/interaction/copy-to-clipboard.js +19 -0
- package/interaction/inline-progress.js +16 -0
- package/interaction/qr-code.js +45 -0
- package/interaction/responsive.js +21 -0
- package/interaction/spoiler.js +40 -0
- package/interaction/spoiler.scss +9 -0
- package/interaction/theme-selector.js +11 -0
- package/ledger/ledger-entry-href-formatter.js +22 -0
- package/ledger/ledger-entry-link.js +59 -0
- package/meta/page-meta-tags.js +229 -0
- package/module/dynamic-module.js +48 -0
- package/package.json +41 -0
- package/state/on-screen-hooks.js +23 -0
- package/state/page-visibility-helpers.js +17 -0
- package/state/page-visibility-hooks.js +12 -0
- package/state/screen-orientation-hooks.js +16 -0
- package/state/state-hooks.js +77 -0
- package/state/stellar-network-hooks.js +45 -0
- package/state/theme.js +29 -0
- package/stellar/key-type.js +92 -0
- package/stellar/ledger-generic-id.js +40 -0
- package/stellar/signature-hint-utils.js +65 -0
- package/toast/toast-notification-instance.js +43 -0
- package/toast/toast-notification.js +46 -0
- package/toast/toast-notifications-block.js +55 -0
- package/toast/toast-notifications.scss +166 -0
- package/tx/op-accounting-changes.js +27 -0
- package/tx/op-description-view.js +925 -0
- package/tx/op-description.scss +98 -0
- package/tx/op-icon.js +93 -0
- package/tx/parser/op-balance-changes.js +62 -0
- package/tx/parser/op-descriptor.js +49 -0
- package/tx/parser/tx-details-parser.js +75 -0
- package/tx/parser/tx-matcher.js +372 -0
- package/tx/parser/type-filter-matcher.js +127 -0
- package/tx/tx-fee-effect.js +14 -0
- package/tx/tx-list-hooks.js +19 -0
- package/tx/tx-operations-list.js +105 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {StrKey} from '@stellar/stellar-base'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {String} key
|
|
5
|
+
* @return {{address: String, type: ('muxed'|'ed25519'|'hash'|'tx'|'contract'), [muxedId]: BigInt}|null}
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export function decodeKeyType(key) {
|
|
9
|
+
if (typeof key !== 'string')
|
|
10
|
+
return null
|
|
11
|
+
const prefix = key[0]
|
|
12
|
+
try {
|
|
13
|
+
switch (prefix) {
|
|
14
|
+
case 'G':
|
|
15
|
+
checkLength(key)
|
|
16
|
+
return {
|
|
17
|
+
type: 'ed25519',
|
|
18
|
+
address: key
|
|
19
|
+
}
|
|
20
|
+
case 'C':
|
|
21
|
+
checkLength(key)
|
|
22
|
+
return {
|
|
23
|
+
type: 'contract',
|
|
24
|
+
address: key
|
|
25
|
+
}
|
|
26
|
+
case 'M':
|
|
27
|
+
return {
|
|
28
|
+
type: 'muxed',
|
|
29
|
+
...parseMuxedAccount(key)
|
|
30
|
+
}
|
|
31
|
+
case 'X':
|
|
32
|
+
checkLength(key)
|
|
33
|
+
return {
|
|
34
|
+
type: 'hash',
|
|
35
|
+
address: key
|
|
36
|
+
}
|
|
37
|
+
case 'T':
|
|
38
|
+
checkLength(key)
|
|
39
|
+
return {
|
|
40
|
+
type: 'tx',
|
|
41
|
+
address: key
|
|
42
|
+
}
|
|
43
|
+
case 'P':
|
|
44
|
+
const spayload = StrKey.decodeSignedPayload(key)
|
|
45
|
+
return {
|
|
46
|
+
type: 'signedPayload',
|
|
47
|
+
address: key,
|
|
48
|
+
publicKey: StrKey.encodeEd25519PublicKey(spayload.slice(0, 32)),
|
|
49
|
+
payload: spayload.slice(36, 36 + spayload.readUIntBE(32, 4)).toString('hex')
|
|
50
|
+
}
|
|
51
|
+
default:
|
|
52
|
+
console.error(new Error('Unknown key prefix: ' + typeof key))
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
console.error(e)
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function checkLength(key, length = 56) {
|
|
62
|
+
if (key.length !== length)
|
|
63
|
+
throw new Error('Invalid key length: ' + key)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parse multiplexed account address
|
|
68
|
+
* @param {String} muxedAddress - Multiplexed Stellar address
|
|
69
|
+
* @return {{address: String, muxedId: BigIint}}
|
|
70
|
+
*/
|
|
71
|
+
export function parseMuxedAccount(muxedAddress) {
|
|
72
|
+
const muxed = StrKey.decodeMed25519PublicKey(muxedAddress)
|
|
73
|
+
return {
|
|
74
|
+
address: StrKey.encodeEd25519PublicKey(muxed.slice(0, 32)),
|
|
75
|
+
muxedId: muxed.readBigInt64BE(32)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Encode address and identifier into a multiplexed address
|
|
81
|
+
* @param {String} address - StrKey-encode Stellar account address
|
|
82
|
+
* @param {BigInt} muxedId - Multiplexed int64 id
|
|
83
|
+
* @return {String}
|
|
84
|
+
*/
|
|
85
|
+
export function encodeMuxedAccount(address, muxedId) {
|
|
86
|
+
const raw = Buffer.allocUnsafe(40)
|
|
87
|
+
//write 32 bytes of ed25519 pubkey
|
|
88
|
+
StrKey.decodeEd25519PublicKey(address).copy(raw)
|
|
89
|
+
//write 8 id bytes
|
|
90
|
+
raw.writeBigInt64BE(muxedId, 32)
|
|
91
|
+
return StrKey.encodeMed25519PublicKey(raw)
|
|
92
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} ParsedStellarId
|
|
3
|
+
* @property {('unknown'|'ledger'|'transaction'|'operation')} type - Parsed id type
|
|
4
|
+
* @property {String} [id] - Parsed id
|
|
5
|
+
* @property {Number} [ledger] - Ledger sequence
|
|
6
|
+
* @property {String} [tx] - Transaction id
|
|
7
|
+
* @property {Number} [operationOrder] - Operation order within a transaction
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse stellar generic id
|
|
12
|
+
* @param {String} id
|
|
13
|
+
* @returns {ParsedStellarId}
|
|
14
|
+
*/
|
|
15
|
+
export function parseStellarGenericId(id) {
|
|
16
|
+
if (!/^\d{1,19}$/.test(id)) return {type: 'unknown'}
|
|
17
|
+
const parsed = BigInt(id)
|
|
18
|
+
const res = {
|
|
19
|
+
id,
|
|
20
|
+
type: 'unknown'
|
|
21
|
+
}
|
|
22
|
+
if (parsed < 4294967296n) {
|
|
23
|
+
res.type = 'ledger'
|
|
24
|
+
res.ledger = Number(parsed)
|
|
25
|
+
return res
|
|
26
|
+
}
|
|
27
|
+
const ledger = parsed / 4294967296n
|
|
28
|
+
const opOrder = parsed % 4096n
|
|
29
|
+
res.ledger = Number(ledger)
|
|
30
|
+
if (opOrder > 0n) {
|
|
31
|
+
res.type = 'operation'
|
|
32
|
+
res.tx = (parsed - opOrder).toString()
|
|
33
|
+
res.operationOrder = Number(opOrder)
|
|
34
|
+
} else {
|
|
35
|
+
res.type = 'transaction'
|
|
36
|
+
res.tx = parsed.toString()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return res
|
|
40
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {Keypair} from '@stellar/stellar-base'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert the signature hint to the StrKey mask
|
|
5
|
+
* @param {Buffer} hint - Hint to convert
|
|
6
|
+
* @return {String}
|
|
7
|
+
*/
|
|
8
|
+
export function signatureHintToMask(hint) {
|
|
9
|
+
const partialPublicKey = Buffer.concat([new Buffer(28).fill(0), hint]),
|
|
10
|
+
hintKeypair = new Keypair({type: 'ed25519', publicKey: partialPublicKey}),
|
|
11
|
+
pk = hintKeypair.publicKey()
|
|
12
|
+
return pk.substring(0, 1) + '_'.repeat(46) + pk.substring(47, 52) + '_'.repeat(4)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Format the signature hint to the friendly form for UI
|
|
17
|
+
* @param {Buffer} hint - Hint to convert
|
|
18
|
+
* @return {string}
|
|
19
|
+
*/
|
|
20
|
+
export function formatSignatureHint(hint) {
|
|
21
|
+
const mask = signatureHintToMask(hint)
|
|
22
|
+
return mask.substring(0, 2) + '…' + mask.substring(46)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Check if the hint matches the specific key
|
|
27
|
+
* @param {Buffer} hint - Hint to check
|
|
28
|
+
* @param {String} key - Key to compare
|
|
29
|
+
* @return {Boolean}
|
|
30
|
+
*/
|
|
31
|
+
export function singatureHintMatchesKey(hint, key) {
|
|
32
|
+
return signatureHintToMask(hint).substring(47, 52) === key.substring(47, 52)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Find a key by the signature hint
|
|
37
|
+
* @param {Buffer} hint - Hint to look for
|
|
38
|
+
* @param {Array<String>} allKeys - Array of potentially matching keys
|
|
39
|
+
* @return {String|null}
|
|
40
|
+
*/
|
|
41
|
+
export function findKeyBySignatureHint(hint, allKeys) {
|
|
42
|
+
return allKeys.find(key => singatureHintMatchesKey(hint, key))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Find tx signature for a given signer key
|
|
47
|
+
* @param {String} key
|
|
48
|
+
* @param {Singature} allSignatures
|
|
49
|
+
* @returns {Signature}
|
|
50
|
+
*/
|
|
51
|
+
export function findSignatureByKey(key, allSignatures = []) {
|
|
52
|
+
return allSignatures.find(sig => singatureHintMatchesKey(sig.hint(), key))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if the hint matches any of the provided keys
|
|
57
|
+
* @param {Buffer} signature - Tx signature
|
|
58
|
+
* @param {Array<String>} publicKeys - Array of available public keys
|
|
59
|
+
* @returns {Array<String>}
|
|
60
|
+
*/
|
|
61
|
+
export function findKeysBySignatureHint(signature, keys) {
|
|
62
|
+
const mask = signatureHintToMask(signature.hint())
|
|
63
|
+
return keys.filter(address => mask[0] === address[0] &&
|
|
64
|
+
mask.substr(47, 5) === address.substr(47, 5))
|
|
65
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export default class ToastNotificationInstance {
|
|
2
|
+
constructor(props) {
|
|
3
|
+
Object.assign(this, props)
|
|
4
|
+
this.timer = null
|
|
5
|
+
this.started = new Date()
|
|
6
|
+
this.remaining = props.ttl || ToastNotificationInstance.ttl
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
id
|
|
10
|
+
|
|
11
|
+
type
|
|
12
|
+
|
|
13
|
+
message = ''
|
|
14
|
+
|
|
15
|
+
onDelete
|
|
16
|
+
|
|
17
|
+
deleted = false
|
|
18
|
+
|
|
19
|
+
started
|
|
20
|
+
|
|
21
|
+
remaining
|
|
22
|
+
|
|
23
|
+
delete() {
|
|
24
|
+
this.deleted = true
|
|
25
|
+
this.onDelete(this.id)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pauseTimer() {
|
|
29
|
+
clearTimeout(this.timer)
|
|
30
|
+
this.timer = null
|
|
31
|
+
this.remaining -= new Date() - this.started
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
resumeTimer(action) {
|
|
35
|
+
if (this.timer)
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
this.started = new Date()
|
|
39
|
+
this.timer = setTimeout(action, this.remaining)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static ttl = 10_000 // 10 seconds by default
|
|
43
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, {useCallback, useEffect, useState} from 'react'
|
|
2
|
+
import cn from 'classnames'
|
|
3
|
+
|
|
4
|
+
const contextIcon = {
|
|
5
|
+
'info': 'icon-info',
|
|
6
|
+
'success': 'icon-ok',
|
|
7
|
+
'warning': 'icon-warning',
|
|
8
|
+
'error': 'icon-warning'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function ToastNotification({notification}) {
|
|
12
|
+
const {type = 'info'} = notification
|
|
13
|
+
const [isClosing, setIsClosing] = useState(false)
|
|
14
|
+
const close = useCallback(function () {
|
|
15
|
+
if (notification.deleted)
|
|
16
|
+
return
|
|
17
|
+
setIsClosing(closing => {
|
|
18
|
+
if (closing)
|
|
19
|
+
return closing
|
|
20
|
+
setTimeout(() => notification.delete(), 300)
|
|
21
|
+
return true
|
|
22
|
+
})
|
|
23
|
+
}, [notification])
|
|
24
|
+
|
|
25
|
+
const pauseTimer = useCallback(() => {
|
|
26
|
+
notification.pauseTimer()
|
|
27
|
+
}, [notification])
|
|
28
|
+
|
|
29
|
+
const resumeTimer = useCallback(() => {
|
|
30
|
+
notification.resumeTimer(close)
|
|
31
|
+
}, [notification, close])
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
notification.timer = setTimeout(close, notification.remaining)
|
|
35
|
+
}, [notification, close])
|
|
36
|
+
|
|
37
|
+
const notificationClass = cn('toast-notification segment', type, {'slide-in': !isClosing, 'slide-out': isClosing})
|
|
38
|
+
return <div className={notificationClass} onMouseEnter={pauseTimer} onMouseLeave={resumeTimer}>
|
|
39
|
+
<i className={cn('toast-notification-icon', contextIcon[type])}/>
|
|
40
|
+
<div>{notification.message}</div>
|
|
41
|
+
<a href="#" className="toast-notification-icon icon-cancel" onClick={close}/>
|
|
42
|
+
<div className="lifetime" style={{animationDuration: notification.ttl + 'ms'}}/>
|
|
43
|
+
</div>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default ToastNotification
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React, {useCallback, useEffect, useState} from 'react'
|
|
2
|
+
import {render} from 'react-dom'
|
|
3
|
+
import ToastNotificationInstance from './toast-notification-instance'
|
|
4
|
+
import Notification from './toast-notification'
|
|
5
|
+
import './toast-notifications.scss'
|
|
6
|
+
|
|
7
|
+
let notificationsCounter = 0
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Initialize toast notifications, add toast notifications container to the DOM, and expose notify() global function
|
|
11
|
+
* @return {HTMLDivElement}
|
|
12
|
+
*/
|
|
13
|
+
export function createToastNotificationsContainer() {
|
|
14
|
+
const container = document.createElement('div')
|
|
15
|
+
document.body.appendChild(container)
|
|
16
|
+
render(<ToastNotificationsBlock/>, container)
|
|
17
|
+
return container
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function ToastNotificationsBlock() {
|
|
21
|
+
const [notifications, setNotifications] = useState([])
|
|
22
|
+
|
|
23
|
+
const deleteNotification = useCallback(function (id) {
|
|
24
|
+
setNotifications(prev => {
|
|
25
|
+
const pos = prev.findIndex(v => v.id === id)
|
|
26
|
+
if (pos < 0)
|
|
27
|
+
return prev
|
|
28
|
+
const res = [...prev]
|
|
29
|
+
res.splice(pos, 1)
|
|
30
|
+
return res
|
|
31
|
+
})
|
|
32
|
+
}, [])
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
//declare globally available notify() function
|
|
36
|
+
window.notify = function ({type, message}) {
|
|
37
|
+
const newNotification = new ToastNotificationInstance({
|
|
38
|
+
type,
|
|
39
|
+
message,
|
|
40
|
+
id: ++notificationsCounter,
|
|
41
|
+
onDelete: deleteNotification
|
|
42
|
+
})
|
|
43
|
+
setNotifications(prevNotifications => [newNotification, ...prevNotifications])
|
|
44
|
+
}
|
|
45
|
+
//set empty callback on unload
|
|
46
|
+
return () => {
|
|
47
|
+
window.notify = function () {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}, [])
|
|
51
|
+
|
|
52
|
+
return <div className="toast-notifications-container">
|
|
53
|
+
{notifications.map(props => <Notification key={props.id} notification={props}/>)}
|
|
54
|
+
</div>
|
|
55
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
.toast-notifications-container {
|
|
2
|
+
$toast-space: 0.75*$space-standard;
|
|
3
|
+
|
|
4
|
+
position: fixed;
|
|
5
|
+
top: 0;
|
|
6
|
+
right: 0;
|
|
7
|
+
width: 50vw;
|
|
8
|
+
max-width: 30em;
|
|
9
|
+
padding: 4px 4px 0 0;
|
|
10
|
+
z-index: 999;
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column-reverse;
|
|
13
|
+
|
|
14
|
+
&:not(:first-child) {
|
|
15
|
+
margin-bottom: 0.375em;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.toast-notification {
|
|
19
|
+
position: relative;
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: start;
|
|
22
|
+
width: 100%;
|
|
23
|
+
padding: $toast-space;
|
|
24
|
+
padding-right: $toast-space*2;
|
|
25
|
+
transition: transform 0.3s ease-out;
|
|
26
|
+
opacity: 0.92;
|
|
27
|
+
line-height: 2rem;
|
|
28
|
+
margin-bottom: 4px;
|
|
29
|
+
|
|
30
|
+
@media (max-width: $responsive-mobile-browser-width) {
|
|
31
|
+
padding: 0.5*$space-standard;
|
|
32
|
+
padding-right: $space-standard;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&:hover {
|
|
36
|
+
opacity: 1;
|
|
37
|
+
|
|
38
|
+
.lifetime {
|
|
39
|
+
animation-play-state: paused;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&:before, &:after {
|
|
44
|
+
clip-path: polygon(0.6rem 0, 100% 0, 100% 100%, calc(100% - 0.6rem) 100%, 0 100%, 0 1.6rem);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&.slide-in {
|
|
48
|
+
animation: .3s slideIn ease-in-out;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&.slide-out {
|
|
52
|
+
transform: translateX(150%);
|
|
53
|
+
flex: 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
> .toast-notification-icon {
|
|
57
|
+
font-size: 1.2em;
|
|
58
|
+
padding-right: $space-micro;
|
|
59
|
+
@media (max-width: $responsive-mobile-browser-width) {
|
|
60
|
+
font-size: 1em;
|
|
61
|
+
padding-right: $space-micro/2;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
> div {
|
|
66
|
+
color: var(--color-text);
|
|
67
|
+
font-size: 0.9em;
|
|
68
|
+
@media (max-width: $responsive-mobile-browser-width) {
|
|
69
|
+
font-size: 0.85em;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.icon-cancel {
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
position: absolute;
|
|
76
|
+
top: $toast-space;
|
|
77
|
+
right: 0;
|
|
78
|
+
|
|
79
|
+
@media (max-width: $responsive-mobile-browser-width) {
|
|
80
|
+
top: $space-micro;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.lifetime {
|
|
85
|
+
position: absolute;
|
|
86
|
+
left: 0;
|
|
87
|
+
bottom: 0;
|
|
88
|
+
width: 100%;
|
|
89
|
+
max-width: 0;
|
|
90
|
+
height: 2px;
|
|
91
|
+
animation-name: timeToClose;
|
|
92
|
+
animation-duration: 10s;
|
|
93
|
+
animation-timing-function: linear;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&.info {
|
|
97
|
+
.toast-notification-icon {
|
|
98
|
+
color: var(--color-highlight);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.lifetime {
|
|
102
|
+
background-color: var(--color-highlight);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
&.success {
|
|
107
|
+
&:before {
|
|
108
|
+
background: var(--color-success-bg);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.toast-notification-icon {
|
|
112
|
+
color: var(--color-success);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.lifetime {
|
|
116
|
+
background-color: var(--color-success);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&.warning {
|
|
121
|
+
&:before {
|
|
122
|
+
background: var(--color-warning-bg);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.toast-notification-icon {
|
|
126
|
+
color: var(--color-warning);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.lifetime {
|
|
130
|
+
background-color: var(--color-warning);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&.error {
|
|
135
|
+
&:before {
|
|
136
|
+
background: var(--color-alert-bg);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.toast-notification-icon {
|
|
140
|
+
color: var(--color-alert);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.lifetime {
|
|
144
|
+
background-color: var(--color-alert);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@keyframes slideIn {
|
|
151
|
+
from {
|
|
152
|
+
transform: translateX(100%);
|
|
153
|
+
}
|
|
154
|
+
to {
|
|
155
|
+
transform: translateX(0%);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@keyframes timeToClose {
|
|
160
|
+
from {
|
|
161
|
+
max-width: 100%;
|
|
162
|
+
}
|
|
163
|
+
to {
|
|
164
|
+
max-width: 0;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {Amount} from '../asset/amount'
|
|
3
|
+
import {retrieveOpBalanceChanges} from './parser/op-balance-changes'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Compact accounting effects (credited/debited amounts)
|
|
7
|
+
* @param {OperationDescriptor} op
|
|
8
|
+
* @constructor
|
|
9
|
+
*/
|
|
10
|
+
export function OpAccountingChanges({op}) {
|
|
11
|
+
const changes = retrieveOpBalanceChanges(op)
|
|
12
|
+
return <div className="accounting-effects condensed">
|
|
13
|
+
{changes.map((ch, i) => <div key={op.txHash + op.order + i}
|
|
14
|
+
className={ch.type === 'accountDebited' ? 'dimmed' : 'color-success'}>
|
|
15
|
+
{ch.type === 'accountDebited' ? '-' : '+'}
|
|
16
|
+
<Amount amount={ch.amount} asset={ch.asset} issuer={false} icon={false}/>
|
|
17
|
+
</div>)}
|
|
18
|
+
</div>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function TxFeeAccountingChanges({amount}) {
|
|
22
|
+
return <div className="accounting-effects condensed">
|
|
23
|
+
<div className="dimmed">
|
|
24
|
+
-<Amount amount={amount} asset="XLM" issuer={false} icon={false}/>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
}
|