@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
package/errors/error-boundary.js
CHANGED
|
@@ -1,98 +1,111 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import PropTypes from 'prop-types'
|
|
3
|
-
import {navigation as nav} from '@stellar-expert/navigation'
|
|
4
|
-
import {BlockSelect} from '../interaction/block-select'
|
|
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
|
-
</div>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
{this.renderError()
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import {navigation as nav} from '@stellar-expert/navigation'
|
|
4
|
+
import {BlockSelect} from '../interaction/block-select'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* React error boundary that catches rendering errors and displays a fallback UI
|
|
8
|
+
* @extends React.Component
|
|
9
|
+
*/
|
|
10
|
+
export class ErrorBoundary extends React.Component {
|
|
11
|
+
constructor(props) {
|
|
12
|
+
super(props)
|
|
13
|
+
this.state = {lastError: null, url: null}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
componentDidCatch(e, errorInfo) {
|
|
17
|
+
e.componentStack = errorInfo?.componentStack
|
|
18
|
+
console.error(e)
|
|
19
|
+
this.setState({lastError: e, url: window.location.href}, () => {
|
|
20
|
+
const stopListening = nav.history.listen((location) => {
|
|
21
|
+
if (this.state.url !== window.location.href) {
|
|
22
|
+
stopListening()
|
|
23
|
+
this.setState({lastError: null, url: null})
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
renderError() {
|
|
30
|
+
const {errorBoundarySendErrors = true} = this.props
|
|
31
|
+
return <>
|
|
32
|
+
{this.renderErrorDetails()}
|
|
33
|
+
{errorBoundarySendErrors && this.renderSendErrorBlock()}
|
|
34
|
+
</>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
renderSendErrorBlock() {
|
|
38
|
+
const {lastError, url} = this.state
|
|
39
|
+
const {message, stack, componentStack} = lastError
|
|
40
|
+
const compiledText = `Error details:
|
|
41
|
+
"${message}" at ${url}
|
|
42
|
+
${stack}
|
|
43
|
+
${componentStack ? 'Components stack: ' + componentStack : ''}
|
|
44
|
+
${navigator.userAgent}`
|
|
45
|
+
return <div className="space dimmed text-small text-right">
|
|
46
|
+
If this error persists please{' '}
|
|
47
|
+
<a href={'mailto:support@stellar.expert?subject=Exception&body=' + encodeURIComponent(compiledText)}
|
|
48
|
+
target="_blank">contact our support</a>.
|
|
49
|
+
</div>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
renderErrorDetails() {
|
|
53
|
+
const {lastError, url} = this.state
|
|
54
|
+
const {message, stack, componentStack} = lastError
|
|
55
|
+
const text = `"${message}" at ${url}`
|
|
56
|
+
const {errorBoundaryErrorDetails = true} = this.props
|
|
57
|
+
if (errorBoundaryErrorDetails === false)
|
|
58
|
+
return null
|
|
59
|
+
if (errorBoundaryErrorDetails === true) {
|
|
60
|
+
return <div className="error space text-small" style={{overflow: 'auto', maxWidth: '100%', padding: '1rem 2rem'}}>
|
|
61
|
+
<BlockSelect as="div">
|
|
62
|
+
<div className="micro-space">{text}</div>
|
|
63
|
+
<div className="text-tiny">
|
|
64
|
+
<pre style={{whiteSpace: 'pre-wrap'}}>{stack}</pre>
|
|
65
|
+
<div>{navigator.userAgent}</div>
|
|
66
|
+
</div>
|
|
67
|
+
</BlockSelect>
|
|
68
|
+
</div>
|
|
69
|
+
}
|
|
70
|
+
return <>{errorBoundaryErrorDetails}</>
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
render() {
|
|
74
|
+
if (!this.state.lastError)
|
|
75
|
+
return this.props.children
|
|
76
|
+
const {title = 'Unhandled error occurred', wrapper, ...otherProps} = this.props
|
|
77
|
+
if (wrapper)
|
|
78
|
+
return React.createElement(wrapper, {...otherProps}, this.renderError())
|
|
79
|
+
return <div className="segment blank">
|
|
80
|
+
<h3 className="color-danger">{title}</h3>
|
|
81
|
+
<hr className="flare"/>
|
|
82
|
+
{this.renderError()}
|
|
83
|
+
</div>
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static propTypes = {
|
|
87
|
+
errorBoundaryTitle: PropTypes.string,
|
|
88
|
+
errorBoundarySendErrors: PropTypes.bool,
|
|
89
|
+
errorBoundaryErrorDetails: PropTypes.oneOfType([PropTypes.bool, PropTypes.any])
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Higher-order component that wraps a component with an ErrorBoundary
|
|
95
|
+
* @param {function} wrapped - React component to wrap
|
|
96
|
+
* @param {Object} [options]
|
|
97
|
+
* @param {string} [options.errorBoundaryTitle] - Title displayed in the error UI
|
|
98
|
+
* @param {boolean} [options.errorBoundarySendErrors] - Show "contact support" link
|
|
99
|
+
* @param {boolean|*} [options.errorBoundaryErrorDetails] - Show error details (true), hide (false), or provide custom content
|
|
100
|
+
* @return {function} Wrapped component with error boundary
|
|
101
|
+
*/
|
|
102
|
+
export function withErrorBoundary(wrapped, {errorBoundaryTitle, errorBoundarySendErrors, errorBoundaryErrorDetails} = {}) {
|
|
103
|
+
function ErrorBoundaryWrapper(props) {
|
|
104
|
+
const nested = /*#__PURE__*/React.createElement(wrapped, props)
|
|
105
|
+
return <ErrorBoundary {...{errorBoundaryTitle, errorBoundarySendErrors, errorBoundaryErrorDetails}}>{nested}</ErrorBoundary>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
ErrorBoundaryWrapper.displayName = `withErrorBoundary(${wrapped.displayName || wrapped.name})`
|
|
109
|
+
ErrorBoundaryWrapper.WrappedComponent = wrapped
|
|
110
|
+
return ErrorBoundaryWrapper
|
|
98
111
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React, {useCallback, useState} from 'react'
|
|
2
|
+
import {StrKey} from '@stellar/stellar-base'
|
|
3
|
+
import {AccountAddress} from '../../account/account-address'
|
|
4
|
+
import {useAutoFocusRef} from '../../interaction/autofocus'
|
|
5
|
+
|
|
6
|
+
export function AccountEditor({value, setValue}) {
|
|
7
|
+
const [internalValue, setInternalValue] = useState(value || '')
|
|
8
|
+
const onChange = useCallback(function (e) {
|
|
9
|
+
const v = e.target.value.trim()
|
|
10
|
+
setInternalValue(v)
|
|
11
|
+
if (StrKey.isValidEd25519PublicKey(v) || StrKey.isValidContract(v)) {
|
|
12
|
+
setValue(v)
|
|
13
|
+
}
|
|
14
|
+
}, [setValue])
|
|
15
|
+
if (!setValue)
|
|
16
|
+
return <AccountAddress account={value} link={false}/>
|
|
17
|
+
|
|
18
|
+
return <input type="text" value={internalValue} onChange={onChange} ref={useAutoFocusRef}
|
|
19
|
+
style={{width: '26em', maxWidth: '56vw'}} className="condensed"/>
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {AssetLink} from '../../asset/asset-link'
|
|
3
|
+
import {AssetSelector} from '../../asset/asset-selector'
|
|
4
|
+
|
|
5
|
+
export function AssetEditor({value, setValue}) {
|
|
6
|
+
if (!setValue)
|
|
7
|
+
return <AssetLink asset={value} link={false}/>
|
|
8
|
+
return <AssetSelector value={value} onChange={setValue} title={value ? undefined : 'Choose asset'} expanded/>
|
|
9
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React, {useCallback, useState} from 'react'
|
|
2
|
+
import {UtcTimestamp} from '../../date/utc-timestamp'
|
|
3
|
+
import {DateSelector} from '../../date/date-selector'
|
|
4
|
+
import {useAutoFocusRef} from '../../interaction/autofocus'
|
|
5
|
+
|
|
6
|
+
export function TimestampEditor({value, setValue, edit}) {
|
|
7
|
+
value = parseInt(value, 10)
|
|
8
|
+
const [internalValue, setInternalValue] = useState(value || undefined)
|
|
9
|
+
|
|
10
|
+
const confirm = useCallback(function () {
|
|
11
|
+
setInternalValue(internalValue => {
|
|
12
|
+
if (internalValue) {
|
|
13
|
+
setValue(internalValue)
|
|
14
|
+
}
|
|
15
|
+
return internalValue
|
|
16
|
+
})
|
|
17
|
+
}, [setValue])
|
|
18
|
+
|
|
19
|
+
const onKeyDown = useCallback(function (e) {
|
|
20
|
+
if (e.key === 'Enter') {
|
|
21
|
+
confirm()
|
|
22
|
+
}
|
|
23
|
+
if (e.key === 'Escape') {
|
|
24
|
+
setValue(value)
|
|
25
|
+
}
|
|
26
|
+
}, [confirm, setValue, value])
|
|
27
|
+
if (!setValue)
|
|
28
|
+
return <UtcTimestamp date={value} className="condensed"/>
|
|
29
|
+
return <>
|
|
30
|
+
<DateSelector value={internalValue} onChange={setInternalValue} onKeyDown={onKeyDown} ref={edit ? useAutoFocusRef : null}/>
|
|
31
|
+
<a href="#" className="icon-ok" onClick={confirm}/>
|
|
32
|
+
|
|
33
|
+
</>
|
|
34
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import {Dropdown} from '../../controls/dropdown'
|
|
3
|
+
|
|
4
|
+
export function OperationTypeEditor({value, setValue}) {
|
|
5
|
+
if (!setValue) {
|
|
6
|
+
const option = typeEditorOptions.find(opt => opt.value === value)
|
|
7
|
+
return <span>{option ? option.title : 'Unknown operation type'}</span>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return <Dropdown title="Choose operation type" expanded onChange={setValue}
|
|
11
|
+
options={typeEditorOptions.map(({title, value}) => ({value, title}))}/>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const typeEditorOptions = [
|
|
15
|
+
{
|
|
16
|
+
title: 'Group: payments',
|
|
17
|
+
description: 'Including CreateAccount, AccountMerge, Payment, PathPaymentStrictReceive, PathPaymentStrictSend, CreateClaimableBalance, ClaimClaimableBalance, Clawback, ClawbackClaimableBalance, Inflation operations',
|
|
18
|
+
value: 'payments'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
title: 'Group: trustlines',
|
|
22
|
+
description: 'Including ChangeTrust, AllowTrust, SetTrustLineFlags operations',
|
|
23
|
+
value: 'trustlines'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
title: 'Group: DEX trading',
|
|
27
|
+
description: 'Including ManageSellOffer, ManageBuyOffer, CreatePassiveSellOffer, LiquidityPoolDeposit, LiquidityPoolWithdraw operations',
|
|
28
|
+
value: 'dex'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: 'Group: account settings',
|
|
32
|
+
description: 'Including CreateAccount, SetOptions, ChangeTrust, AllowTrust, AccountMerge, Inflation, ManageData, BumpSequence, BeginSponsoringFutureReserves, EndSponsoringFutureReserves, RevokeSponsorship, SetTrustLineFlags operations',
|
|
33
|
+
value: 'settings'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: 'Group: smart contracts',
|
|
37
|
+
description: 'Including InvokeHostFunction, BumpFootprintExpiration, RestoreFootprint operations',
|
|
38
|
+
value: 'soroban'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
title: 'CreateAccount',
|
|
42
|
+
value: '0'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
title: 'Payment',
|
|
46
|
+
value: '1'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
title: 'PathPaymentStrictReceive',
|
|
50
|
+
value: '2'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
title: 'ManageSellOffer',
|
|
54
|
+
value: '3'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
title: 'CreatePassiveSellOffer',
|
|
58
|
+
value: '4'
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
title: 'SetOptions',
|
|
62
|
+
value: '5'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
title: 'ChangeTrust',
|
|
66
|
+
value: '6'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
title: 'AllowTrust',
|
|
70
|
+
value: '7'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
title: 'AccountMerge',
|
|
74
|
+
value: '8'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
title: 'Inflation',
|
|
78
|
+
value: '9'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
title: 'ManageData',
|
|
82
|
+
value: '10'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
title: 'BumpSequence',
|
|
86
|
+
value: '11'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
title: 'ManageBuyOffer',
|
|
90
|
+
value: '12'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
title: 'PathPaymentStrictSend',
|
|
94
|
+
value: '13'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
title: 'CreateClaimableBalance',
|
|
98
|
+
value: '14'
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
title: 'ClaimClaimableBalance',
|
|
102
|
+
value: '15'
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
title: 'BeginSponsoringFutureReserves',
|
|
106
|
+
value: '16'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
title: 'EndSponsoringFutureReserves',
|
|
110
|
+
value: '17'
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
title: 'RevokeSponsorship',
|
|
114
|
+
value: '18'
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
title: 'Clawback',
|
|
118
|
+
value: '19'
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
title: 'ClawbackClaimableBalance',
|
|
122
|
+
value: '20'
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
title: 'SetTrustLineFlags',
|
|
126
|
+
value: '21'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
title: 'LiquidityPoolDeposit',
|
|
130
|
+
value: '22'
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
title: 'LiquidityPoolWithdraw',
|
|
134
|
+
value: '23'
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
title: 'InvokeHostFunction',
|
|
138
|
+
value: '24'
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
title: 'BumpFootprintExpiration',
|
|
142
|
+
value: '25'
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
title: 'RestoreFootprint',
|
|
146
|
+
value: '26'
|
|
147
|
+
}
|
|
148
|
+
]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React, {useCallback, useState} from 'react'
|
|
2
|
+
import {StrKey} from '@stellar/stellar-base'
|
|
3
|
+
import {shortenString} from '@stellar-expert/formatter'
|
|
4
|
+
import {AssetLink} from '../asset/asset-link'
|
|
5
|
+
import {useAutoFocusRef} from '../interaction/autofocus'
|
|
6
|
+
import {OperationTypeEditor} from './editors/type-filter-view'
|
|
7
|
+
import {AssetEditor} from './editors/asset-filter-view'
|
|
8
|
+
import {AccountEditor} from './editors/account-filter-view'
|
|
9
|
+
import {TimestampEditor} from './editors/timestamp-filter-view'
|
|
10
|
+
|
|
11
|
+
export function TextEditor({value, setValue, mask}) {
|
|
12
|
+
const [internalValue, setInternalValue] = useState(value || '')
|
|
13
|
+
|
|
14
|
+
const onChange = useCallback(function (e) {
|
|
15
|
+
let v = e.target.value.trim()
|
|
16
|
+
if (mask instanceof RegExp) {
|
|
17
|
+
v = v.replace(mask, '')
|
|
18
|
+
}
|
|
19
|
+
if (typeof mask === 'function') {
|
|
20
|
+
v = mask(v)
|
|
21
|
+
}
|
|
22
|
+
setInternalValue(v)
|
|
23
|
+
}, [mask])
|
|
24
|
+
|
|
25
|
+
const confirm = useCallback(function () {
|
|
26
|
+
setInternalValue(internalValue => {
|
|
27
|
+
setValue(internalValue)
|
|
28
|
+
return internalValue
|
|
29
|
+
})
|
|
30
|
+
}, [setValue])
|
|
31
|
+
|
|
32
|
+
const onKeyDown = useCallback(function (e) {
|
|
33
|
+
if (e.key === 'Enter') {
|
|
34
|
+
confirm()
|
|
35
|
+
}
|
|
36
|
+
if (e.key === 'Escape') {
|
|
37
|
+
setValue(value)
|
|
38
|
+
}
|
|
39
|
+
}, [confirm, setValue, value])
|
|
40
|
+
|
|
41
|
+
if (!setValue) {
|
|
42
|
+
value = value.toString()
|
|
43
|
+
return <span>{value.length > 20 ? shortenString(value, 12) : value}</span>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return <>
|
|
47
|
+
<input type="text" value={internalValue} ref={useAutoFocusRef} onChange={onChange} onKeyDown={onKeyDown}
|
|
48
|
+
style={{width: '16em', maxWidth: '50vw'}}/>
|
|
49
|
+
<a href="#" className="icon-ok" onClick={confirm}/>
|
|
50
|
+
</>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function OfferIdEditor({value, setValue}) {
|
|
54
|
+
return <TextEditor value={value} setValue={setValue} mask={/[\D]/g}/>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function LiquidityPoolEditor({value, setValue}) {
|
|
58
|
+
if (!setValue) {
|
|
59
|
+
if (/^[a-f0-9]{64}$/.test(value)) { //remap hex format to pool id format
|
|
60
|
+
try {
|
|
61
|
+
value = StrKey.encodeLiquidityPool(Buffer.from(value, 'hex'))
|
|
62
|
+
} catch (_) {
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!StrKey.isValidLiquidityPool(value))
|
|
66
|
+
return <span className="dimmed">(Invalid pool)</span>
|
|
67
|
+
if (value.startsWith('native'))
|
|
68
|
+
return <span className="dimmed">(Native pool)</span>
|
|
69
|
+
return <AssetLink asset={value} link={false}/>
|
|
70
|
+
}
|
|
71
|
+
return <TextEditor value={value} setValue={setValue} mask={/[\W]/g}/>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function MemoEditor({value, setValue}) {
|
|
75
|
+
return <TextEditor value={value} setValue={setValue} mask={v => v.substring(0, 64)}/>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function TopicEditor({value, setValue}) {
|
|
79
|
+
if (!setValue)
|
|
80
|
+
return <code className="word-break">{value}</code>
|
|
81
|
+
return <TextEditor value={value} setValue={setValue}/>
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const editorMapping = {
|
|
85
|
+
topic: TopicEditor,
|
|
86
|
+
type: OperationTypeEditor,
|
|
87
|
+
account: AccountEditor,
|
|
88
|
+
source: AccountEditor,
|
|
89
|
+
destination: AccountEditor,
|
|
90
|
+
asset: AssetEditor,
|
|
91
|
+
src_asset: AssetEditor,
|
|
92
|
+
dest_asset: AssetEditor,
|
|
93
|
+
from: TimestampEditor,
|
|
94
|
+
to: TimestampEditor,
|
|
95
|
+
memo: MemoEditor,
|
|
96
|
+
offer: OfferIdEditor,
|
|
97
|
+
pool: LiquidityPoolEditor
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function resolveFilterEditor(field) {
|
|
101
|
+
return editorMapping[field]
|
|
102
|
+
}
|