@stellar-expert/ui-framework 1.16.7 → 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 (92) 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/basic-styles/base.scss +50 -50
  20. package/basic-styles/grid.scss +1 -1
  21. package/basic-styles/table.scss +1 -1
  22. package/claimable-balance/claimable-balance-claimants.js +5 -0
  23. package/contract/contract-api.js +15 -0
  24. package/contract/invocation-info-view.js +10 -2
  25. package/contract/sc-val.js +24 -0
  26. package/controls/button-group.js +25 -19
  27. package/controls/button-group.scss +46 -46
  28. package/controls/button.js +93 -78
  29. package/controls/button.scss +173 -173
  30. package/controls/code-block.js +42 -34
  31. package/controls/code-block.scss +71 -71
  32. package/controls/dropdown.js +318 -287
  33. package/controls/dropdown.scss +159 -159
  34. package/controls/external-link.js +10 -4
  35. package/controls/info-tooltip.js +23 -16
  36. package/controls/slider.js +29 -19
  37. package/controls/tabs.js +94 -94
  38. package/controls/tabs.scss +70 -70
  39. package/controls/tooltip.js +244 -240
  40. package/controls/tooltip.scss +116 -116
  41. package/controls/update-highlighter.js +32 -27
  42. package/controls/update-highlighter.scss +7 -7
  43. package/date/date-selector.js +56 -54
  44. package/date/elapsed-time.js +28 -21
  45. package/dex/price-dynamic.js +53 -44
  46. package/dex/price-dynamic.scss +33 -33
  47. package/directory/directory-hooks.js +109 -97
  48. package/effect/effect-description.js +5 -3
  49. package/errors/error-boundary.js +110 -97
  50. package/horizon/horizon-account-helpers.js +104 -104
  51. package/horizon/horizon-ledger-helpers.js +35 -35
  52. package/horizon/horizon-trades-helper.js +88 -88
  53. package/horizon/horizon-transaction-helpers.js +36 -36
  54. package/index.d.ts +1241 -0
  55. package/interaction/accordion.js +43 -35
  56. package/interaction/autofocus.js +13 -9
  57. package/interaction/block-select.js +64 -53
  58. package/interaction/block-select.scss +21 -21
  59. package/interaction/copy-to-clipboard.js +25 -18
  60. package/interaction/inline-progress.js +20 -15
  61. package/interaction/qr-code.js +34 -34
  62. package/interaction/responsive.js +20 -20
  63. package/interaction/spoiler.js +52 -39
  64. package/interaction/spoiler.scss +6 -6
  65. package/interaction/theme-selector.js +13 -10
  66. package/ledger/ledger-entry-href-formatter.js +4 -3
  67. package/ledger/ledger-entry-link.js +93 -58
  68. package/ledger/ledger-info-parser.js +28 -0
  69. package/meta/page-meta-tags.js +243 -238
  70. package/module/dynamic-module.js +47 -47
  71. package/package.json +3 -2
  72. package/state/on-screen-hooks.js +22 -22
  73. package/state/page-visibility-helpers.js +29 -16
  74. package/state/page-visibility-hooks.js +13 -11
  75. package/state/screen-orientation-hooks.js +19 -15
  76. package/state/state-hooks.js +76 -76
  77. package/state/stellar-network-hooks.js +56 -44
  78. package/state/theme.js +29 -28
  79. package/stellar/key-type.js +92 -91
  80. package/stellar/ledger-generic-id.js +39 -39
  81. package/stellar/signature-hint-utils.js +65 -65
  82. package/toast/toast-notifications-block.js +59 -59
  83. package/toast/toast-notifications.scss +1 -1
  84. package/tx/op-description-view.js +84 -81
  85. package/tx/op-icon.js +98 -98
  86. package/tx/parser/op-balance-changes.js +66 -66
  87. package/tx/parser/op-descriptor.js +51 -48
  88. package/tx/parser/tx-details-parser.js +81 -81
  89. package/tx/parser/tx-matcher.js +371 -371
  90. package/tx/parser/type-filter-matcher.js +126 -126
  91. package/tx/tx-list-hooks.js +32 -18
  92. package/tx/tx-operations-list.js +117 -116
