@stellar-expert/ui-framework 1.16.8 → 1.17.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.
Files changed (78) hide show
  1. package/CLAUDE.md +35 -0
  2. package/README.md +1125 -3
  3. package/account/account-address.js +127 -127
  4. package/account/available-balance.js +22 -22
  5. package/account/identicon.js +90 -90
  6. package/account/signer-key.js +65 -64
  7. package/api/explorer-api-hooks.js +209 -202
  8. package/api/explorer-api-paginated-list-hooks.js +441 -440
  9. package/api/explorer-batch-info-loader.js +111 -85
  10. package/api/explorer-tx-api.js +28 -28
  11. package/api/ledger-stream.js +15 -0
  12. package/asset/amount.js +56 -56
  13. package/asset/asset-icon.js +41 -41
  14. package/asset/asset-issuer.js +21 -21
  15. package/asset/asset-link.js +107 -107
  16. package/asset/asset-list-hooks.js +59 -59
  17. package/asset/asset-meta-hooks.js +88 -88
  18. package/asset/asset-selector.js +72 -71
  19. package/claimable-balance/claimable-balance-claimants.js +23 -18
  20. package/contract/contract-api.js +15 -0
  21. package/contract/invocation-info-view.js +10 -2
  22. package/contract/sc-val.js +131 -107
  23. package/controls/button-group.js +25 -19
  24. package/controls/button.js +93 -78
  25. package/controls/code-block.js +42 -34
  26. package/controls/dropdown.js +318 -287
  27. package/controls/external-link.js +10 -4
  28. package/controls/info-tooltip.js +23 -16
  29. package/controls/slider.js +29 -19
  30. package/controls/tabs.js +94 -94
  31. package/controls/tooltip.js +244 -240
  32. package/controls/update-highlighter.js +32 -27
  33. package/date/date-selector.js +56 -54
  34. package/date/elapsed-time.js +28 -21
  35. package/dex/price-dynamic.js +53 -44
  36. package/directory/directory-hooks.js +109 -97
  37. package/effect/effect-description.js +346 -344
  38. package/errors/error-boundary.js +110 -97
  39. package/horizon/horizon-account-helpers.js +104 -104
  40. package/horizon/horizon-ledger-helpers.js +35 -35
  41. package/horizon/horizon-trades-helper.js +88 -88
  42. package/horizon/horizon-transaction-helpers.js +36 -36
  43. package/index.d.ts +1241 -0
  44. package/interaction/accordion.js +43 -35
  45. package/interaction/autofocus.js +13 -9
  46. package/interaction/block-select.js +64 -53
  47. package/interaction/copy-to-clipboard.js +25 -18
  48. package/interaction/inline-progress.js +20 -15
  49. package/interaction/qr-code.js +34 -34
  50. package/interaction/responsive.js +20 -20
  51. package/interaction/spoiler.js +52 -39
  52. package/interaction/theme-selector.js +13 -10
  53. package/ledger/ledger-entry-href-formatter.js +27 -26
  54. package/ledger/ledger-entry-link.js +93 -58
  55. package/ledger/ledger-info-parser.js +46 -18
  56. package/meta/page-meta-tags.js +243 -238
  57. package/module/dynamic-module.js +47 -47
  58. package/package.json +41 -40
  59. package/state/on-screen-hooks.js +22 -22
  60. package/state/page-visibility-helpers.js +29 -16
  61. package/state/page-visibility-hooks.js +13 -11
  62. package/state/screen-orientation-hooks.js +19 -15
  63. package/state/state-hooks.js +76 -76
  64. package/state/stellar-network-hooks.js +56 -44
  65. package/state/theme.js +29 -28
  66. package/stellar/key-type.js +92 -91
  67. package/stellar/ledger-generic-id.js +39 -39
  68. package/stellar/signature-hint-utils.js +65 -65
  69. package/toast/toast-notifications-block.js +59 -59
  70. package/tx/op-description-view.js +945 -942
  71. package/tx/op-icon.js +98 -98
  72. package/tx/parser/op-balance-changes.js +66 -66
  73. package/tx/parser/op-descriptor.js +51 -48
  74. package/tx/parser/tx-details-parser.js +81 -81
  75. package/tx/parser/tx-matcher.js +371 -371
  76. package/tx/parser/type-filter-matcher.js +126 -126
  77. package/tx/tx-list-hooks.js +32 -18
  78. package/tx/tx-operations-list.js +117 -116
