@stellar-expert/ui-framework 1.9.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/.npmrc +1 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/account/account-address.js +127 -0
- package/account/account-address.scss +20 -0
- package/account/available-balance.js +21 -0
- package/account/identicon.js +91 -0
- package/account/identicon.scss +6 -0
- package/account/signer-key.js +65 -0
- package/api/api-cache.js +5 -0
- package/api/explorer-api-call.js +37 -0
- package/api/explorer-api-hooks.js +202 -0
- package/api/explorer-api-paginated-list-hooks.js +439 -0
- package/api/explorer-batch-info-loader.js +85 -0
- package/api/explorer-tx-api.js +29 -0
- package/asset/amount.js +53 -0
- package/asset/asset-icon.js +34 -0
- package/asset/asset-issuer.js +22 -0
- package/asset/asset-link.js +93 -0
- package/asset/asset-link.scss +26 -0
- package/asset/asset-list-hooks.js +60 -0
- package/asset/asset-meta-hooks.js +78 -0
- package/asset/asset-selector.js +72 -0
- package/asset/asset-selector.scss +41 -0
- package/basic-styles/base.scss +53 -0
- package/basic-styles/form.scss +90 -0
- package/basic-styles/grid.scss +388 -0
- package/basic-styles/link.scss +17 -0
- package/basic-styles/lists.scss +68 -0
- package/basic-styles/loader.scss +22 -0
- package/basic-styles/responsive.scss +29 -0
- package/basic-styles/scrollbars.scss +19 -0
- package/basic-styles/spacing.scss +50 -0
- package/basic-styles/table.scss +104 -0
- package/basic-styles/themes.scss +59 -0
- package/basic-styles/typography.scss +191 -0
- package/basic-styles/variables.scss +26 -0
- package/claimable-balance/claimable-balance-claimants.js +12 -0
- package/contract/sc-val.js +70 -0
- package/contract/wasm-section-parser.js +159 -0
- package/contract/wasm-section-reader.js +79 -0
- package/contract/xdr-reader.js +148 -0
- package/controls/active-icon.scss +23 -0
- package/controls/button-group.js +20 -0
- package/controls/button-group.scss +48 -0
- package/controls/button.js +74 -0
- package/controls/button.scss +148 -0
- package/controls/code-block.js +35 -0
- package/controls/code-block.scss +74 -0
- package/controls/dropdown.js +281 -0
- package/controls/dropdown.scss +161 -0
- package/controls/external-link.js +5 -0
- package/controls/info-tooltip.js +17 -0
- package/controls/info-tooltip.scss +4 -0
- package/controls/slider.js +20 -0
- package/controls/slider.scss +22 -0
- package/controls/tabs.js +94 -0
- package/controls/tabs.scss +73 -0
- package/controls/tooltip.js +214 -0
- package/controls/tooltip.scss +97 -0
- package/controls/update-highlighter.js +28 -0
- package/controls/update-highlighter.scss +10 -0
- package/date/date-selector.js +44 -0
- package/date/elapsed-time.js +22 -0
- package/date/utc-timestamp.js +23 -0
- package/dex/price-dynamic.js +45 -0
- package/dex/price-dynamic.scss +36 -0
- package/directory/directory-hooks.js +89 -0
- package/effect/effect-description.js +289 -0
- package/effect/op-effects-view.js +11 -0
- package/effect/op-effects.scss +8 -0
- package/errors/error-boundary.js +98 -0
- package/fonts/font.scss +23 -0
- package/fonts/icons/config.json +1858 -0
- package/fonts/icons/icons-embedded.scss +644 -0
- package/horizon/horizon-account-helpers.js +104 -0
- package/horizon/horizon-client-helpers.js +52 -0
- package/horizon/horizon-ledger-helpers.js +36 -0
- package/horizon/horizon-orderbook-helpers.js +14 -0
- package/horizon/horizon-trades-helper.js +89 -0
- package/horizon/horizon-transaction-helpers.js +36 -0
- package/index.js +85 -0
- package/index.scss +16 -0
- package/interaction/autofocus.js +9 -0
- package/interaction/block-select.js +54 -0
- package/interaction/block-select.scss +24 -0
- package/interaction/copy-to-clipboard.js +19 -0
- package/interaction/inline-progress.js +16 -0
- package/interaction/qr-code.js +45 -0
- package/interaction/responsive.js +21 -0
- package/interaction/spoiler.js +40 -0
- package/interaction/spoiler.scss +9 -0
- package/interaction/theme-selector.js +11 -0
- package/ledger/ledger-entry-href-formatter.js +22 -0
- package/ledger/ledger-entry-link.js +59 -0
- package/meta/page-meta-tags.js +229 -0
- package/module/dynamic-module.js +48 -0
- package/package.json +41 -0
- package/state/on-screen-hooks.js +23 -0
- package/state/page-visibility-helpers.js +17 -0
- package/state/page-visibility-hooks.js +12 -0
- package/state/screen-orientation-hooks.js +16 -0
- package/state/state-hooks.js +77 -0
- package/state/stellar-network-hooks.js +45 -0
- package/state/theme.js +29 -0
- package/stellar/key-type.js +92 -0
- package/stellar/ledger-generic-id.js +40 -0
- package/stellar/signature-hint-utils.js +65 -0
- package/toast/toast-notification-instance.js +43 -0
- package/toast/toast-notification.js +46 -0
- package/toast/toast-notifications-block.js +55 -0
- package/toast/toast-notifications.scss +166 -0
- package/tx/op-accounting-changes.js +27 -0
- package/tx/op-description-view.js +925 -0
- package/tx/op-description.scss +98 -0
- package/tx/op-icon.js +93 -0
- package/tx/parser/op-balance-changes.js +62 -0
- package/tx/parser/op-descriptor.js +49 -0
- package/tx/parser/tx-details-parser.js +75 -0
- package/tx/parser/tx-matcher.js +372 -0
- package/tx/parser/type-filter-matcher.js +127 -0
- package/tx/tx-fee-effect.js +14 -0
- package/tx/tx-list-hooks.js +19 -0
- package/tx/tx-operations-list.js +105 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
export class XdrReader {
|
|
2
|
+
/**
|
|
3
|
+
* @constructor
|
|
4
|
+
* @param {Buffer} source - Buffer containing serialized data
|
|
5
|
+
*/
|
|
6
|
+
constructor(source) {
|
|
7
|
+
if (!Buffer.isBuffer(source)) {
|
|
8
|
+
if (source instanceof Array) {
|
|
9
|
+
source = Buffer.from(source)
|
|
10
|
+
} else
|
|
11
|
+
throw new Error('Source not specified')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
this._buffer = source
|
|
15
|
+
this._length = source.length
|
|
16
|
+
this._index = 0
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @type {Buffer}
|
|
21
|
+
* @private
|
|
22
|
+
* @readonly
|
|
23
|
+
*/
|
|
24
|
+
_buffer
|
|
25
|
+
/**
|
|
26
|
+
* @type {Number}
|
|
27
|
+
* @private
|
|
28
|
+
* @readonly
|
|
29
|
+
*/
|
|
30
|
+
_length
|
|
31
|
+
/**
|
|
32
|
+
* @type {Number}
|
|
33
|
+
* @private
|
|
34
|
+
* @readonly
|
|
35
|
+
*/
|
|
36
|
+
_index
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Check if the reader reached the end of the input buffer
|
|
40
|
+
* @return {Boolean}
|
|
41
|
+
*/
|
|
42
|
+
get eof() {
|
|
43
|
+
return this._index === this._length
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Advance reader position, check padding and overflow
|
|
48
|
+
* @param {Number} size - Bytes to read
|
|
49
|
+
* @return {Number} Position to read from
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
advance(size) {
|
|
53
|
+
const from = this._index
|
|
54
|
+
// advance cursor position
|
|
55
|
+
this._index += size
|
|
56
|
+
// check buffer boundaries
|
|
57
|
+
if (this._length < this._index)
|
|
58
|
+
throw new Error(
|
|
59
|
+
'attempt to read outside the boundary of the buffer'
|
|
60
|
+
)
|
|
61
|
+
// check that padding is correct for Opaque and String
|
|
62
|
+
const padding = 4 - (size % 4 || 4)
|
|
63
|
+
if (padding > 0) {
|
|
64
|
+
for (let i = 0; i < padding; i++)
|
|
65
|
+
if (this._buffer[this._index + i] !== 0)
|
|
66
|
+
// all bytes in the padding should be zeros
|
|
67
|
+
throw new Error('Invalid padding')
|
|
68
|
+
this._index += padding
|
|
69
|
+
}
|
|
70
|
+
return from
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Reset reader position
|
|
75
|
+
* @return {void}
|
|
76
|
+
*/
|
|
77
|
+
rewind() {
|
|
78
|
+
this._index = 0
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Read byte array from the buffer
|
|
83
|
+
* @param {Number} size - Bytes to read
|
|
84
|
+
* @return {Buffer} - Sliced portion of the underlying buffer
|
|
85
|
+
*/
|
|
86
|
+
read(size) {
|
|
87
|
+
const from = this.advance(size)
|
|
88
|
+
return this._buffer.subarray(from, from + size)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Read i32 from buffer
|
|
93
|
+
* @return {Number}
|
|
94
|
+
*/
|
|
95
|
+
readInt32BE() {
|
|
96
|
+
return this._buffer.readInt32BE(this.advance(4))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Read u32 from buffer
|
|
101
|
+
* @return {Number}
|
|
102
|
+
*/
|
|
103
|
+
readUInt32BE() {
|
|
104
|
+
return this._buffer.readUInt32BE(this.advance(4))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Read i64 from buffer
|
|
109
|
+
* @return {BigInt}
|
|
110
|
+
*/
|
|
111
|
+
readBigInt64BE() {
|
|
112
|
+
return this._buffer.readBigInt64BE(this.advance(8))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Read u64 from buffer
|
|
117
|
+
* @return {BigInt}
|
|
118
|
+
*/
|
|
119
|
+
readBigUInt64BE() {
|
|
120
|
+
return this._buffer.readBigUInt64BE(this.advance(8))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Read float from buffer
|
|
125
|
+
* @return {Number}
|
|
126
|
+
*/
|
|
127
|
+
readFloatBE() {
|
|
128
|
+
return this._buffer.readFloatBE(this.advance(4))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Read double from buffer
|
|
133
|
+
* @return {Number}
|
|
134
|
+
*/
|
|
135
|
+
readDoubleBE() {
|
|
136
|
+
return this._buffer.readDoubleBE(this.advance(8))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Ensure that input buffer has been consumed in full, otherwise it's a type mismatch
|
|
141
|
+
* @return {void}
|
|
142
|
+
* @throws {Error}
|
|
143
|
+
*/
|
|
144
|
+
ensureInputConsumed() {
|
|
145
|
+
if (this._index !== this._length)
|
|
146
|
+
throw new Error(`Invalid XDR contract typecast - source buffer not entirely consumed`)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.active-icon {
|
|
2
|
+
display: inline-block;
|
|
3
|
+
padding: 0 .3em;
|
|
4
|
+
position: relative;
|
|
5
|
+
|
|
6
|
+
&:active {
|
|
7
|
+
color: var(--color-bg);
|
|
8
|
+
outline: none;
|
|
9
|
+
|
|
10
|
+
&:after {
|
|
11
|
+
content: '';
|
|
12
|
+
display: block;
|
|
13
|
+
position: absolute;
|
|
14
|
+
top: -.1em;
|
|
15
|
+
left: .15em;
|
|
16
|
+
width: 1.5em;
|
|
17
|
+
height: 1.5em;
|
|
18
|
+
border-radius: 50%;
|
|
19
|
+
background: var(--color-highlight);
|
|
20
|
+
z-index: -1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import './button-group.scss'
|
|
4
|
+
|
|
5
|
+
export const ButtonGroup = React.memo(function ButtonGroup({inline, children, ...otherProps}) {
|
|
6
|
+
if (inline)
|
|
7
|
+
return <span className="button-group" {...otherProps}>{children}</span>
|
|
8
|
+
return <div className="button-group" {...otherProps}>{children}</div>
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
ButtonGroup.propTypes = {
|
|
12
|
+
/**
|
|
13
|
+
* Nested buttons
|
|
14
|
+
*/
|
|
15
|
+
children: PropTypes.any.isRequired,
|
|
16
|
+
/**
|
|
17
|
+
* Whether to render the group as inline element (span)
|
|
18
|
+
*/
|
|
19
|
+
inline: PropTypes.bool
|
|
20
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
@use "../basic-styles/variables";
|
|
2
|
+
@import "./button";
|
|
3
|
+
|
|
4
|
+
.button-group {
|
|
5
|
+
> * {
|
|
6
|
+
vertical-align: top;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
&:not(:last-child) {
|
|
10
|
+
margin-right: $button-spacing;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
& > button,
|
|
14
|
+
& > .button {
|
|
15
|
+
+ .button {
|
|
16
|
+
margin-left: -0.76em;
|
|
17
|
+
|
|
18
|
+
&.small {
|
|
19
|
+
margin-left: -0.96em;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&:before {
|
|
23
|
+
border-left: 2px solid var(--color-primary);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&.selected {
|
|
28
|
+
&.disabled,
|
|
29
|
+
&[disabled] {
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
color: var(--color-text);
|
|
32
|
+
opacity: 1;
|
|
33
|
+
|
|
34
|
+
&:before {
|
|
35
|
+
background: var(--color-primary);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&:not(:last-child) {;
|
|
41
|
+
margin-right: 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
& > :not(:last-child) > .button {
|
|
46
|
+
margin-right: 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import cn from 'classnames'
|
|
4
|
+
import './button.scss'
|
|
5
|
+
|
|
6
|
+
export const Button = React.memo(function Button({href, onClick, block, outline, clear, stackable, small, disabled, className, children, ...op}) {
|
|
7
|
+
const c = cn('button', {
|
|
8
|
+
small,
|
|
9
|
+
disabled,
|
|
10
|
+
'button-block': block,
|
|
11
|
+
'button-outline': outline,
|
|
12
|
+
'button-clear': clear,
|
|
13
|
+
stackable
|
|
14
|
+
}, className)
|
|
15
|
+
const props = {className: c, onClick, ...op}
|
|
16
|
+
if (href) {
|
|
17
|
+
props.onClick = function (e) {
|
|
18
|
+
e.preventDefault()
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
return <a href={href} {...props}>{children}</a>
|
|
22
|
+
}
|
|
23
|
+
if (disabled) {
|
|
24
|
+
props.disabled = true
|
|
25
|
+
}
|
|
26
|
+
return <button {...props}>{children}</button>
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
Button.propTypes = {
|
|
30
|
+
/**
|
|
31
|
+
* Button link - renders the button as A tag; if not set, BUTTON tag is rendered instead
|
|
32
|
+
*/
|
|
33
|
+
href: PropTypes.string,
|
|
34
|
+
/**
|
|
35
|
+
* Click handler
|
|
36
|
+
*/
|
|
37
|
+
onClick: PropTypes.func,
|
|
38
|
+
/**
|
|
39
|
+
* Whether to render the button as block element
|
|
40
|
+
*/
|
|
41
|
+
block: PropTypes.bool,
|
|
42
|
+
/**
|
|
43
|
+
* Render only a thin outline instead of the color-filled button
|
|
44
|
+
*/
|
|
45
|
+
outline: PropTypes.bool,
|
|
46
|
+
/**
|
|
47
|
+
* Do not render an outline - just the text
|
|
48
|
+
*/
|
|
49
|
+
clear: PropTypes.bool,
|
|
50
|
+
/**
|
|
51
|
+
* Whether buttons should look stackable on mobile devices
|
|
52
|
+
*/
|
|
53
|
+
stackable: PropTypes.bool,
|
|
54
|
+
/**
|
|
55
|
+
* Renders a small button
|
|
56
|
+
*/
|
|
57
|
+
small: PropTypes.bool,
|
|
58
|
+
/**
|
|
59
|
+
* Whether the button is currently disabled
|
|
60
|
+
*/
|
|
61
|
+
disabled: PropTypes.bool,
|
|
62
|
+
/**
|
|
63
|
+
* Externally provided CSS classes
|
|
64
|
+
*/
|
|
65
|
+
className: PropTypes.string,
|
|
66
|
+
/**
|
|
67
|
+
* Tooltip text
|
|
68
|
+
*/
|
|
69
|
+
title: PropTypes.string,
|
|
70
|
+
/**
|
|
71
|
+
* Text inside the button
|
|
72
|
+
*/
|
|
73
|
+
children: PropTypes.any.isRequired
|
|
74
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
@use "../basic-styles/variables";
|
|
2
|
+
|
|
3
|
+
$button-spacing: 0.5rem;
|
|
4
|
+
|
|
5
|
+
.button,
|
|
6
|
+
button {
|
|
7
|
+
border: none;
|
|
8
|
+
color: var(--color-bg);
|
|
9
|
+
background: none;
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
display: inline-block;
|
|
12
|
+
font-size: $font-size-base;
|
|
13
|
+
font-weight: 400;
|
|
14
|
+
font-family: $font-face-primary;
|
|
15
|
+
height: 2.4em;
|
|
16
|
+
min-width: 6em;
|
|
17
|
+
line-height: 2.4em;
|
|
18
|
+
padding: 0 1.4em;
|
|
19
|
+
text-align: center;
|
|
20
|
+
text-decoration: none;
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
margin-right: $button-spacing;
|
|
23
|
+
margin-bottom: 0.5em;
|
|
24
|
+
position: relative;
|
|
25
|
+
z-index: 0;
|
|
26
|
+
user-select: none;
|
|
27
|
+
|
|
28
|
+
&.button-block {
|
|
29
|
+
display: block;
|
|
30
|
+
width: 100%;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&:last-child {
|
|
34
|
+
margin-right: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.small {
|
|
38
|
+
font-size: 1.25rem;
|
|
39
|
+
padding: 0 1em;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&:before {
|
|
43
|
+
content: '';
|
|
44
|
+
display: block;
|
|
45
|
+
background: var(--color-highlight);
|
|
46
|
+
border: none;
|
|
47
|
+
position: absolute;
|
|
48
|
+
z-index: -1;
|
|
49
|
+
top: 0;
|
|
50
|
+
left: 6px;
|
|
51
|
+
width: calc(100% - 12px);
|
|
52
|
+
height: 100%;
|
|
53
|
+
transform: skew(-20deg);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
&:focus {
|
|
57
|
+
outline: 0;
|
|
58
|
+
background: none !important;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&:hover {
|
|
62
|
+
color: var(--color-bg);
|
|
63
|
+
&:before {
|
|
64
|
+
background: var(--color-primary);
|
|
65
|
+
border-color: var(--color-primary);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&:active {
|
|
70
|
+
&:before {
|
|
71
|
+
top: 1px;
|
|
72
|
+
left: 7px;
|
|
73
|
+
background: var(--color-primary);
|
|
74
|
+
border-color: var(--color-primary);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&[disabled],
|
|
79
|
+
&.disabled {
|
|
80
|
+
cursor: default !important;
|
|
81
|
+
opacity: 0.7;
|
|
82
|
+
|
|
83
|
+
&:hover,
|
|
84
|
+
&:active {
|
|
85
|
+
&:before {
|
|
86
|
+
background: var(--color-primary);
|
|
87
|
+
border-color: var(--color-primary);
|
|
88
|
+
top: 0;
|
|
89
|
+
left: 6px;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&.button-outline {
|
|
95
|
+
color: var(--color-highlight);
|
|
96
|
+
|
|
97
|
+
&:before {
|
|
98
|
+
border: 1px solid var(--color-highlight);
|
|
99
|
+
background: var(--color-bg);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&:hover {
|
|
103
|
+
&:before {
|
|
104
|
+
background: var(--color-bg);
|
|
105
|
+
border-color: var(--color-primary);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&[disabled],
|
|
110
|
+
&.disabled {
|
|
111
|
+
&:focus,
|
|
112
|
+
&:hover {
|
|
113
|
+
color: var(--color-highlight);
|
|
114
|
+
}
|
|
115
|
+
&:before {
|
|
116
|
+
background: var(--color-bg);
|
|
117
|
+
border-color: var(--color-highlight);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&.button-clear {
|
|
123
|
+
color: var(--color-highlight);
|
|
124
|
+
|
|
125
|
+
&:focus,
|
|
126
|
+
&:hover {
|
|
127
|
+
color: var(--color-primary);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&[disabled],
|
|
131
|
+
&.disabled {
|
|
132
|
+
&:focus,
|
|
133
|
+
&:hover {
|
|
134
|
+
color: var(--color-highlight);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@media (max-width: $responsive-mobile-browser-width) {
|
|
141
|
+
button,
|
|
142
|
+
.button {
|
|
143
|
+
&.stackable {
|
|
144
|
+
display: block;
|
|
145
|
+
width: 100%;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import cn from 'classnames'
|
|
4
|
+
import hljs from 'highlight.js/lib/core'
|
|
5
|
+
import jsLang from 'highlight.js/lib/languages/javascript'
|
|
6
|
+
import jsonLang from 'highlight.js/lib/languages/json'
|
|
7
|
+
import xmlLang from 'highlight.js/lib/languages/xml'
|
|
8
|
+
import plaintextLang from 'highlight.js/lib/languages/plaintext'
|
|
9
|
+
import tomlLang from 'highlight.js/lib/languages/ini'
|
|
10
|
+
import rustLang from 'highlight.js/lib/languages/rust'
|
|
11
|
+
import './code-block.scss'
|
|
12
|
+
|
|
13
|
+
hljs.registerLanguage('js', jsLang)
|
|
14
|
+
hljs.registerLanguage('json', jsonLang)
|
|
15
|
+
hljs.registerLanguage('html', xmlLang)
|
|
16
|
+
hljs.registerLanguage('xml', xmlLang)
|
|
17
|
+
hljs.registerLanguage('plain', plaintextLang)
|
|
18
|
+
hljs.registerLanguage('toml', tomlLang)
|
|
19
|
+
hljs.registerLanguage('rust', rustLang)
|
|
20
|
+
|
|
21
|
+
export const CodeBlock = React.memo(function CodeBlock({children, lang, className, style}) {
|
|
22
|
+
if (lang) {
|
|
23
|
+
lang = lang.split(',')
|
|
24
|
+
}
|
|
25
|
+
const languageFilter = lang || ['js', 'json']
|
|
26
|
+
const highlighted = hljs.highlightAuto(children, languageFilter)
|
|
27
|
+
return <pre dangerouslySetInnerHTML={{__html: highlighted.value}} className={cn('hljs', className)} style={style}/>
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
CodeBlock.propTypes = {
|
|
31
|
+
children: PropTypes.string.isRequired,
|
|
32
|
+
lang: PropTypes.oneOf(['js', 'json', 'html', 'xml', 'toml', 'rust', 'plain']),
|
|
33
|
+
className: PropTypes.string,
|
|
34
|
+
style: PropTypes.object
|
|
35
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
@use "../basic-styles/variables";
|
|
2
|
+
|
|
3
|
+
.hljs {
|
|
4
|
+
background: #1f2d34;
|
|
5
|
+
color: #BABABA;
|
|
6
|
+
font-size: 0.875*$font-size-base;
|
|
7
|
+
letter-spacing: -0.01em;
|
|
8
|
+
line-height: 1.3;
|
|
9
|
+
display: block;
|
|
10
|
+
overflow-x: auto;
|
|
11
|
+
padding: $space-micro $space-standard;
|
|
12
|
+
border: 1px solid var(--color-contrast-border);
|
|
13
|
+
border-radius: $border-radius-input;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.hljs-bullet,
|
|
17
|
+
.hljs-quote,
|
|
18
|
+
.hljs-link,
|
|
19
|
+
.hljs-number,
|
|
20
|
+
.hljs-regexp,
|
|
21
|
+
.hljs-literal {
|
|
22
|
+
color: #6896BA;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.hljs-code,
|
|
26
|
+
.hljs-selector-class {
|
|
27
|
+
color: #A6E22E;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.hljs-strong,
|
|
31
|
+
.hljs-emphasis {
|
|
32
|
+
color: #A8A8A2;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.hljs-emphasis {
|
|
36
|
+
font-style: italic;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.hljs-keyword,
|
|
40
|
+
.hljs-selector-tag,
|
|
41
|
+
.hljs-section,
|
|
42
|
+
.hljs-attribute,
|
|
43
|
+
.hljs-name,
|
|
44
|
+
.hljs-variable {
|
|
45
|
+
color: #CB7832;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.hljs-params {
|
|
49
|
+
color: #B9B9B9;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.hljs-string {
|
|
53
|
+
color: #6A8759;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.hljs-subst,
|
|
57
|
+
.hljs-type,
|
|
58
|
+
.hljs-built_in,
|
|
59
|
+
.hljs-builtin-name,
|
|
60
|
+
.hljs-symbol,
|
|
61
|
+
.hljs-selector-id,
|
|
62
|
+
.hljs-selector-attr,
|
|
63
|
+
.hljs-selector-pseudo,
|
|
64
|
+
.hljs-template-tag,
|
|
65
|
+
.hljs-template-variable,
|
|
66
|
+
.hljs-addition {
|
|
67
|
+
color: #E0C46C;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.hljs-comment,
|
|
71
|
+
.hljs-deletion,
|
|
72
|
+
.hljs-meta {
|
|
73
|
+
color: #7F7F7F;
|
|
74
|
+
}
|