@@ -1,117 +1,117 @@
1
- $tooltip-notch-shadow-color: var(--color-border-shadow);
2
-
3
- .tooltip-wrapper {
4
- width: 40rem;
5
- max-width: Min(40rem, 60vw);
6
- margin: 0;
7
- padding: .8rem;
8
- position: absolute;
9
- visibility: hidden;
10
- opacity: 0;
11
- transition: opacity 0.15s ease 0.4s, visibility 0.15s ease 0.4s;
12
- z-index: 10;
13
- background: transparent;
14
- border: none;
15
-
16
- &:popover-open {
17
- visibility: visible;
18
- opacity: 1;
19
- }
20
- }
21
-
22
- .tooltip {
23
- position: relative;
24
- font-size: 0.9*$font-size-base;
25
- font-style: normal;
26
- line-height: 1.3;
27
- background: var(--color-bg);
28
- border-color: var(--color-contrast-border);
29
- border-radius: $border-radius-input;
30
- box-shadow: 0 1px 6px 2px var(--color-backdrop);
31
- padding: 1rem 1.4rem;
32
- letter-spacing: normal;
33
- word-break: normal;
34
- visibility: hidden;
35
-
36
- &:before {
37
- content: "";
38
- background: var(--color-bg);
39
- height: .8rem;
40
- width: .8rem;
41
- position: absolute;
42
- z-index: 9;
43
- transform: rotate(45deg);
44
- }
45
-
46
- &.top:before {
47
- left: 50%;
48
- bottom: -.2em;
49
- box-shadow: 1px 1px 0 $tooltip-notch-shadow-color;
50
- margin-left: -0.26rem;
51
- }
52
-
53
- &.bottom:before {
54
- left: 50%;
55
- top: -.2em;
56
- box-shadow: -1px -1px 0 $tooltip-notch-shadow-color;
57
- margin-left: -0.26rem;
58
- }
59
-
60
- &.left:before {
61
- right: -.2em;
62
- top: 50%;
63
- margin-top: -0.26em;
64
- box-shadow: 1px -1px 0 $tooltip-notch-shadow-color;
65
- }
66
-
67
- &.right:before {
68
- left: -.2em;
69
- top: 50%;
70
- margin-top: -0.26em;
71
- box-shadow: -1px 1px 0 $tooltip-notch-shadow-color;
72
- }
73
-
74
- .tooltip-content {
75
- color: var(--color-text);
76
- z-index: 5;
77
- position: relative;
78
- }
79
-
80
- &.visible {
81
- visibility: visible;
82
- }
83
- }
84
-
85
- .trigger {
86
- position: absolute;
87
- font-size: 1.2rem;
88
- margin-top: -.3rem;
89
- margin-left: .1rem;
90
- margin-right: .1rem;
91
- color: var(--color-primary);
92
-
93
- + .trigger {
94
- margin-left: 1em;
95
- }
96
-
97
- &:before {
98
- opacity: 0.4;
99
- }
100
-
101
- &:after {
102
- content: '';
103
- position: absolute;
104
- opacity: 0.01;
105
- display: block;
106
- width: 2em;
107
- height: 2em;
108
- left: -0.4em;
109
- top: -0.2em;
110
- }
111
-
112
- &:hover {
113
- &:before {
114
- opacity: 1;
115
- }
116
- }
1
+ $tooltip-notch-shadow-color: var(--color-border-shadow);
2
+
3
+ .tooltip-wrapper {
4
+ width: 40rem;
5
+ max-width: Min(40rem, 60vw);
6
+ margin: 0;
7
+ padding: .8rem;
8
+ position: absolute;
9
+ visibility: hidden;
10
+ opacity: 0;
11
+ transition: opacity 0.15s ease 0.4s, visibility 0.15s ease 0.4s;
12
+ z-index: 10;
13
+ background: transparent;
14
+ border: none;
15
+
16
+ &:popover-open {
17
+ visibility: visible;
18
+ opacity: 1;
19
+ }
20
+ }
21
+
22
+ .tooltip {
23
+ position: relative;
24
+ font-size: 0.9*$font-size-base;
25
+ font-style: normal;
26
+ line-height: 1.3;
27
+ background: var(--color-bg);
28
+ border-color: var(--color-contrast-border);
29
+ border-radius: $border-radius-input;
30
+ box-shadow: 0 1px 6px 2px var(--color-backdrop);
31
+ padding: 1rem 1.4rem;
32
+ letter-spacing: normal;
33
+ word-break: normal;
34
+ visibility: hidden;
35
+
36
+ &:before {
37
+ content: "";
38
+ background: var(--color-bg);
39
+ height: .8rem;
40
+ width: .8rem;
41
+ position: absolute;
42
+ z-index: 9;
43
+ transform: rotate(45deg);
44
+ }
45
+
46
+ &.top:before {
47
+ left: 50%;
48
+ bottom: -.2em;
49
+ box-shadow: 1px 1px 0 $tooltip-notch-shadow-color;
50
+ margin-left: -0.26rem;
51
+ }
52
+
53
+ &.bottom:before {
54
+ left: 50%;
55
+ top: -.2em;
56
+ box-shadow: -1px -1px 0 $tooltip-notch-shadow-color;
57
+ margin-left: -0.26rem;
58
+ }
59
+
60
+ &.left:before {
61
+ right: -.2em;
62
+ top: 50%;
63
+ margin-top: -0.26em;
64
+ box-shadow: 1px -1px 0 $tooltip-notch-shadow-color;
65
+ }
66
+
67
+ &.right:before {
68
+ left: -.2em;
69
+ top: 50%;
70
+ margin-top: -0.26em;
71
+ box-shadow: -1px 1px 0 $tooltip-notch-shadow-color;
72
+ }
73
+
74
+ .tooltip-content {
75
+ color: var(--color-text);
76
+ z-index: 5;
77
+ position: relative;
78
+ }
79
+
80
+ &.visible {
81
+ visibility: visible;
82
+ }
83
+ }
84
+
85
+ .trigger {
86
+ position: absolute;
87
+ font-size: 1.2rem;
88
+ margin-top: -.3rem;
89
+ margin-left: .1rem;
90
+ margin-right: .1rem;
91
+ color: var(--color-primary);
92
+
93
+ + .trigger {
94
+ margin-left: 1em;
95
+ }
96
+
97
+ &:before {
98
+ opacity: 0.4;
99
+ }
100
+
101
+ &:after {
102
+ content: '';
103
+ position: absolute;
104
+ opacity: 0.01;
105
+ display: block;
106
+ width: 2em;
107
+ height: 2em;
108
+ left: -0.4em;
109
+ top: -0.2em;
110
+ }
111
+
112
+ &:hover {
113
+ &:before {
114
+ opacity: 1;
115
+ }
116
+ }
117
117
  }
@@ -1,28 +1,33 @@
1
- import React, {useRef} from 'react'
2
- import PropTypes from 'prop-types'
3
- import cn from 'classnames'
4
- import {useDependantState} from '../state/state-hooks'
5
- import './update-highlighter.scss'
6
-
7
- export const UpdateHighlighter = React.memo(function UpdateHighlighter({children}) {
8
- const timerRef = useRef(0)
9
- const [active, setActiveState] = useDependantState(() => {
10
- //reset the timer in case if previous animation wasn't finished yet
11
- if (timerRef.current) {
12
- clearTimeout(timerRef.current)
13
- useRef.current = 0
14
- }
15
- //schedule class reset
16
- timerRef.current = setTimeout(function () {
17
- timerRef.current = 0
18
- setActiveState(false)
19
- }, 600)
20
- return true
21
- }, [children])
22
-
23
- return <span className={cn({highlighter: active})}>{children}</span>
24
- })
25
-
26
- UpdateHighlighter.propTypes = {
27
- children: PropTypes.any.isRequired
1
+ import React, {useRef} from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import cn from 'classnames'
4
+ import {useDependantState} from '../state/state-hooks'
5
+ import './update-highlighter.scss'
6
+
7
+ /**
8
+ * Briefly highlights its content with an animation when children change
9
+ * @param {Object} props
10
+ * @param {*} props.children - Content to monitor and highlight on update
11
+ */
12
+ export const UpdateHighlighter = React.memo(function UpdateHighlighter({children}) {
13
+ const timerRef = useRef(0)
14
+ const [active, setActiveState] = useDependantState(() => {
15
+ //reset the timer in case if previous animation wasn't finished yet
16
+ if (timerRef.current) {
17
+ clearTimeout(timerRef.current)
18
+ useRef.current = 0
19
+ }
20
+ //schedule class reset
21
+ timerRef.current = setTimeout(function () {
22
+ timerRef.current = 0
23
+ setActiveState(false)
24
+ }, 600)
25
+ return true
26
+ }, [children])
27
+
28
+ return <span className={cn({highlighter: active})}>{children}</span>
29
+ })
30
+
31
+ UpdateHighlighter.propTypes = {
32
+ children: PropTypes.any.isRequired
28
33
  }
@@ -1,8 +1,8 @@
1
- .highlighter {
2
- animation: highlighter 0.6s ease-in;
3
- }
4
-
5
- @keyframes highlighter {
6
- from {background-color: transparentize($color-primary, 0.5);}
7
- to {background-color: transparent;}
1
+ .highlighter {
2
+ animation: highlighter 0.6s ease-in;
3
+ }
4
+
5
+ @keyframes highlighter {
6
+ from {background-color: rgba($color-primary, 0.5);}
7
+ to {background-color: transparent;}
8
8
  }
@@ -1,55 +1,57 @@
1
- import React, {useCallback, useEffect, useState} from 'react'
2
- import {debounce} from 'throttle-debounce'
3
- import {normalizeDate, toUnixTimestamp} from '@stellar-expert/formatter'
4
-
5
- /**
6
- * @param {String} value - Current input value
7
- * @param {DateSelector~OnChange} onChange - Onchange event handler
8
- * @param {String} [min] - Minimum allowed date
9
- * @param {String} [max] - Maximum allowed date
10
- * @param {*} [ref]
11
- */
12
- export function DateSelector({value, onChange, min, max, ref, ...otherProps}) {
13
- const [date, setDate] = useState(value ? trimIsoDateSeconds(normalizeDate(value)) : '')
14
- useEffect(() => {
15
- if (value) {
16
- setDate(trimIsoDateSeconds(normalizeDate(value)))
17
- } else {
18
- setDate('')
19
- }
20
- }, [value])
21
-
22
- const selectDate = useCallback(debounce(400, function (newDate) {
23
- if (value !== newDate) {
24
- setDate(newDate)
25
- if (onChange) {
26
- onChange(newDate ? toUnixTimestamp(normalizeDate(newDate)) : null)
27
- }
28
- }
29
- }), [onChange, value])
30
-
31
- if (max === undefined) {
32
- max = trimIsoDateSeconds(new Date(new Date().getTime() + 24 * 60 * 60 * 1000))
33
- }
34
- return <input type="datetime-local" value={date} className="date-selector condensed" step={60} ref={ref}
35
- min={min || minSelectableValue} max={max} onChange={e => selectDate(e.target.value)}
36
- style={{width: '11em', overflow: 'hidden'}} {...otherProps}/>
37
- }
38
-
39
- /**
40
- * @param {Date|Number} date
41
- * @return {String}
42
- */
43
- export function trimIsoDateSeconds(date) {
44
- if (typeof date === 'number') {
45
- date = new Date(date)
46
- }
47
- return date.toISOString().replace(/:\d{2}\.\d*Z/, '')
48
- }
49
-
50
- const minSelectableValue = trimIsoDateSeconds(new Date('2015-09-30T16:46:00Z'))
51
-
52
- /**
53
- * @callback DateSelector~OnChange
54
- * @param {number|null} value - Selected value represented as a Unix timestamp or null for invalid date value
1
+ import React, {useCallback, useEffect, useState} from 'react'
2
+ import {debounce} from 'throttle-debounce'
3
+ import {normalizeDate, toUnixTimestamp} from '@stellar-expert/formatter'
4
+
5
+ /**
6
+ * Date-time picker input
7
+ * @param {string} value - Current input value
8
+ * @param {DateSelector~OnChange} onChange - Onchange event handler
9
+ * @param {string} [min] - Minimum allowed date
10
+ * @param {string} [max] - Maximum allowed date
11
+ * @param {*} [ref]
12
+ */
13
+ export function DateSelector({value, onChange, min, max, ref, ...otherProps}) {
14
+ const [date, setDate] = useState(value ? trimIsoDateSeconds(normalizeDate(value)) : '')
15
+ useEffect(() => {
16
+ if (value) {
17
+ setDate(trimIsoDateSeconds(normalizeDate(value)))
18
+ } else {
19
+ setDate('')
20
+ }
21
+ }, [value])
22
+
23
+ const selectDate = useCallback(debounce(400, function (newDate) {
24
+ if (value !== newDate) {
25
+ setDate(newDate)
26
+ if (onChange) {
27
+ onChange(newDate ? toUnixTimestamp(normalizeDate(newDate)) : null)
28
+ }
29
+ }
30
+ }), [onChange, value])
31
+
32
+ if (max === undefined) {
33
+ max = trimIsoDateSeconds(new Date(new Date().getTime() + 24 * 60 * 60 * 1000))
34
+ }
35
+ return <input type="datetime-local" value={date} className="date-selector condensed" step={60} ref={ref}
36
+ min={min || minSelectableValue} max={max} onChange={e => selectDate(e.target.value)}
37
+ style={{width: '11em', overflow: 'hidden'}} {...otherProps}/>
38
+ }
39
+
40
+ /**
41
+ * Trim seconds and milliseconds for basic ISO date format representation
42
+ * @param {Date|number} date
43
+ * @return {string}
44
+ */
45
+ export function trimIsoDateSeconds(date) {
46
+ if (typeof date === 'number') {
47
+ date = new Date(date)
48
+ }
49
+ return date.toISOString().replace(/:\d{2}\.\d*Z/, '')
50
+ }
51
+
52
+ const minSelectableValue = trimIsoDateSeconds(new Date('2015-09-30T16:46:00Z'))
53
+
54
+ /**
55
+ * @callback DateSelector~OnChange
56
+ * @param {number|null} value - Selected value represented as a Unix timestamp or null for invalid date value
55
57
  */
@@ -1,22 +1,29 @@
1
- import React from 'react'
2
- import TimeAgo from 'react-timeago'
3
-
4
- const timeUnits = {
5
- second: 's',
6
- minute: 'm',
7
- hour: 'h',
8
- day: 'd',
9
- week: 'w',
10
- month: 'mo',
11
- year: 'y'
12
- }
13
-
14
- export const ElapsedTime = React.memo(function ElapsedTime({ts, className, suffix}) {
15
- const then = Date.parse(ts)
16
- return <span className={className}>
17
- <TimeAgo date={ts} formatter={(v, unit) => `${v}${timeUnits[unit]}`} now={function () {
18
- const now = Date.now()
19
- return then > now ? then : now
20
- }}/>{suffix}
21
- </span>
1
+ import React from 'react'
2
+ import TimeAgo from 'react-timeago'
3
+
4
+ const timeUnits = {
5
+ second: 's',
6
+ minute: 'm',
7
+ hour: 'h',
8
+ day: 'd',
9
+ week: 'w',
10
+ month: 'mo',
11
+ year: 'y'
12
+ }
13
+
14
+ /**
15
+ * Displays relative elapsed time since a given timestamp (e.g., "3m ago")
16
+ * @param {Object} props
17
+ * @param {Date|string|number} props.ts - Timestamp to measure elapsed time from
18
+ * @param {string} [props.className] - Additional CSS classes
19
+ * @param {string} [props.suffix] - Text appended after the time (e.g., " ago")
20
+ */
21
+ export const ElapsedTime = React.memo(function ElapsedTime({ts, className, suffix}) {
22
+ const then = Date.parse(ts)
23
+ return <span className={className}>
24
+ <TimeAgo date={ts} formatter={(v, unit) => `${v}${timeUnits[unit]}`} now={function () {
25
+ const now = Date.now()
26
+ return then > now ? then : now
27
+ }}/>{suffix}
28
+ </span>
22
29
  })
@@ -1,45 +1,54 @@
1
- import React from 'react'
2
- import PropTypes from 'prop-types'
3
- import cn from 'classnames'
4
- import {formatPrice} from '@stellar-expert/formatter'
5
- import './price-dynamic.scss'
6
-
7
- export const PriceDynamic = React.memo(function PriceDynamic({change, current, prev, standalone, allowZero}) {
8
- if (change === undefined) {
9
- if (current === prev || !prev || !current) {
10
- change = 0
11
- } else {
12
- change = 100 * (current - prev) / prev
13
- }
14
- }
15
- if (Math.abs(change) > 10000)
16
- return null
17
- change = formatPrice(Math.abs(change), 2) + '%'
18
- if (change === '0%' && !allowZero)
19
- return null
20
- let direction
21
- if (parseInt(change) > 0) {
22
- direction = 'positive'
23
- }
24
- if (parseInt(change) < 0) {
25
- direction = 'negative'
26
- }
27
- const className = cn('price-change', getChangeDirection(change), {standalone})
28
- return <span className={className} aria-label={` (${change})`}>{change}</span>
29
- })
30
-
31
- function getChangeDirection(change) {
32
- change = parseInt(change, 10)
33
- if (change > 0)
34
- return 'positive'
35
- if (change < 0)
36
- return 'negative'
37
- }
38
-
39
- PriceDynamic.propTypes = {
40
- change: PropTypes.number,
41
- current: PropTypes.number,
42
- prev: PropTypes.number,
43
- standalone: PropTypes.bool,
44
- allowZero: PropTypes.bool
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import cn from 'classnames'
4
+ import {formatPrice} from '@stellar-expert/formatter'
5
+ import './price-dynamic.scss'
6
+
7
+ /**
8
+ * Displays a price change percentage with positive/negative styling
9
+ * @param {Object} props
10
+ * @param {number} [props.change] - Pre-calculated change percentage; auto-calculated from current/prev if omitted
11
+ * @param {number} [props.current] - Current price value (used to calculate change)
12
+ * @param {number} [props.prev] - Previous price value (used to calculate change)
13
+ * @param {boolean} [props.standalone] - Apply standalone styling
14
+ * @param {boolean} [props.allowZero] - Show "0%" instead of returning null for zero change
15
+ */
16
+ export const PriceDynamic = React.memo(function PriceDynamic({change, current, prev, standalone, allowZero}) {
17
+ if (change === undefined) {
18
+ if (current === prev || !prev || !current) {
19
+ change = 0
20
+ } else {
21
+ change = 100 * (current - prev) / prev
22
+ }
23
+ }
24
+ if (Math.abs(change) > 10000)
25
+ return null
26
+ change = formatPrice(Math.abs(change), 2) + '%'
27
+ if (change === '0%' && !allowZero)
28
+ return null
29
+ let direction
30
+ if (parseInt(change) > 0) {
31
+ direction = 'positive'
32
+ }
33
+ if (parseInt(change) < 0) {
34
+ direction = 'negative'
35
+ }
36
+ const className = cn('price-change', getChangeDirection(change), {standalone})
37
+ return <span className={className} aria-label={` (${change})`}>{change}</span>
38
+ })
39
+
40
+ function getChangeDirection(change) {
41
+ change = parseInt(change, 10)
42
+ if (change > 0)
43
+ return 'positive'
44
+ if (change < 0)
45
+ return 'negative'
46
+ }
47
+
48
+ PriceDynamic.propTypes = {
49
+ change: PropTypes.number,
50
+ current: PropTypes.number,
51
+ prev: PropTypes.number,
52
+ standalone: PropTypes.bool,
53
+ allowZero: PropTypes.bool
45
54
  }
@@ -1,34 +1,34 @@
1
- .price-change {
2
- vertical-align: super;
3
- line-height: 1;
4
- font-size: 0.8em;
5
- margin-right: -0.2em;
6
-
7
- &:before {
8
- font-size: .8em;
9
- vertical-align: bottom;
10
- padding: 0 .1em;
11
- line-height: 2.2;
12
- }
13
-
14
- &.positive {
15
- color: var(--color-price-up);
16
-
17
- &:before {
18
- content: '\2191';
19
- }
20
- }
21
-
22
- &.negative {
23
- color: var(--color-price-down);
24
-
25
- &:before {
26
- content: '\2193';
27
- }
28
- }
29
-
30
- &.standalone {
31
- vertical-align: middle;
32
- font-size: 0.9em;
33
- }
1
+ .price-change {
2
+ vertical-align: super;
3
+ line-height: 1;
4
+ font-size: 0.8em;
5
+ margin-right: -0.2em;
6
+
7
+ &:before {
8
+ font-size: .8em;
9
+ vertical-align: bottom;
10
+ padding: 0 .1em;
11
+ line-height: 2.2;
12
+ }
13
+
14
+ &.positive {
15
+ color: var(--color-price-up);
16
+
17
+ &:before {
18
+ content: '\2191';
19
+ }
20
+ }
21
+
22
+ &.negative {
23
+ color: var(--color-price-down);
24
+
25
+ &:before {
26
+ content: '\2193';
27
+ }
28
+ }
29
+
30
+ &.standalone {
31
+ vertical-align: middle;
32
+ font-size: 0.9em;
33
+ }
34
34
  }