@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.
Files changed (85) hide show
  1. package/README.md +1168 -3
  2. package/account/account-address.js +127 -127
  3. package/account/available-balance.js +22 -22
  4. package/account/identicon.js +90 -90
  5. package/account/signer-key.js +65 -64
  6. package/api/explorer-api-hooks.js +209 -202
  7. package/api/explorer-api-paginated-list-hooks.js +441 -440
  8. package/api/explorer-batch-info-loader.js +111 -85
  9. package/api/explorer-tx-api.js +28 -28
  10. package/api/ledger-stream.js +15 -0
  11. package/asset/amount.js +56 -56
  12. package/asset/asset-icon.js +41 -41
  13. package/asset/asset-issuer.js +21 -21
  14. package/asset/asset-link.js +107 -107
  15. package/asset/asset-list-hooks.js +59 -59
  16. package/asset/asset-meta-hooks.js +88 -88
  17. package/asset/asset-selector.js +72 -71
  18. package/claimable-balance/claimable-balance-claimants.js +23 -18
  19. package/contract/contract-api.js +15 -0
  20. package/contract/invocation-info-view.js +10 -2
  21. package/contract/sc-val.js +131 -107
  22. package/controls/button-group.js +25 -19
  23. package/controls/button.js +93 -78
  24. package/controls/code-block.js +42 -34
  25. package/controls/dropdown.js +318 -287
  26. package/controls/external-link.js +10 -4
  27. package/controls/info-tooltip.js +23 -16
  28. package/controls/slider.js +29 -19
  29. package/controls/tabs.js +94 -94
  30. package/controls/tooltip.js +244 -240
  31. package/controls/update-highlighter.js +32 -27
  32. package/date/date-selector.js +56 -54
  33. package/date/elapsed-time.js +28 -21
  34. package/dex/price-dynamic.js +53 -44
  35. package/directory/directory-hooks.js +109 -97
  36. package/effect/effect-description.js +346 -344
  37. package/errors/error-boundary.js +110 -97
  38. package/filter/editors/account-filter-view.js +20 -0
  39. package/filter/editors/asset-filter-view.js +9 -0
  40. package/filter/editors/timestamp-filter-view.js +34 -0
  41. package/filter/editors/type-filter-view.js +148 -0
  42. package/filter/filter-editors.js +102 -0
  43. package/filter/filter-view.js +218 -0
  44. package/filter/filter.scss +57 -0
  45. package/horizon/horizon-account-helpers.js +104 -104
  46. package/horizon/horizon-ledger-helpers.js +35 -35
  47. package/horizon/horizon-trades-helper.js +88 -88
  48. package/horizon/horizon-transaction-helpers.js +36 -36
  49. package/index.d.ts +1271 -0
  50. package/index.js +95 -93
  51. package/interaction/accordion.js +43 -35
  52. package/interaction/autofocus.js +13 -9
  53. package/interaction/block-select.js +64 -53
  54. package/interaction/copy-to-clipboard.js +25 -18
  55. package/interaction/inline-progress.js +20 -15
  56. package/interaction/qr-code.js +34 -34
  57. package/interaction/responsive.js +20 -20
  58. package/interaction/spoiler.js +52 -39
  59. package/interaction/theme-selector.js +13 -10
  60. package/ledger/ledger-entry-href-formatter.js +27 -26
  61. package/ledger/ledger-entry-link.js +93 -58
  62. package/ledger/ledger-info-parser.js +46 -18
  63. package/meta/page-meta-tags.js +243 -238
  64. package/module/dynamic-module.js +47 -47
  65. package/package.json +71 -40
  66. package/state/on-screen-hooks.js +22 -22
  67. package/state/page-visibility-helpers.js +29 -16
  68. package/state/page-visibility-hooks.js +13 -11
  69. package/state/screen-orientation-hooks.js +19 -15
  70. package/state/state-hooks.js +76 -76
  71. package/state/stellar-network-hooks.js +56 -44
  72. package/state/theme.js +29 -28
  73. package/stellar/key-type.js +92 -91
  74. package/stellar/ledger-generic-id.js +39 -39
  75. package/stellar/signature-hint-utils.js +65 -65
  76. package/toast/toast-notifications-block.js +59 -59
  77. package/tx/op-description-view.js +945 -942
  78. package/tx/op-icon.js +98 -98
  79. package/tx/parser/op-balance-changes.js +66 -66
  80. package/tx/parser/op-descriptor.js +51 -48
  81. package/tx/parser/tx-details-parser.js +81 -81
  82. package/tx/parser/tx-matcher.js +371 -371
  83. package/tx/parser/type-filter-matcher.js +126 -126
  84. package/tx/tx-list-hooks.js +32 -18
  85. package/tx/tx-operations-list.js +117 -116