@@ -1,108 +1,108 @@
1
- import React from 'react'
2
- import cn from 'classnames'
3
- import {shortenString} from '@stellar-expert/formatter'
4
- import {AssetDescriptor} from '@stellar-expert/asset-descriptor'
5
- import {useStellarNetwork} from '../state/stellar-network-hooks'
6
- import {formatExplorerLink} from '../ledger/ledger-entry-href-formatter'
7
- import {AccountAddress} from '../account/account-address'
8
- import {useAssetMeta} from './asset-meta-hooks'
9
- import {AssetIcon} from './asset-icon'
10
- import {AssetIssuer} from './asset-issuer'
11
- import './asset-link.scss'
12
-
13
- /**
14
- * Explorer asset link
15
- * @param {String|AssetDescriptor|Asset} asset - Asset name/descriptor
16
- * @param {Boolean|String} [link] - Reference link
17
- * @param {Boolean} [issuer] - Whether to show asset issuer
18
- * @param {Boolean} [icon] - Whether to show asset icon
19
- * @param {String} [className] - Optional CSS class name
20
- * @param {{}} [style] - Optional CSS style
21
- * @param {*} [children] - Optional inner link text
22
- * @constructor
23
- */
24
- export const AssetLink = React.memo(function AssetLink({
25
- asset,
26
- link,
27
- issuer,
28
- icon,
29
- className,
30
- style,
31
- children: innerText
32
- }) {
33
- if (!(asset instanceof AssetDescriptor)) {
34
- asset = AssetDescriptor.parse(asset)
35
- }
36
- useStellarNetwork()
37
- const meta = useAssetMeta(asset)
38
-
39
- if (!asset)
40
- return null
41
-
42
- let children = innerText
43
- if (!innerText) {
44
- if (asset.poolId) {
45
- if (meta) {
46
- const [assetA, assetB] = meta.assets.map(a => AssetDescriptor.parse(a.asset))
47
- children = <span title={'Liquidity pool ' + asset.poolId} className="nowrap">
48
- <span>
49
- <AssetWarningStatus meta={assetA}/>
50
- {icon !== false && <AssetIcon asset={assetA}/>}
51
- {assetA.code}
52
- {issuer === true && <AssetIssuer asset={assetA}/>}
53
- </span>
54
- <span style={{fontSize: '0.7em'}}>&nbsp;<i className="icon icon-plus dimmed"/>&nbsp;</span>
55
- <span>
56
- <AssetWarningStatus meta={assetB}/>
57
- {icon !== false && <AssetIcon asset={assetB}/>}
58
- {assetB.code}
59
- {issuer === true && <AssetIssuer asset={assetB}/>}
60
- </span>
61
- </span>
62
- } else {
63
- children = <>{shortenString(asset.poolId)}</>
64
- }
65
- } else if (asset.isContract) {
66
- children = <>
67
- <AssetWarningStatus meta={meta}/>
68
- {icon !== false && <AssetIcon asset={asset}/>}
69
- {!!meta?.code && <span title={meta.tokenName}>{meta.code} </span>}
70
- {(issuer !== false || !meta?.code) &&
71
- <AccountAddress account={asset.contract} chars={8} link={false} icon={false}/>}
72
- </>
73
- } else {
74
- children = <>
75
- <AssetWarningStatus meta={meta}/>
76
- {icon !== false && <AssetIcon asset={asset}/>}
77
- {!!asset.code && asset.code}
78
- {issuer !== false && <AssetIssuer asset={asset}/>}
79
- </>
80
- }
81
- }
82
-
83
- const props = {
84
- 'aria-label': asset.toString(),
85
- className: cn('asset-link', className),
86
- style,
87
- children
88
- }
89
- if (link === false)
90
- return <span {...props}/>
91
- if (typeof link === 'string') {
92
- props.href = link
93
- } else {
94
- props.href = asset.poolId ?
95
- formatExplorerLink('liquidity-pool', asset.poolId) :
96
- formatExplorerLink('asset', asset.toString())
97
- if (window.origin !== explorerFrontendOrigin) {
98
- props.target = '_blank'
99
- }
100
- }
101
- return <a {...props}/>
102
- })
103
-
104
- function AssetWarningStatus({meta}) {
105
- if (!meta?.unsafe)
106
- return null
107
- return <i className="icon icon-warning color-warning" title="Warning: asset reported as unsafe"/>
1
+ import React from 'react'
2
+ import cn from 'classnames'
3
+ import {shortenString} from '@stellar-expert/formatter'
4
+ import {AssetDescriptor} from '@stellar-expert/asset-descriptor'
5
+ import {useStellarNetwork} from '../state/stellar-network-hooks'
6
+ import {formatExplorerLink} from '../ledger/ledger-entry-href-formatter'
7
+ import {AccountAddress} from '../account/account-address'
8
+ import {useAssetMeta} from './asset-meta-hooks'
9
+ import {AssetIcon} from './asset-icon'
10
+ import {AssetIssuer} from './asset-issuer'
11
+ import './asset-link.scss'
12
+
13
+ /**
14
+ * Explorer asset link
15
+ * @param {string|AssetDescriptor|Asset} asset - Asset name/descriptor
16
+ * @param {boolean|string} [link] - Reference link
17
+ * @param {boolean} [issuer] - Whether to show asset issuer
18
+ * @param {boolean} [icon] - Whether to show asset icon
19
+ * @param {string} [className] - Optional CSS class name
20
+ * @param {{}} [style] - Optional CSS style
21
+ * @param {*} [children] - Optional inner link text
22
+ * @constructor
23
+ */
24
+ export const AssetLink = React.memo(function AssetLink({
25
+ asset,
26
+ link,
27
+ issuer,
28
+ icon,
29
+ className,
30
+ style,
31
+ children: innerText
32
+ }) {
33
+ if (!(asset instanceof AssetDescriptor)) {
34
+ asset = AssetDescriptor.parse(asset)
35
+ }
36
+ useStellarNetwork()
37
+ const meta = useAssetMeta(asset)
38
+
39
+ if (!asset)
40
+ return null
41
+
42
+ let children = innerText
43
+ if (!innerText) {
44
+ if (asset.poolId) {
45
+ if (meta) {
46
+ const [assetA, assetB] = meta.assets.map(a => AssetDescriptor.parse(a.asset))
47
+ children = <span title={'Liquidity pool ' + asset.poolId} className="nowrap">
48
+ <span>
49
+ <AssetWarningStatus meta={assetA}/>
50
+ {icon !== false && <AssetIcon asset={assetA}/>}
51
+ {assetA.code}
52
+ {issuer === true && <AssetIssuer asset={assetA}/>}
53
+ </span>
54
+ <span style={{fontSize: '0.7em'}}>&nbsp;<i className="icon icon-plus dimmed"/>&nbsp;</span>
55
+ <span>
56
+ <AssetWarningStatus meta={assetB}/>
57
+ {icon !== false && <AssetIcon asset={assetB}/>}
58
+ {assetB.code}
59
+ {issuer === true && <AssetIssuer asset={assetB}/>}
60
+ </span>
61
+ </span>
62
+ } else {
63
+ children = <>{shortenString(asset.poolId)}</>
64
+ }
65
+ } else if (asset.isContract) {
66
+ children = <>
67
+ <AssetWarningStatus meta={meta}/>
68
+ {icon !== false && <AssetIcon asset={asset}/>}
69
+ {!!meta?.code && <span title={meta.tokenName}>{meta.code} </span>}
70
+ {(issuer !== false || !meta?.code) &&
71
+ <AccountAddress account={asset.contract} chars={8} link={false} icon={false}/>}
72
+ </>
73
+ } else {
74
+ children = <>
75
+ <AssetWarningStatus meta={meta}/>
76
+ {icon !== false && <AssetIcon asset={asset}/>}
77
+ {!!asset.code && asset.code}
78
+ {issuer !== false && <AssetIssuer asset={asset}/>}
79
+ </>
80
+ }
81
+ }
82
+
83
+ const props = {
84
+ 'aria-label': asset.toString(),
85
+ className: cn('asset-link', className),
86
+ style,
87
+ children
88
+ }
89
+ if (link === false)
90
+ return <span {...props}/>
91
+ if (typeof link === 'string') {
92
+ props.href = link
93
+ } else {
94
+ props.href = asset.poolId ?
95
+ formatExplorerLink('liquidity-pool', asset.poolId) :
96
+ formatExplorerLink('asset', asset.toString())
97
+ if (window.origin !== explorerFrontendOrigin) {
98
+ props.target = '_blank'
99
+ }
100
+ }
101
+ return <a {...props}/>
102
+ })
103
+
104
+ function AssetWarningStatus({meta}) {
105
+ if (!meta?.unsafe)
106
+ return null
107
+ return <i className="icon icon-warning color-warning" title="Warning: asset reported as unsafe"/>
108
108
  }
@@ -1,60 +1,60 @@
1
- import React, {useState} from 'react'
2
- import {throttle} from 'throttle-debounce'
3
- import equal from 'react-fast-compare'
4
- import {stringifyQuery} from '@stellar-expert/navigation'
5
- import {fetchExplorerApi} from '../api/explorer-api-call'
6
- import {useDeepEffect} from '../state/state-hooks'
7
- import {getCurrentStellarNetwork} from '../state/stellar-network-hooks'
8
-
9
- const defaults = {
10
- limit: 20,
11
- order: 'desc',
12
- sort: 'rating'
13
- }
14
-
15
- function getCurrentCursor(data) {
16
- if (!data || !data.length) return undefined
17
- return data[data.length - 1].paging_token
18
- }
19
-
20
- /**
21
- *
22
- * @param {Object} params
23
- * @return {{assets: Array<Object>, loadPage: Function, loading: Boolean}}
24
- */
25
- export function useAssetList(params) {
26
- const [loading, setLoading] = useState(false),
27
- [assets, setAssets] = useState({data: [], params}),
28
- loadPage = throttle(1000, function () {
29
- if (loading) return
30
- const requestParams = {
31
- ...defaults, ...params
32
- }
33
- if (equal(params, assets.params)) {
34
- requestParams.cursor = getCurrentCursor(assets.data)
35
- }
36
- const endpoint = getCurrentStellarNetwork() + '/asset' + stringifyQuery(requestParams)
37
- setLoading(true)
38
- fetchExplorerApi(endpoint)
39
- .then(res => {
40
- const {records} = res._embedded
41
- setAssets(existing => {
42
- let data = records
43
- if (equal(params, existing.params)) {
44
- data = [...existing.data, ...records]
45
- }
46
- return {data, params}
47
- })
48
- setLoading(false)
49
- })
50
- .catch(e => console.error(e))
51
- .finally(() => {
52
- setLoading(false)
53
- })
54
- })
55
- useDeepEffect(() => {
56
- loadPage()
57
- }, [params])
58
-
59
- return {assets: assets.data, loadPage, loading}
1
+ import React, {useState} from 'react'
2
+ import {throttle} from 'throttle-debounce'
3
+ import equal from 'react-fast-compare'
4
+ import {stringifyQuery} from '@stellar-expert/navigation'
5
+ import {fetchExplorerApi} from '../api/explorer-api-call'
6
+ import {useDeepEffect} from '../state/state-hooks'
7
+ import {getCurrentStellarNetwork} from '../state/stellar-network-hooks'
8
+
9
+ const defaults = {
10
+ limit: 20,
11
+ order: 'desc',
12
+ sort: 'rating'
13
+ }
14
+
15
+ function getCurrentCursor(data) {
16
+ if (!data || !data.length) return undefined
17
+ return data[data.length - 1].paging_token
18
+ }
19
+
20
+ /**
21
+ *
22
+ * @param {Object} params
23
+ * @return {{assets: Array<Object>, loadPage: function, loading: boolean}}
24
+ */
25
+ export function useAssetList(params) {
26
+ const [loading, setLoading] = useState(false),
27
+ [assets, setAssets] = useState({data: [], params}),
28
+ loadPage = throttle(1000, function () {
29
+ if (loading) return
30
+ const requestParams = {
31
+ ...defaults, ...params
32
+ }
33
+ if (equal(params, assets.params)) {
34
+ requestParams.cursor = getCurrentCursor(assets.data)
35
+ }
36
+ const endpoint = getCurrentStellarNetwork() + '/asset' + stringifyQuery(requestParams)
37
+ setLoading(true)
38
+ fetchExplorerApi(endpoint)
39
+ .then(res => {
40
+ const {records} = res._embedded
41
+ setAssets(existing => {
42
+ let data = records
43
+ if (equal(params, existing.params)) {
44
+ data = [...existing.data, ...records]
45
+ }
46
+ return {data, params}
47
+ })
48
+ setLoading(false)
49
+ })
50
+ .catch(e => console.error(e))
51
+ .finally(() => {
52
+ setLoading(false)
53
+ })
54
+ })
55
+ useDeepEffect(() => {
56
+ loadPage()
57
+ }, [params])
58
+
59
+ return {assets: assets.data, loadPage, loading}
60
60
  }
@@ -1,89 +1,89 @@
1
- import {useEffect, useState} from 'react'
2
- import {AssetDescriptor} from '@stellar-expert/asset-descriptor'
3
- import {stringifyQuery} from '@stellar-expert/navigation'
4
- import {InMemoryClientCache} from '@stellar-expert/client-cache'
5
- import {fetchExplorerApi} from '../api/explorer-api-call'
6
- import {ExplorerBatchInfoLoader} from '../api/explorer-batch-info-loader'
7
- import {getCurrentStellarNetwork} from '../state/stellar-network-hooks'
8
-
9
- /**
10
- * @typedef AssetBasicTomlInfo
11
- * @property {String} name
12
- * @property {String} orgName
13
- * @property {String} image
14
- * @property {Number} decimals
15
- */
16
-
17
- /**
18
- * @typedef AssetMeta
19
- * @property {String} name
20
- * @property {String} domain
21
- * @property {AssetBasicTomlInfo} toml_info
22
- */
23
-
24
- const cache = new InMemoryClientCache()
25
-
26
- const loader = new ExplorerBatchInfoLoader(batch => {
27
- return fetchExplorerApi(getCurrentStellarNetwork() + '/asset/meta' + stringifyQuery({
28
- asset: batch,
29
- origin: window.location.origin
30
- }))
31
- }, entry => {
32
- cache.set(entry.name, entry)
33
- return {
34
- key: entry.name,
35
- info: entry
36
- }
37
- })
38
-
39
- function retrieveFromCache(asset) {
40
- //try to load from the shared cache
41
- const cachedEntry = cache.get(asset)
42
- if (cachedEntry && !cachedEntry.isStale) {
43
- if (!cachedEntry.isExpired)
44
- return cachedEntry.data//everything is up to date - no need to re-fetch
45
- }
46
- }
47
-
48
- function normalizeAssetName(asset) {
49
- if (!asset)
50
- return null
51
- if (typeof asset === 'string' && asset.length === 56)
52
- return asset //contract id
53
- return AssetDescriptor.parse(asset).toFQAN()
54
- }
55
-
56
- /**
57
- *
58
- * @param {AssetDescriptor|String} asset
59
- * @return {AssetMeta}
60
- */
61
- export function useAssetMeta(asset) {
62
- try {
63
- asset = normalizeAssetName(asset)
64
- } catch (e) {
65
- asset = null
66
- }
67
- const [assetInfo, setAssetInfo] = useState(retrieveFromCache(asset))
68
- useEffect(() => {
69
- if (!asset)
70
- return
71
- const cached = retrieveFromCache(asset)
72
- setAssetInfo(cached)
73
- if (cached)
74
- return
75
- let unloaded = false
76
- //load from the server
77
- loader.loadEntry(asset)
78
- .then(a => {
79
- if (unloaded)
80
- return
81
- setAssetInfo(a)
82
- })
83
- return () => {
84
- unloaded = true
85
- }
86
- }, [asset])
87
-
88
- return assetInfo
1
+ import {useEffect, useState} from 'react'
2
+ import {AssetDescriptor} from '@stellar-expert/asset-descriptor'
3
+ import {stringifyQuery} from '@stellar-expert/navigation'
4
+ import {InMemoryClientCache} from '@stellar-expert/client-cache'
5
+ import {fetchExplorerApi} from '../api/explorer-api-call'
6
+ import {ExplorerBatchInfoLoader} from '../api/explorer-batch-info-loader'
7
+ import {getCurrentStellarNetwork} from '../state/stellar-network-hooks'
8
+
9
+ /**
10
+ * @typedef AssetBasicTomlInfo
11
+ * @property {string} name
12
+ * @property {string} orgName
13
+ * @property {string} image
14
+ * @property {number} decimals
15
+ */
16
+
17
+ /**
18
+ * @typedef AssetMeta
19
+ * @property {string} name
20
+ * @property {string} domain
21
+ * @property {AssetBasicTomlInfo} toml_info
22
+ */
23
+
24
+ const cache = new InMemoryClientCache()
25
+
26
+ const loader = new ExplorerBatchInfoLoader(batch => {
27
+ return fetchExplorerApi(getCurrentStellarNetwork() + '/asset/meta' + stringifyQuery({
28
+ asset: batch,
29
+ origin: window.location.origin
30
+ }))
31
+ }, entry => {
32
+ cache.set(entry.name, entry)
33
+ return {
34
+ key: entry.name,
35
+ info: entry
36
+ }
37
+ })
38
+
39
+ function retrieveFromCache(asset) {
40
+ //try to load from the shared cache
41
+ const cachedEntry = cache.get(asset)
42
+ if (cachedEntry && !cachedEntry.isStale) {
43
+ if (!cachedEntry.isExpired)
44
+ return cachedEntry.data//everything is up to date - no need to re-fetch
45
+ }
46
+ }
47
+
48
+ function normalizeAssetName(asset) {
49
+ if (!asset)
50
+ return null
51
+ if (typeof asset === 'string' && asset.length === 56)
52
+ return asset //contract id
53
+ return AssetDescriptor.parse(asset).toFQAN()
54
+ }
55
+
56
+ /**
57
+ *
58
+ * @param {AssetDescriptor|string} asset
59
+ * @return {AssetMeta}
60
+ */
61
+ export function useAssetMeta(asset) {
62
+ try {
63
+ asset = normalizeAssetName(asset)
64
+ } catch (e) {
65
+ asset = null
66
+ }
67
+ const [assetInfo, setAssetInfo] = useState(retrieveFromCache(asset))
68
+ useEffect(() => {
69
+ if (!asset)
70
+ return
71
+ const cached = retrieveFromCache(asset)
72
+ setAssetInfo(cached)
73
+ if (cached)
74
+ return
75
+ let unloaded = false
76
+ //load from the server
77
+ loader.loadEntry(asset)
78
+ .then(a => {
79
+ if (unloaded)
80
+ return
81
+ setAssetInfo(a)
82
+ })
83
+ return () => {
84
+ unloaded = true
85
+ }
86
+ }, [asset])
87
+
88
+ return assetInfo
89
89
  }