@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,92 +1,93 @@
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)
1
+ import {StrKey} from '@stellar/stellar-base'
2
+
3
+ /**
4
+ * Decode StrKey-encoded Stellar key and determine its type
5
+ * @param {string} key
6
+ * @return {{address: string, type: ('muxed'|'ed25519'|'hash'|'tx'|'contract'), [muxedId]: bigint}|null}
7
+ * @internal
8
+ */
9
+ export function decodeKeyType(key) {
10
+ if (typeof key !== 'string')
11
+ return null
12
+ const prefix = key[0]
13
+ try {
14
+ switch (prefix) {
15
+ case 'G':
16
+ checkLength(key)
17
+ return {
18
+ type: 'ed25519',
19
+ address: key
20
+ }
21
+ case 'C':
22
+ checkLength(key)
23
+ return {
24
+ type: 'contract',
25
+ address: key
26
+ }
27
+ case 'M':
28
+ return {
29
+ type: 'muxed',
30
+ ...parseMuxedAccount(key)
31
+ }
32
+ case 'X':
33
+ checkLength(key)
34
+ return {
35
+ type: 'hash',
36
+ address: key
37
+ }
38
+ case 'T':
39
+ checkLength(key)
40
+ return {
41
+ type: 'tx',
42
+ address: key
43
+ }
44
+ case 'P':
45
+ const spayload = StrKey.decodeSignedPayload(key)
46
+ return {
47
+ type: 'signedPayload',
48
+ address: key,
49
+ publicKey: StrKey.encodeEd25519PublicKey(spayload.slice(0, 32)),
50
+ payload: spayload.slice(36, 36 + spayload.readUIntBE(32, 4)).toString('hex')
51
+ }
52
+ default:
53
+ console.error(new Error('Unknown key prefix: ' + typeof key))
54
+ return null
55
+ }
56
+ } catch (e) {
57
+ console.error(e)
58
+ return null
59
+ }
60
+ }
61
+
62
+ function checkLength(key, length = 56) {
63
+ if (key.length !== length)
64
+ throw new Error('Invalid key length: ' + key)
65
+ }
66
+
67
+ /**
68
+ * Parse multiplexed account address
69
+ * @param {string} muxedAddress - Multiplexed Stellar address
70
+ * @return {{address: string, muxedId: bigint}}
71
+ */
72
+ export function parseMuxedAccount(muxedAddress) {
73
+ const muxed = StrKey.decodeMed25519PublicKey(muxedAddress)
74
+ return {
75
+ address: StrKey.encodeEd25519PublicKey(muxed.slice(0, 32)),
76
+ muxedId: muxed.readBigInt64BE(32)
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Encode address and identifier into a multiplexed address
82
+ * @param {string} address - StrKey-encode Stellar account address
83
+ * @param {bigint} muxedId - Multiplexed int64 id
84
+ * @return {string}
85
+ */
86
+ export function encodeMuxedAccount(address, muxedId) {
87
+ const raw = Buffer.allocUnsafe(40)
88
+ //write 32 bytes of ed25519 pubkey
89
+ StrKey.decodeEd25519PublicKey(address).copy(raw)
90
+ //write 8 id bytes
91
+ raw.writeBigInt64BE(muxedId, 32)
92
+ return StrKey.encodeMed25519PublicKey(raw)
92
93
  }
@@ -1,40 +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
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
40
  }
@@ -1,65 +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 {Signature} 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
- }
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 {Signature} 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
+ }
@@ -1,60 +1,60 @@
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
- /**
37
- * Show toast notification popup
38
- * @param {'info'|'success'|'warning'|'error'} type - Notification type
39
- * @param {String} message - Message to show
40
- */
41
- window.notify = function ({type, message}) {
42
- const newNotification = new ToastNotificationInstance({
43
- type,
44
- message,
45
- id: ++notificationsCounter,
46
- onDelete: deleteNotification
47
- })
48
- setNotifications(prevNotifications => [newNotification, ...prevNotifications])
49
- }
50
- //set empty callback on unload
51
- return () => {
52
- window.notify = function () {
53
- }
54
- }
55
- }, [])
56
-
57
- return <div className="toast-notifications-container">
58
- {notifications.map(props => <Notification key={props.id} notification={props}/>)}
59
- </div>
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
+ /**
37
+ * Show toast notification popup
38
+ * @param {'info'|'success'|'warning'|'error'} type - Notification type
39
+ * @param {string} message - Message to show
40
+ */
41
+ window.notify = function ({type, message}) {
42
+ const newNotification = new ToastNotificationInstance({
43
+ type,
44
+ message,
45
+ id: ++notificationsCounter,
46
+ onDelete: deleteNotification
47
+ })
48
+ setNotifications(prevNotifications => [newNotification, ...prevNotifications])
49
+ }
50
+ //set empty callback on unload
51
+ return () => {
52
+ window.notify = function () {
53
+ }
54
+ }
55
+ }, [])
56
+
57
+ return <div className="toast-notifications-container">
58
+ {notifications.map(props => <Notification key={props.id} notification={props}/>)}
59
+ </div>
60
60
  }