package/index.js CHANGED
@@ -1,93 +1,95 @@
1
- import './index.scss'
2
-
3
- window.explorerFrontendOrigin = window.explorerFrontendOrigin || 'https://stellar.expert'
4
- window.explorerApiOrigin = window.explorerApiOrigin || 'https://api.stellar.expert'
5
- window.horizonOrigin = window.horizonOrigin || 'https://horizon.stellar.org'
6
-
7
- //modules
8
- export * from './module/dynamic-module'
9
- //state management and utils
10
- export * from './state/state-hooks'
11
- export * from './state/on-screen-hooks'
12
- export * from './state/stellar-network-hooks'
13
- export * from './state/screen-orientation-hooks'
14
- export * from './state/page-visibility-helpers'
15
- export * from './state/theme'
16
- export * from './meta/page-meta-tags'
17
- //explorer API bindings
18
- export * from './api/explorer-api-hooks'
19
- export * from './api/explorer-api-paginated-list-hooks'
20
- export * from './api/explorer-tx-api'
21
- export * from './api/explorer-batch-info-loader'
22
- export * from './api/ledger-stream'
23
- //Horizon API binding and utils
24
- export * from './stellar/ledger-generic-id'
25
- export * from './horizon/horizon-client-helpers'
26
- export * from './horizon/horizon-ledger-helpers'
27
- export * from './horizon/horizon-transaction-helpers'
28
- export * from './horizon/horizon-account-helpers'
29
- export * from './horizon/horizon-orderbook-helpers'
30
- export * from './horizon/horizon-trades-helper'
31
- //basic UI controls
32
- export * from './controls/button'
33
- export * from './controls/button-group'
34
- export * from './controls/info-tooltip'
35
- export * from './controls/tooltip'
36
- export * from './controls/update-highlighter'
37
- export * from './controls/tabs'
38
- export * from './controls/dropdown'
39
- export * from './controls/code-block'
40
- export * from './controls/slider'
41
- export * from './controls/external-link'
42
- export * from './toast/toast-notifications-block'
43
- export * from './errors/error-boundary'
44
- //interaction
45
- export * from './interaction/autofocus'
46
- export * from './interaction/block-select'
47
- export * from './interaction/copy-to-clipboard'
48
- export * from './interaction/spoiler'
49
- export * from './interaction/accordion'
50
- export * from './interaction/theme-selector'
51
- export * from './interaction/inline-progress'
52
- export * from './interaction/responsive'
53
- export * from './interaction/qr-code'
54
- export * from './interaction/dialog'
55
- export * from './interaction/system-dialog'
56
- //date components
57
- export * from './date/utc-timestamp'
58
- export * from './date/elapsed-time'
59
- export * from './date/date-selector'
60
- //ledger-entries-related components
61
- export * from './ledger/ledger-entry-link'
62
- export * from './ledger/ledger-entry-href-formatter'
63
- export * from './ledger/ledger-info-parser'
64
- //account-related components
65
- export * from './account/identicon'
66
- export * from './account/account-address'
67
- export * from './account/signer-key'
68
- export * from './account/available-balance'
69
- //asset-related components
70
- export * from './asset/asset-link'
71
- export * from './asset/asset-issuer'
72
- export * from './asset/asset-icon'
73
- export * from './asset/asset-selector'
74
- export * from './asset/amount'
75
- export * from './asset/asset-meta-hooks'
76
- export * from './asset/asset-list-hooks'
77
- //claimable-balance-related components
78
- export * from './claimable-balance/claimable-balance-claimants'
79
- //DEX-related components
80
- export * from './dex/price-dynamic'
81
- //directory-related components
82
- export * from './directory/directory-hooks'
83
- //transaction/operation/effects components
84
- export * from './tx/tx-operations-list'
85
- export * from './tx/parser/tx-details-parser'
86
- export * from './tx/tx-list-hooks'
87
- export * from './effect/effect-description'
88
- //contract-related components
89
- export * from './contract/contract-api'
90
- //Stellar-specific utils
91
- export * from './stellar/key-type'
92
- export * from './stellar/signature-hint-utils'
93
- export * from './contract/sc-val'
1
+ import './index.scss'
2
+
3
+ window.explorerFrontendOrigin = window.explorerFrontendOrigin || 'https://stellar.expert'
4
+ window.explorerApiOrigin = window.explorerApiOrigin || 'https://api.stellar.expert'
5
+ window.horizonOrigin = window.horizonOrigin || 'https://horizon.stellar.org'
6
+
7
+ //modules
8
+ export * from './module/dynamic-module'
9
+ //state management and utils
10
+ export * from './state/state-hooks'
11
+ export * from './state/on-screen-hooks'
12
+ export * from './state/stellar-network-hooks'
13
+ export * from './state/screen-orientation-hooks'
14
+ export * from './state/page-visibility-helpers'
15
+ export * from './state/theme'
16
+ export * from './meta/page-meta-tags'
17
+ //explorer API bindings
18
+ export * from './api/explorer-api-hooks'
19
+ export * from './api/explorer-api-paginated-list-hooks'
20
+ export * from './api/explorer-tx-api'
21
+ export * from './api/explorer-batch-info-loader'
22
+ export * from './api/ledger-stream'
23
+ //Horizon API binding and utils
24
+ export * from './stellar/ledger-generic-id'
25
+ export * from './horizon/horizon-client-helpers'
26
+ export * from './horizon/horizon-ledger-helpers'
27
+ export * from './horizon/horizon-transaction-helpers'
28
+ export * from './horizon/horizon-account-helpers'
29
+ export * from './horizon/horizon-orderbook-helpers'
30
+ export * from './horizon/horizon-trades-helper'
31
+ //basic UI controls
32
+ export * from './controls/button'
33
+ export * from './controls/button-group'
34
+ export * from './controls/info-tooltip'
35
+ export * from './controls/tooltip'
36
+ export * from './controls/update-highlighter'
37
+ export * from './controls/tabs'
38
+ export * from './controls/dropdown'
39
+ export * from './controls/code-block'
40
+ export * from './controls/slider'
41
+ export * from './controls/external-link'
42
+ export * from './toast/toast-notifications-block'
43
+ export * from './errors/error-boundary'
44
+ //interaction
45
+ export * from './interaction/autofocus'
46
+ export * from './interaction/block-select'
47
+ export * from './interaction/copy-to-clipboard'
48
+ export * from './interaction/spoiler'
49
+ export * from './interaction/accordion'
50
+ export * from './interaction/theme-selector'
51
+ export * from './interaction/inline-progress'
52
+ export * from './interaction/responsive'
53
+ export * from './interaction/qr-code'
54
+ export * from './interaction/dialog'
55
+ export * from './interaction/system-dialog'
56
+ //date components
57
+ export * from './date/utc-timestamp'
58
+ export * from './date/elapsed-time'
59
+ export * from './date/date-selector'
60
+ //ledger-entries-related components
61
+ export * from './ledger/ledger-entry-link'
62
+ export * from './ledger/ledger-entry-href-formatter'
63
+ export * from './ledger/ledger-info-parser'
64
+ //account-related components
65
+ export * from './account/identicon'
66
+ export * from './account/account-address'
67
+ export * from './account/signer-key'
68
+ export * from './account/available-balance'
69
+ //asset-related components
70
+ export * from './asset/asset-link'
71
+ export * from './asset/asset-issuer'
72
+ export * from './asset/asset-icon'
73
+ export * from './asset/asset-selector'
74
+ export * from './asset/amount'
75
+ export * from './asset/asset-meta-hooks'
76
+ export * from './asset/asset-list-hooks'
77
+ //claimable-balance-related components
78
+ export * from './claimable-balance/claimable-balance-claimants'
79
+ //DEX-related components
80
+ export * from './dex/price-dynamic'
81
+ //directory-related components
82
+ export * from './directory/directory-hooks'
83
+ //transaction/operation/effects components
84
+ export * from './tx/tx-operations-list'
85
+ export * from './tx/parser/tx-details-parser'
86
+ export * from './tx/tx-list-hooks'
87
+ export * from './effect/effect-description'
88
+ //contract-related components
89
+ export * from './contract/contract-api'
90
+ //filter component
91
+ export * from './filter/filter-view'
92
+ //Stellar-specific utils
93
+ export * from './stellar/key-type'
94
+ export * from './stellar/signature-hint-utils'
95
+ export * from './contract/sc-val'
@@ -1,36 +1,44 @@
1
- import React, {useCallback, useEffect, useState} from 'react'
2
- import cn from 'classnames'
3
- import './accordion.scss'
4
-
5
- /**
6
- * Group of collapsible panels
7
- * @param {{key: String, title: String|JSX.Element, content:*}[]} options - Accordion options
8
- * @param {String} [collapsedSymbol] - Prefix to show for collapsed panels
9
- * @param {String} [expandedSymbol] - Prefix to show for expanded panel
10
- */
11
- export function Accordion({options, collapsedSymbol = '+', expandedSymbol = '-', ...otherProps}) {
12
- const [selectedOption, setSelectedOption] = useState()
13
- useEffect(() => {
14
- const firstOption = options[0]
15
- setSelectedOption(firstOption.key || firstOption.title)
16
- }, [options])
17
- const changeSelected = useCallback(e => setSelectedOption(e.currentTarget.dataset.key), [options])
18
- return <div className="accordion" {...otherProps}>
19
- {options.map(({key, title, content}) => {
20
- const expanded = key ?
21
- selectedOption === key :
22
- selectedOption === title
23
- return <div key={key || title} className={cn('option', {expanded})}>
24
- <div className="accordion-header" data-collapsed={collapsedSymbol} data-expanded={expandedSymbol} data-key={key || title}
25
- onClick={changeSelected}>
26
- {title || key}
27
- </div>
28
- <div className="accordion-collapse">
29
- <div className="accordion-body">
30
- {content}
31
- </div>
32
- </div>
33
- </div>
34
- })}
35
- </div>
1
+ import React, {useCallback, useEffect, useState} from 'react'
2
+ import cn from 'classnames'
3
+ import './accordion.scss'
4
+
5
+ /**
6
+ * @typedef {Object} AccordionOption
7
+ * @property {string} [key] - Unique key for the panel (falls back to title)
8
+ * @property {string|JSX.Element} title - Panel header content
9
+ * @property {*} content - Panel body content
10
+ */
11
+
12
+ /**
13
+ * Group of collapsible panels where only one panel is expanded at a time
14
+ * @param {Object} props
15
+ * @param {AccordionOption[]} props.options - Accordion panel definitions
16
+ * @param {string} [props.collapsedSymbol='+'] - Prefix shown for collapsed panels
17
+ * @param {string} [props.expandedSymbol='-'] - Prefix shown for the expanded panel
18
+ */
19
+ export function Accordion({options, collapsedSymbol = '+', expandedSymbol = '-', ...otherProps}) {
20
+ const [selectedOption, setSelectedOption] = useState()
21
+ useEffect(() => {
22
+ const firstOption = options[0]
23
+ setSelectedOption(firstOption.key || firstOption.title)
24
+ }, [options])
25
+ const changeSelected = useCallback(e => setSelectedOption(e.currentTarget.dataset.key), [options])
26
+ return <div className="accordion" {...otherProps}>
27
+ {options.map(({key, title, content}) => {
28
+ const expanded = key ?
29
+ selectedOption === key :
30
+ selectedOption === title
31
+ return <div key={key || title} className={cn('option', {expanded})}>
32
+ <div className="accordion-header" data-collapsed={collapsedSymbol} data-expanded={expandedSymbol} data-key={key || title}
33
+ onClick={changeSelected}>
34
+ {title || key}
35
+ </div>
36
+ <div className="accordion-collapse">
37
+ <div className="accordion-body">
38
+ {content}
39
+ </div>
40
+ </div>
41
+ </div>
42
+ })}
43
+ </div>
36
44
  }
@@ -1,9 +1,13 @@
1
- export function useAutoFocusRef(inputRef) {
2
- if (!inputRef)
3
- return
4
- setTimeout(() => {
5
- if (document.body.contains(inputRef)) {
6
- inputRef.focus()
7
- }
8
- }, 200)
9
- }
1
+ /**
2
+ * Auto-focuses the given DOM element after a short delay (ref callback)
3
+ * @param {HTMLElement} inputRef - DOM element to focus
4
+ */
5
+ export function useAutoFocusRef(inputRef) {
6
+ if (!inputRef)
7
+ return
8
+ setTimeout(() => {
9
+ if (document.body.contains(inputRef)) {
10
+ inputRef.focus()
11
+ }
12
+ }, 200)
13
+ }
@@ -1,54 +1,65 @@
1
- import React from 'react'
2
- import PropTypes from 'prop-types'
3
- import cn from 'classnames'
4
- import './block-select.scss'
5
-
6
- function select(target) {
7
- //handle textarea and inputs
8
- if (target.nodeName.match(/^(INPUT|TEXTAREA)$/i)) {
9
- target.focus()
10
- target.select()
11
- return
12
- }
13
- //handle selection inside text elements
14
- const range = document.createRange()
15
- range.selectNodeContents(target)
16
- const sel = window.getSelection()
17
- if (typeof sel.setBaseAndExtent === 'function') {
18
- // Safari
19
- sel.setBaseAndExtent(target, 0, target, 1)
20
- }
21
- sel.removeAllRanges()
22
- sel.addRange(range)
23
- }
24
-
25
- export const BlockSelect = React.memo(function BlockSelect({as = 'span', children, title, className, wrap, inline, style, ...op}) {
26
- const props = {
27
- className: cn('block-select', className),
28
- onFocus: e => select(e.target),
29
- tabIndex: '-1',
30
- style,
31
- title,
32
- ...op
33
- }
34
- if (wrap) {
35
- props.style = {...props.style, whiteSpace: 'normal', overflow: 'visible'}
36
- }
37
- if (wrap === false) {
38
- props.style = {...props.style, whiteSpace: 'nowrap', overflow: 'hidden'}
39
- }
40
- if (inline) {
41
- props.style = {...props.style, display: 'inline'}
42
- }
43
- return React.createElement(as, props, children)
44
- })
45
-
46
- BlockSelect.propTypes = {
47
- children: PropTypes.any.isRequired,
48
- title: PropTypes.string,
49
- className: PropTypes.string,
50
- style: PropTypes.object,
51
- wrap: PropTypes.bool,
52
- inline: PropTypes.bool,
53
- as: PropTypes.string
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import cn from 'classnames'
4
+ import './block-select.scss'
5
+
6
+ function select(target) {
7
+ //handle textarea and inputs
8
+ if (target.nodeName.match(/^(INPUT|TEXTAREA)$/i)) {
9
+ target.focus()
10
+ target.select()
11
+ return
12
+ }
13
+ //handle selection inside text elements
14
+ const range = document.createRange()
15
+ range.selectNodeContents(target)
16
+ const sel = window.getSelection()
17
+ if (typeof sel.setBaseAndExtent === 'function') {
18
+ // Safari
19
+ sel.setBaseAndExtent(target, 0, target, 1)
20
+ }
21
+ sel.removeAllRanges()
22
+ sel.addRange(range)
23
+ }
24
+
25
+ /**
26
+ * Block that selects all its text content on focus/click
27
+ * @param {Object} props
28
+ * @param {string} [props.as='span'] - HTML tag to render
29
+ * @param {*} props.children - Content to display
30
+ * @param {string} [props.title] - HTML title attribute
31
+ * @param {string} [props.className] - Additional CSS classes
32
+ * @param {boolean} [props.wrap] - Enable text wrapping (true) or disable it (false)
33
+ * @param {boolean} [props.inline] - Force inline display
34
+ * @param {Object} [props.style] - Inline styles
35
+ */
36
+ export const BlockSelect = React.memo(function BlockSelect({as = 'span', children, title, className, wrap, inline, style, ...op}) {
37
+ const props = {
38
+ className: cn('block-select', className),
39
+ onFocus: e => select(e.target),
40
+ tabIndex: '-1',
41
+ style,
42
+ title,
43
+ ...op
44
+ }
45
+ if (wrap) {
46
+ props.style = {...props.style, whiteSpace: 'normal', overflow: 'visible'}
47
+ }
48
+ if (wrap === false) {
49
+ props.style = {...props.style, whiteSpace: 'nowrap', overflow: 'hidden'}
50
+ }
51
+ if (inline) {
52
+ props.style = {...props.style, display: 'inline'}
53
+ }
54
+ return React.createElement(as, props, children)
55
+ })
56
+
57
+ BlockSelect.propTypes = {
58
+ children: PropTypes.any.isRequired,
59
+ title: PropTypes.string,
60
+ className: PropTypes.string,
61
+ style: PropTypes.object,
62
+ wrap: PropTypes.bool,
63
+ inline: PropTypes.bool,
64
+ as: PropTypes.string
54
65
  }
@@ -1,19 +1,26 @@
1
- import React from 'react'
2
- import PropTypes from 'prop-types'
3
- import {CopyToClipboard as Copy} from 'react-copy-to-clipboard'
4
-
5
- export const CopyToClipboard = React.memo(function CopyToClipboard({text, children, title}) {
6
- return <Copy text={text}>
7
- {children ? children : <a href="#" className="icon-copy active-icon" title={title}/>}
8
- </Copy>
9
- })
10
-
11
- CopyToClipboard.defaultProps = {
12
- title: 'Copy to clipboard'
13
- }
14
-
15
- CopyToClipboard.propTypes = {
16
- text: PropTypes.string.isRequired,
17
- title: PropTypes.string,
18
- children: PropTypes.any
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import {CopyToClipboard as Copy} from 'react-copy-to-clipboard'
4
+
5
+ /**
6
+ * Copy-to-clipboard wrapper; shows a default copy icon if no children are provided
7
+ * @param {Object} props
8
+ * @param {string} props.text - Text to copy to clipboard
9
+ * @param {*} [props.children] - Custom trigger element (defaults to a copy icon)
10
+ * @param {string} [props.title='Copy to clipboard'] - Tooltip text
11
+ */
12
+ export const CopyToClipboard = React.memo(function CopyToClipboard({text, children, title}) {
13
+ return <Copy text={text}>
14
+ {children ? children : <a href="#" className="icon-copy active-icon" title={title}/>}
15
+ </Copy>
16
+ })
17
+
18
+ CopyToClipboard.defaultProps = {
19
+ title: 'Copy to clipboard'
20
+ }
21
+
22
+ CopyToClipboard.propTypes = {
23
+ text: PropTypes.string.isRequired,
24
+ title: PropTypes.string,
25
+ children: PropTypes.any
19
26
  }
@@ -1,16 +1,21 @@
1
- import React, {useEffect, useRef, useState} from 'react'
2
- import PropTypes from 'prop-types'
3
-
4
- export const InlineProgress = React.memo(function InlineProgress({dots = 5}) {
5
- const [progress, setProgress] = useState(0),
6
- intervalRef = useRef(0)
7
- useEffect(() => {
8
- intervalRef.current = setInterval(() => setProgress(p => ++p), 500)
9
- return () => clearInterval(intervalRef.current)
10
- }, [])
11
- return <span>{'.'.repeat(progress % (dots + 1))}</span>
12
- })
13
-
14
- InlineProgress.propTypes = {
15
- dots: PropTypes.number
1
+ import React, {useEffect, useRef, useState} from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ /**
5
+ * Animated inline progress indicator that cycles through dots
6
+ * @param {Object} props
7
+ * @param {number} [props.dots=5] - Maximum number of dots to display
8
+ */
9
+ export const InlineProgress = React.memo(function InlineProgress({dots = 5}) {
10
+ const [progress, setProgress] = useState(0),
11
+ intervalRef = useRef(0)
12
+ useEffect(() => {
13
+ intervalRef.current = setInterval(() => setProgress(p => ++p), 500)
14
+ return () => clearInterval(intervalRef.current)
15
+ }, [])
16
+ return <span>{'.'.repeat(progress % (dots + 1))}</span>
17
+ })
18
+
19
+ InlineProgress.propTypes = {
20
+ dots: PropTypes.number
16
21
  }
@@ -1,35 +1,35 @@
1
- import React, {useMemo, useRef} from 'react'
2
- import {QRCodeCanvas} from 'qrcode.react'
3
-
4
- /**
5
- * QrCode renderer
6
- * @param {String} value - Value to encode
7
- * @param {String} [caption] - Additional caption under QR code
8
- * @param {Number} [size] - Width|height fo the rendered QR code image
9
- * @param {String} [embeddedImage] - Optional logo to render in the center of QR code
10
- * @param {Number} [embeddedSize] - Embedded logo size (by default 10% of QR code size)
11
- * @return {JSX.Element}
12
- */
13
- export const QrCode = React.memo(function QrCode({value, caption, size = 320, embeddedImage, embeddedSize}) {
14
- const foreground = useMemo(() => getComputedStyle(document.documentElement).getPropertyValue('--color-primary'))
15
- const containerRef = useRef()
16
- return <div className="text-center" ref={containerRef}>
17
- <QRCodeCanvas value={value} size={256} level="Q" includeMargin imageSettings={embedImage(embeddedImage, embeddedSize, size)}
18
- fgColor={foreground} style={{width: size + 'px', height: size + 'px', display: 'block', margin: 'auto'}}/>
19
- {!!caption && <div className="text-small dimmed condensed word-break">{caption}</div>}
20
- </div>
21
- })
22
-
23
- function embedImage(src, size, qrSize) {
24
- if (!src)
25
- return undefined
26
- if (!size) {
27
- size = qrSize * 0.1
28
- }
29
- return {
30
- src,
31
- height: size,
32
- width: size,
33
- excavate: true
34
- }
1
+ import React, {useMemo, useRef} from 'react'
2
+ import {QRCodeCanvas} from 'qrcode.react'
3
+
4
+ /**
5
+ * QrCode renderer
6
+ * @param {string} value - Value to encode
7
+ * @param {string} [caption] - Additional caption under QR code
8
+ * @param {number} [size] - Width|height fo the rendered QR code image
9
+ * @param {string} [embeddedImage] - Optional logo to render in the center of QR code
10
+ * @param {number} [embeddedSize] - Embedded logo size (by default 10% of QR code size)
11
+ * @return {JSX.Element}
12
+ */
13
+ export const QrCode = React.memo(function QrCode({value, caption, size = 320, embeddedImage, embeddedSize}) {
14
+ const foreground = useMemo(() => getComputedStyle(document.documentElement).getPropertyValue('--color-primary'))
15
+ const containerRef = useRef()
16
+ return <div className="text-center" ref={containerRef}>
17
+ <QRCodeCanvas value={value} size={256} level="Q" includeMargin imageSettings={embedImage(embeddedImage, embeddedSize, size)}
18
+ fgColor={foreground} style={{width: size + 'px', height: size + 'px', display: 'block', margin: 'auto'}}/>
19
+ {!!caption && <div className="text-small dimmed condensed word-break">{caption}</div>}
20
+ </div>
21
+ })
22
+
23
+ function embedImage(src, size, qrSize) {
24
+ if (!src)
25
+ return undefined
26
+ if (!size) {
27
+ size = qrSize * 0.1
28
+ }
29
+ return {
30
+ src,
31
+ height: size,
32
+ width: size,
33
+ excavate: true
34
+ }
35
35
  }
@@ -1,21 +1,21 @@
1
- import {useState, useEffect} from 'react'
2
- import {throttle} from 'throttle-debounce'
3
-
4
- /**
5
- * Measures window client width
6
- * @return {Number}
7
- */
8
- export function useWindowWidth() {
9
- const [width, setWidth] = useState(window.innerWidth)
10
-
11
- const onResize = throttle(100, function () {
12
- setWidth(window.innerWidth)
13
- })
14
-
15
- useEffect(() => {
16
- window.addEventListener('resize', onResize)
17
- return () => window.removeEventListener('resize', onResize)
18
- }, [])
19
-
20
- return width
1
+ import {useState, useEffect} from 'react'
2
+ import {throttle} from 'throttle-debounce'
3
+
4
+ /**
5
+ * Measures window client width
6
+ * @return {number}
7
+ */
8
+ export function useWindowWidth() {
9
+ const [width, setWidth] = useState(window.innerWidth)
10
+
11
+ const onResize = throttle(100, function () {
12
+ setWidth(window.innerWidth)
13
+ })
14
+
15
+ useEffect(() => {
16
+ window.addEventListener('resize', onResize)
17
+ return () => window.removeEventListener('resize', onResize)
18
+ }, [])
19
+
20
+ return width
21
21
  }