@xyo-network/react-chain-blockchain 1.18.0 → 1.18.1
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/dist/browser/components/account/BalanceHistoryFlexbox.d.ts +1 -1
- package/dist/browser/components/account/BalanceHistoryFlexbox.d.ts.map +1 -1
- package/dist/browser/components/account/helpers/formatBalanceMagnitude.d.ts +1 -1
- package/dist/browser/components/account/helpers/formatBalanceMagnitude.d.ts.map +1 -1
- package/dist/browser/components/account/hooks/usePagedAccountBalanceHistory.d.ts +1 -1
- package/dist/browser/components/account/hooks/usePagedAccountBalanceHistory.d.ts.map +1 -1
- package/dist/browser/components/block/helpers/blockProducer.d.ts +6 -2
- package/dist/browser/components/block/helpers/blockProducer.d.ts.map +1 -1
- package/dist/browser/components/block/helpers/payloadCountsFromBlock.d.ts +1 -1
- package/dist/browser/components/block/helpers/payloadCountsFromBlock.d.ts.map +1 -1
- package/dist/browser/components/block/hooks/useBlockProducer.d.ts +6 -2
- package/dist/browser/components/block/hooks/useBlockProducer.d.ts.map +1 -1
- package/dist/browser/components/block/hooks/usePayloadCountsFromBlock.d.ts +1 -1
- package/dist/browser/components/block/hooks/usePayloadCountsFromBlock.d.ts.map +1 -1
- package/dist/browser/components/block/table/cell/lib/BlockTableCellProps.d.ts +1 -1
- package/dist/browser/components/block/table/cell/lib/BlockTableCellProps.d.ts.map +1 -1
- package/dist/browser/components/chain/hooks/useOnBlock.d.ts +21 -13
- package/dist/browser/components/chain/hooks/useOnBlock.d.ts.map +1 -1
- package/dist/browser/components/index.d.ts +1 -0
- package/dist/browser/components/index.d.ts.map +1 -1
- package/dist/browser/components/payload/builder/transfer/Form.d.ts.map +1 -1
- package/dist/browser/components/payload/builder/transfer/builder/SingleFlexbox.d.ts.map +1 -1
- package/dist/browser/components/payload/fields/XyoAddressTextField.d.ts.map +1 -1
- package/dist/browser/components/rate/SpanTypography.d.ts +8 -0
- package/dist/browser/components/rate/SpanTypography.d.ts.map +1 -0
- package/dist/browser/components/rate/SpeedTypography.d.ts +7 -0
- package/dist/browser/components/rate/SpeedTypography.d.ts.map +1 -0
- package/dist/browser/components/rate/TimeTypography.d.ts +7 -0
- package/dist/browser/components/rate/TimeTypography.d.ts.map +1 -0
- package/dist/browser/components/rate/flexbox/FlexBox.d.ts +7 -0
- package/dist/browser/components/rate/flexbox/FlexBox.d.ts.map +1 -0
- package/dist/browser/components/rate/flexbox/FlexBox.stories.d.ts +10 -0
- package/dist/browser/components/rate/flexbox/FlexBox.stories.d.ts.map +1 -0
- package/dist/browser/components/rate/flexbox/index.d.ts +2 -0
- package/dist/browser/components/rate/flexbox/index.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/Container.d.ts +15 -0
- package/dist/browser/components/rate/gauge/Container.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/Container.stories.d.ts +12 -0
- package/dist/browser/components/rate/gauge/Container.stories.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/Pointer.d.ts +6 -0
- package/dist/browser/components/rate/gauge/Pointer.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/Ticks.d.ts +38 -0
- package/dist/browser/components/rate/gauge/Ticks.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/WithLabel.d.ts +5 -0
- package/dist/browser/components/rate/gauge/WithLabel.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/WithLabel.stories.d.ts +11 -0
- package/dist/browser/components/rate/gauge/WithLabel.stories.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/helpers/blockRateConversions.d.ts +4 -0
- package/dist/browser/components/rate/gauge/helpers/blockRateConversions.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/helpers/index.d.ts +2 -0
- package/dist/browser/components/rate/gauge/helpers/index.d.ts.map +1 -0
- package/dist/browser/components/rate/gauge/index.d.ts +5 -0
- package/dist/browser/components/rate/gauge/index.d.ts.map +1 -0
- package/dist/browser/components/rate/index.d.ts +7 -0
- package/dist/browser/components/rate/index.d.ts.map +1 -0
- package/dist/browser/components/rate/support/MetricTypography.d.ts +11 -0
- package/dist/browser/components/rate/support/MetricTypography.d.ts.map +1 -0
- package/dist/browser/components/rate/support/index.d.ts +2 -0
- package/dist/browser/components/rate/support/index.d.ts.map +1 -0
- package/dist/browser/components/transactions/TransactionsQuickTipButton.d.ts.map +1 -1
- package/dist/browser/context/analyzer/state.d.ts +1 -1
- package/dist/browser/context/analyzer/state.d.ts.map +1 -1
- package/dist/browser/context/chain/Provider.d.ts.map +1 -1
- package/dist/browser/context/chain/State.d.ts +1 -2
- package/dist/browser/context/chain/State.d.ts.map +1 -1
- package/dist/browser/helpers/rate/index.d.ts +2 -0
- package/dist/browser/helpers/rate/index.d.ts.map +1 -0
- package/dist/browser/helpers/rate/rateUnitToLabel.d.ts +3 -0
- package/dist/browser/helpers/rate/rateUnitToLabel.d.ts.map +1 -0
- package/dist/browser/helpers/txsFromBlock.d.ts +4 -22
- package/dist/browser/helpers/txsFromBlock.d.ts.map +1 -1
- package/dist/browser/hooks/chain-iterator/useChainIteratorParams.d.ts +47 -143
- package/dist/browser/hooks/chain-iterator/useChainIteratorParams.d.ts.map +1 -1
- package/dist/browser/hooks/useTxsFromBlock.d.ts +2 -22
- package/dist/browser/hooks/useTxsFromBlock.d.ts.map +1 -1
- package/dist/browser/index.mjs +719 -326
- package/dist/browser/index.mjs.map +1 -1
- package/dist/browser/types/BlockComponentProps.d.ts +1 -1
- package/dist/browser/types/BlockComponentProps.d.ts.map +1 -1
- package/dist/browser/types/BlockComponents.d.ts +1 -1
- package/dist/browser/types/BlockComponents.d.ts.map +1 -1
- package/dist/browser/types/render/BlockChainRenderProps.d.ts +1 -2
- package/dist/browser/types/render/BlockChainRenderProps.d.ts.map +1 -1
- package/package.json +31 -31
- package/src/components/account/BalanceHistoryFlexbox.tsx +2 -2
- package/src/components/account/helpers/formatBalanceMagnitude.ts +1 -1
- package/src/components/account/hooks/usePagedAccountBalanceHistory.ts +9 -14
- package/src/components/block/helpers/blockProducer.ts +1 -1
- package/src/components/block/helpers/payloadCountsFromBlock.ts +1 -1
- package/src/components/block/hooks/useBlockProducer.ts +1 -1
- package/src/components/block/hooks/usePayloadCountsFromBlock.ts +1 -1
- package/src/components/block/table/cell/lib/BlockTableCellProps.ts +1 -1
- package/src/components/chain/hooks/useOnBlock.ts +3 -3
- package/src/components/index.ts +1 -0
- package/src/components/payload/builder/transfer/Form.tsx +5 -2
- package/src/components/payload/builder/transfer/builder/SingleFlexbox.tsx +12 -15
- package/src/components/payload/fields/XyoAddressTextField.tsx +10 -3
- package/src/components/rate/SpanTypography.tsx +20 -0
- package/src/components/rate/SpeedTypography.tsx +17 -0
- package/src/components/rate/TimeTypography.tsx +17 -0
- package/src/components/rate/flexbox/FlexBox.stories.tsx +44 -0
- package/src/components/rate/flexbox/FlexBox.tsx +31 -0
- package/src/components/rate/flexbox/index.ts +1 -0
- package/src/components/rate/gauge/Container.stories.tsx +77 -0
- package/src/components/rate/gauge/Container.tsx +75 -0
- package/src/components/rate/gauge/Pointer.tsx +67 -0
- package/src/components/rate/gauge/Ticks.tsx +122 -0
- package/src/components/rate/gauge/WithLabel.stories.tsx +70 -0
- package/src/components/rate/gauge/WithLabel.tsx +20 -0
- package/src/components/rate/gauge/helpers/blockRateConversions.ts +104 -0
- package/src/components/rate/gauge/helpers/index.ts +1 -0
- package/src/components/rate/gauge/index.ts +4 -0
- package/src/components/rate/index.ts +6 -0
- package/src/components/rate/support/MetricTypography.tsx +78 -0
- package/src/components/rate/support/index.ts +1 -0
- package/src/components/transactions/TransactionsQuickTipButton.tsx +14 -9
- package/src/context/analyzer/Provider.tsx +2 -2
- package/src/context/analyzer/state.ts +1 -1
- package/src/context/chain/Provider.tsx +28 -21
- package/src/context/chain/State.ts +1 -2
- package/src/helpers/rate/index.ts +1 -0
- package/src/helpers/rate/rateUnitToLabel.ts +27 -0
- package/src/helpers/txsFromBlock.ts +4 -2
- package/src/hooks/chain-iterator/useChainIteratorParams.ts +13 -4
- package/src/hooks/useTxsFromBlock.ts +1 -1
- package/src/types/BlockComponentProps.ts +1 -1
- package/src/types/BlockComponents.ts +1 -1
- package/src/types/render/BlockChainRenderProps.ts +1 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { GaugeContainerProps } from '@mui/x-charts'
|
|
2
|
+
import {
|
|
3
|
+
GaugeContainer, GaugeReferenceArc, GaugeValueArc,
|
|
4
|
+
} from '@mui/x-charts'
|
|
5
|
+
import type { BlockRate, TimeDurations } from '@xyo-network/xl1-sdk'
|
|
6
|
+
import type { PropsWithChildren } from 'react'
|
|
7
|
+
|
|
8
|
+
import { BlockRateConversions } from './helpers/index.ts'
|
|
9
|
+
import { GaugePointer } from './Pointer.tsx'
|
|
10
|
+
import { GaugeTicks } from './Ticks.tsx'
|
|
11
|
+
|
|
12
|
+
export type GaugeConfig = {
|
|
13
|
+
// whether to show ticks on the gauge
|
|
14
|
+
showTicks?: boolean
|
|
15
|
+
// the block rate to target on the gauge
|
|
16
|
+
targetBlockRate: number
|
|
17
|
+
// the unit of time for the target block rate (e.g., seconds, minutes)
|
|
18
|
+
targetBlockRateUnit: keyof TimeDurations
|
|
19
|
+
// the position of the pointer when the block rate matches the target rate
|
|
20
|
+
// should be approximately between 2/3 and 3/4 position of the gauge
|
|
21
|
+
targetPosition: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface BlockRateSpeedGaugeProps extends GaugeContainerProps, PropsWithChildren {
|
|
25
|
+
blockRate?: BlockRate
|
|
26
|
+
gaugeConfig?: GaugeConfig
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const BlockRateSpeedGaugeContainer: React.FC<BlockRateSpeedGaugeProps> = ({
|
|
30
|
+
blockRate,
|
|
31
|
+
children,
|
|
32
|
+
gaugeConfig,
|
|
33
|
+
startAngle = -110,
|
|
34
|
+
endAngle = 110,
|
|
35
|
+
width = 200,
|
|
36
|
+
height = 150,
|
|
37
|
+
...props
|
|
38
|
+
}) => {
|
|
39
|
+
const { rate, rateUnit } = blockRate || {}
|
|
40
|
+
const {
|
|
41
|
+
targetBlockRate = 5, targetBlockRateUnit = 'minutes', targetPosition = 75, showTicks = true,
|
|
42
|
+
} = gaugeConfig || {}
|
|
43
|
+
|
|
44
|
+
// Get the appropriate converter function based on the target block rate unit
|
|
45
|
+
const converter = BlockRateConversions[targetBlockRateUnit]
|
|
46
|
+
|
|
47
|
+
// Normalize rate to the gauge
|
|
48
|
+
const maxGaugeValue = endAngle // matches endAngle
|
|
49
|
+
const blocksPerMinute = rate === undefined ? 0 : converter(rate, rateUnit)
|
|
50
|
+
|
|
51
|
+
// Scale: 5 blocks/min should map to 75 out of 110 max
|
|
52
|
+
// This means: normalizedValue = (blocksPerMinute / targetRate) * targetPosition
|
|
53
|
+
// And we want it capped at maxGaugeValue
|
|
54
|
+
const normalizedValue = Math.min((blocksPerMinute / targetBlockRate) * targetPosition, maxGaugeValue)
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<GaugeContainer
|
|
58
|
+
width={width}
|
|
59
|
+
height={height}
|
|
60
|
+
startAngle={startAngle}
|
|
61
|
+
endAngle={endAngle}
|
|
62
|
+
value={normalizedValue}
|
|
63
|
+
valueMax={endAngle}
|
|
64
|
+
innerRadius="95%"
|
|
65
|
+
outerRadius="100%"
|
|
66
|
+
{...props}
|
|
67
|
+
>
|
|
68
|
+
{showTicks && <GaugeTicks />}
|
|
69
|
+
<GaugeReferenceArc />
|
|
70
|
+
<GaugeValueArc />
|
|
71
|
+
<GaugePointer startAngle={-2} />
|
|
72
|
+
{children}
|
|
73
|
+
</GaugeContainer>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useTheme } from '@mui/material'
|
|
2
|
+
import { useGaugeState } from '@mui/x-charts/Gauge'
|
|
3
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
4
|
+
import { useEffect, useState } from 'react'
|
|
5
|
+
|
|
6
|
+
export interface GaugePointerProps {
|
|
7
|
+
pointerColor?: string
|
|
8
|
+
startAngle?: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const GaugePointer: React.FC<GaugePointerProps> = ({ pointerColor, startAngle = 0 }) => {
|
|
12
|
+
const theme = useTheme()
|
|
13
|
+
const strokeColor = isDefined(pointerColor) ? pointerColor : theme.palette.error.dark
|
|
14
|
+
const {
|
|
15
|
+
valueAngle, outerRadius, cx, cy,
|
|
16
|
+
} = useGaugeState()
|
|
17
|
+
|
|
18
|
+
const [currentAngle, setCurrentAngle] = useState(startAngle)
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (valueAngle === null) return
|
|
22
|
+
|
|
23
|
+
const duration = 500 // 0.5 second animation
|
|
24
|
+
const startTime = Date.now()
|
|
25
|
+
const animationStartAngle = currentAngle // Start from current position
|
|
26
|
+
const endAngle = valueAngle
|
|
27
|
+
|
|
28
|
+
const animate = () => {
|
|
29
|
+
const now = Date.now()
|
|
30
|
+
const elapsed = now - startTime
|
|
31
|
+
const progress = Math.min(elapsed / duration, 1)
|
|
32
|
+
|
|
33
|
+
// Ease-out cubic for smooth deceleration
|
|
34
|
+
const easeProgress = 1 - Math.pow(1 - progress, 3)
|
|
35
|
+
|
|
36
|
+
// take the current angle and add the difference to the end angle based on progress
|
|
37
|
+
const newAngle = animationStartAngle + (endAngle - animationStartAngle) * easeProgress
|
|
38
|
+
setCurrentAngle(newAngle)
|
|
39
|
+
|
|
40
|
+
if (progress < 1) {
|
|
41
|
+
globalThis.requestAnimationFrame(animate)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
globalThis.requestAnimationFrame(animate)
|
|
46
|
+
}, [currentAngle, valueAngle])
|
|
47
|
+
|
|
48
|
+
if (valueAngle === null) {
|
|
49
|
+
// No value to display
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const target = {
|
|
54
|
+
x: cx + outerRadius * Math.sin(currentAngle),
|
|
55
|
+
y: cy - outerRadius * Math.cos(currentAngle),
|
|
56
|
+
}
|
|
57
|
+
return (
|
|
58
|
+
<g className="GaugePointer">
|
|
59
|
+
<circle cx={cx} cy={cy} r={5} fill={strokeColor} />
|
|
60
|
+
<path
|
|
61
|
+
d={`M ${cx} ${cy} L ${target.x} ${target.y}`}
|
|
62
|
+
stroke={strokeColor}
|
|
63
|
+
strokeWidth={3}
|
|
64
|
+
/>
|
|
65
|
+
</g>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { useTheme } from '@mui/material'
|
|
2
|
+
import { useGaugeState } from '@mui/x-charts/Gauge'
|
|
3
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
4
|
+
import type { JSX } from 'react'
|
|
5
|
+
|
|
6
|
+
export interface GaugeTicksProps {
|
|
7
|
+
/**
|
|
8
|
+
* Length of major ticks as a percentage of the radius
|
|
9
|
+
* @default 0.15
|
|
10
|
+
*/
|
|
11
|
+
majorTickLength?: number
|
|
12
|
+
/**
|
|
13
|
+
* Width of major ticks in pixels
|
|
14
|
+
* @default 2
|
|
15
|
+
*/
|
|
16
|
+
majorTickWidth?: number
|
|
17
|
+
/**
|
|
18
|
+
* Length of minor ticks as a percentage of the radius
|
|
19
|
+
* @default 0.08
|
|
20
|
+
*/
|
|
21
|
+
minorTickLength?: number
|
|
22
|
+
/**
|
|
23
|
+
* Width of minor ticks in pixels
|
|
24
|
+
* @default 1
|
|
25
|
+
*/
|
|
26
|
+
minorTickWidth?: number
|
|
27
|
+
/**
|
|
28
|
+
* Number of minor ticks between major ticks
|
|
29
|
+
* @default 4
|
|
30
|
+
*/
|
|
31
|
+
minorTicksPerMajor?: number
|
|
32
|
+
/**
|
|
33
|
+
* Number of major ticks to display
|
|
34
|
+
* @default 11
|
|
35
|
+
*/
|
|
36
|
+
numTicks?: number
|
|
37
|
+
/**
|
|
38
|
+
* Color of the ticks
|
|
39
|
+
*/
|
|
40
|
+
tickColor?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const GaugeTicks: React.FC<GaugeTicksProps> = ({
|
|
44
|
+
numTicks = 11,
|
|
45
|
+
minorTicksPerMajor = 4,
|
|
46
|
+
majorTickLength = 0.2,
|
|
47
|
+
minorTickLength = 0.15,
|
|
48
|
+
majorTickWidth = 2,
|
|
49
|
+
minorTickWidth = 1,
|
|
50
|
+
tickColor,
|
|
51
|
+
}) => {
|
|
52
|
+
const theme = useTheme()
|
|
53
|
+
const {
|
|
54
|
+
startAngle, endAngle, outerRadius, cx, cy,
|
|
55
|
+
} = useGaugeState()
|
|
56
|
+
|
|
57
|
+
const color = isDefined(tickColor) ? tickColor : theme.vars.palette.text.secondary
|
|
58
|
+
|
|
59
|
+
if (startAngle === null || endAngle === null) {
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const ticks: JSX.Element[] = []
|
|
64
|
+
const totalAngle = endAngle - startAngle
|
|
65
|
+
|
|
66
|
+
// Generate major ticks
|
|
67
|
+
for (let i = 0; i < numTicks; i++) {
|
|
68
|
+
const angle = startAngle + (i / (numTicks - 1)) * totalAngle
|
|
69
|
+
const tickLength = outerRadius * majorTickLength
|
|
70
|
+
const tickStart = outerRadius
|
|
71
|
+
const innerRadius = tickStart - tickLength
|
|
72
|
+
|
|
73
|
+
const x1 = cx + tickStart * Math.sin(angle)
|
|
74
|
+
const y1 = cy - tickStart * Math.cos(angle)
|
|
75
|
+
const x2 = cx + innerRadius * Math.sin(angle)
|
|
76
|
+
const y2 = cy - innerRadius * Math.cos(angle)
|
|
77
|
+
|
|
78
|
+
ticks.push(
|
|
79
|
+
<line
|
|
80
|
+
className={`GaugeTick-major-${i}`}
|
|
81
|
+
key={`major-${i}`}
|
|
82
|
+
x1={x1}
|
|
83
|
+
y1={y1}
|
|
84
|
+
x2={x2}
|
|
85
|
+
y2={y2}
|
|
86
|
+
stroke={color}
|
|
87
|
+
strokeWidth={majorTickWidth}
|
|
88
|
+
// strokeLinecap="round"
|
|
89
|
+
/>,
|
|
90
|
+
)
|
|
91
|
+
// Generate minor ticks between major ticks (except after the last major tick)
|
|
92
|
+
if (i < numTicks - 1) {
|
|
93
|
+
const angleStep = totalAngle / (numTicks - 1) / (minorTicksPerMajor + 1)
|
|
94
|
+
for (let j = 1; j <= minorTicksPerMajor; j++) {
|
|
95
|
+
const minorAngle = angle + angleStep * j
|
|
96
|
+
const minorTickLen = outerRadius * minorTickLength
|
|
97
|
+
const minorTickStart = outerRadius
|
|
98
|
+
const minorInnerRadius = minorTickStart - minorTickLen
|
|
99
|
+
|
|
100
|
+
const mx1 = cx + minorTickStart * Math.sin(minorAngle)
|
|
101
|
+
const my1 = cy - minorTickStart * Math.cos(minorAngle)
|
|
102
|
+
const mx2 = cx + minorInnerRadius * Math.sin(minorAngle)
|
|
103
|
+
const my2 = cy - minorInnerRadius * Math.cos(minorAngle)
|
|
104
|
+
|
|
105
|
+
ticks.push(
|
|
106
|
+
<line
|
|
107
|
+
key={`minor-${i}-${j}`}
|
|
108
|
+
x1={mx1}
|
|
109
|
+
y1={my1}
|
|
110
|
+
x2={mx2}
|
|
111
|
+
y2={my2}
|
|
112
|
+
stroke={color}
|
|
113
|
+
strokeWidth={minorTickWidth}
|
|
114
|
+
// strokeLinecap="round"
|
|
115
|
+
/>,
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return <g className="GaugeTicks">{ticks}</g>
|
|
122
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Meta, StoryFn } from '@storybook/react-vite'
|
|
2
|
+
import type { BlockRate } from '@xyo-network/xl1-sdk'
|
|
3
|
+
import { asXL1BlockRange } from '@xyo-network/xl1-sdk'
|
|
4
|
+
|
|
5
|
+
import type { GaugeConfig } from './Container.tsx'
|
|
6
|
+
import { BlockRateSpeedGaugeWithLabel } from './WithLabel.tsx'
|
|
7
|
+
|
|
8
|
+
const blockRateSeconds: BlockRate = {
|
|
9
|
+
range: asXL1BlockRange([100, 200], true),
|
|
10
|
+
span: 100,
|
|
11
|
+
rate: 0.083_33,
|
|
12
|
+
rateUnit: 'seconds',
|
|
13
|
+
timeDifference: (100 * 12),
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const blockRateMinutes: BlockRate = {
|
|
17
|
+
range: asXL1BlockRange([100, 200], true),
|
|
18
|
+
span: 100,
|
|
19
|
+
rate: 5,
|
|
20
|
+
rateUnit: 'minutes',
|
|
21
|
+
timeDifference: (100 * 12) / 60,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const blockRateHour: BlockRate = {
|
|
25
|
+
range: asXL1BlockRange([100, 200], true),
|
|
26
|
+
span: 100,
|
|
27
|
+
rate: 7 * 60,
|
|
28
|
+
rateUnit: 'hours',
|
|
29
|
+
timeDifference: (100 * 12) / 60,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const gaugeConfigHours: GaugeConfig = {
|
|
33
|
+
targetBlockRate: 5 * 60,
|
|
34
|
+
targetBlockRateUnit: 'hours',
|
|
35
|
+
targetPosition: 75,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const gaugeConfigMinutes: GaugeConfig = {
|
|
39
|
+
targetBlockRate: 5,
|
|
40
|
+
targetBlockRateUnit: 'minutes',
|
|
41
|
+
targetPosition: 75,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default {
|
|
45
|
+
title: 'BlockRate/Gauge/Label',
|
|
46
|
+
component: BlockRateSpeedGaugeWithLabel,
|
|
47
|
+
} satisfies Meta<typeof BlockRateSpeedGaugeWithLabel>
|
|
48
|
+
|
|
49
|
+
const Template: StoryFn<typeof BlockRateSpeedGaugeWithLabel> = (args) => {
|
|
50
|
+
return <BlockRateSpeedGaugeWithLabel {...args} />
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const Default = Template.bind({})
|
|
54
|
+
Default.args = {}
|
|
55
|
+
|
|
56
|
+
const WithBlockRateSeconds = Template.bind({})
|
|
57
|
+
WithBlockRateSeconds.args = { blockRate: blockRateSeconds }
|
|
58
|
+
|
|
59
|
+
const WithBlockRateMinutes = Template.bind({})
|
|
60
|
+
WithBlockRateMinutes.args = { blockRate: blockRateMinutes, gaugeConfig: gaugeConfigMinutes }
|
|
61
|
+
|
|
62
|
+
const WithBlockRateHours = Template.bind({})
|
|
63
|
+
WithBlockRateHours.args = { blockRate: blockRateHour, gaugeConfig: gaugeConfigHours }
|
|
64
|
+
|
|
65
|
+
export {
|
|
66
|
+
Default,
|
|
67
|
+
WithBlockRateHours,
|
|
68
|
+
WithBlockRateMinutes,
|
|
69
|
+
WithBlockRateSeconds,
|
|
70
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FlexCol } from '@xylabs/react-flexbox'
|
|
2
|
+
import { isDefined } from '@xylabs/sdk-js'
|
|
3
|
+
|
|
4
|
+
import { rateUnitToLabel } from '../../../helpers/rate/index.ts'
|
|
5
|
+
import { BlockRateSpeedTypography } from '../SpeedTypography.tsx'
|
|
6
|
+
import type { BlockRateSpeedGaugeProps } from './Container.tsx'
|
|
7
|
+
import { BlockRateSpeedGaugeContainer } from './Container.tsx'
|
|
8
|
+
|
|
9
|
+
export interface BlockRateSpeedGaugeWithLabelProps extends BlockRateSpeedGaugeProps {}
|
|
10
|
+
|
|
11
|
+
export const BlockRateSpeedGaugeWithLabel: React.FC<BlockRateSpeedGaugeProps> = ({ blockRate, ...props }) => {
|
|
12
|
+
const rateUnitLabel = isDefined(blockRate?.rateUnit) ? rateUnitToLabel(blockRate.rateUnit) : ''
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<FlexCol>
|
|
16
|
+
<BlockRateSpeedGaugeContainer blockRate={blockRate} {...props} />
|
|
17
|
+
<BlockRateSpeedTypography rate={blockRate?.rate} rateUnitLabel={rateUnitLabel} />
|
|
18
|
+
</FlexCol>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { isDefined, isUndefined } from '@xylabs/sdk-js'
|
|
2
|
+
import type { TimeDurations } from '@xyo-network/xl1-sdk'
|
|
3
|
+
|
|
4
|
+
export type BlockRateConverter = (rateValue: number, unit?: keyof TimeDurations) => number
|
|
5
|
+
|
|
6
|
+
const toBlocksPerMillisecond: BlockRateConverter = (rateValue: number, unit?: keyof TimeDurations): number => {
|
|
7
|
+
if (isUndefined(unit)) return rateValue
|
|
8
|
+
|
|
9
|
+
const conversions: Record<keyof TimeDurations, number> = {
|
|
10
|
+
millis: 1, // already in milliseconds
|
|
11
|
+
seconds: 1000, // 1 second = 1000 milliseconds
|
|
12
|
+
minutes: 60_000, // 1 minute = 60000 milliseconds
|
|
13
|
+
hours: 3_600_000, // 1 hour = 3600000 milliseconds
|
|
14
|
+
days: 86_400_000, // 1 day = 86400000 milliseconds
|
|
15
|
+
weeks: 604_800_000, // 1 week = 604800000 milliseconds
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return rateValue * (isDefined(conversions[unit]) ? conversions[unit] : 1)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const toBlocksPerSecond: BlockRateConverter = (rateValue: number, unit?: keyof TimeDurations): number => {
|
|
22
|
+
if (isUndefined(unit)) return rateValue
|
|
23
|
+
|
|
24
|
+
const conversions: Record<keyof TimeDurations, number> = {
|
|
25
|
+
millis: 0.001, // 1 millisecond = 0.001 seconds
|
|
26
|
+
seconds: 1, // already in seconds
|
|
27
|
+
minutes: 60, // 1 minute = 60 seconds
|
|
28
|
+
hours: 3600, // 1 hour = 3600 seconds
|
|
29
|
+
days: 86_400, // 1 day = 86400 seconds
|
|
30
|
+
weeks: 604_800, // 1 week = 604800 seconds
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return rateValue * (isDefined(conversions[unit]) ? conversions[unit] : 1)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Convert rate to blocks per minute based on the unit
|
|
37
|
+
const toBlocksPerMinute: BlockRateConverter = (rateValue: number, unit?: keyof TimeDurations): number => {
|
|
38
|
+
if (isUndefined(unit)) return rateValue
|
|
39
|
+
|
|
40
|
+
const conversions: Record<keyof TimeDurations, number> = {
|
|
41
|
+
millis: 60_000, // 1 minute = 60000 milliseconds
|
|
42
|
+
seconds: 60, // 1 minute = 60 seconds
|
|
43
|
+
minutes: 1, // already in minutes
|
|
44
|
+
hours: 1 / 60, // 1 hour = 60 minutes
|
|
45
|
+
days: 1 / 1440, // 1 day = 1440 minutes
|
|
46
|
+
weeks: 1 / 10_080, // 1 week = 10080 minutes
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return rateValue * (isDefined(conversions[unit]) ? conversions[unit] : 1)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const toBlocksPerHour: BlockRateConverter = (rateValue: number, unit?: keyof TimeDurations): number => {
|
|
53
|
+
if (isUndefined(unit)) return rateValue
|
|
54
|
+
|
|
55
|
+
const conversions: Record<keyof TimeDurations, number> = {
|
|
56
|
+
millis: 3_600_000, // 1 hour = 3600000 milliseconds
|
|
57
|
+
seconds: 3600, // 1 hour = 3600 seconds
|
|
58
|
+
minutes: 60, // 1 hour = 60 minutes
|
|
59
|
+
hours: 1, // already in hours
|
|
60
|
+
days: 1 / 24, // 1 day = 24 hours
|
|
61
|
+
weeks: 1 / 168, // 1 week = 168 hours
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return rateValue * (isDefined(conversions[unit]) ? conversions[unit] : 1)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const toBlocksPerDay: BlockRateConverter = (rateValue: number, unit?: keyof TimeDurations): number => {
|
|
68
|
+
if (isUndefined(unit)) return rateValue
|
|
69
|
+
|
|
70
|
+
const conversions: Record<keyof TimeDurations, number> = {
|
|
71
|
+
millis: 86_400_000, // 1 day = 86400000 milliseconds
|
|
72
|
+
seconds: 86_400, // 1 day = 86400 seconds
|
|
73
|
+
minutes: 1440, // 1 day = 1440 minutes
|
|
74
|
+
hours: 24, // 1 day = 24 hours
|
|
75
|
+
days: 1, // already in days
|
|
76
|
+
weeks: 1 / 7, // 1 week = 7 days
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return rateValue * (isDefined(conversions[unit]) ? conversions[unit] : 1)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const toBlocksPerWeek: BlockRateConverter = (rateValue: number, unit?: keyof TimeDurations): number => {
|
|
83
|
+
if (isUndefined(unit)) return rateValue
|
|
84
|
+
|
|
85
|
+
const conversions: Record<keyof TimeDurations, number> = {
|
|
86
|
+
millis: 604_800_000, // 1 week = 604800000 milliseconds
|
|
87
|
+
seconds: 604_800, // 1 week = 604800 seconds
|
|
88
|
+
minutes: 10_080, // 1 week = 10080 minutes
|
|
89
|
+
hours: 168, // 1 week = 168 hours
|
|
90
|
+
days: 7, // 1 week = 7 days
|
|
91
|
+
weeks: 1, // already in weeks
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return rateValue * (isDefined(conversions[unit]) ? conversions[unit] : 1)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const BlockRateConversions: Record<keyof TimeDurations, BlockRateConverter> = {
|
|
98
|
+
millis: toBlocksPerMillisecond,
|
|
99
|
+
seconds: toBlocksPerSecond,
|
|
100
|
+
minutes: toBlocksPerMinute,
|
|
101
|
+
hours: toBlocksPerHour,
|
|
102
|
+
days: toBlocksPerDay,
|
|
103
|
+
weeks: toBlocksPerWeek,
|
|
104
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './blockRateConversions.ts'
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { TypographyProps } from '@mui/material'
|
|
2
|
+
import { Icon, Typography } from '@mui/material'
|
|
3
|
+
import { isUndefined } from '@xylabs/sdk-js'
|
|
4
|
+
import type { ReactNode } from 'react'
|
|
5
|
+
import { useEffect, useState } from 'react'
|
|
6
|
+
|
|
7
|
+
export interface MetricTypographyProps extends TypographyProps {
|
|
8
|
+
animationDurationMs?: number
|
|
9
|
+
disableAnimation?: boolean
|
|
10
|
+
icon?: ReactNode
|
|
11
|
+
label?: ReactNode
|
|
12
|
+
metric?: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const MetricTypography: React.FC<MetricTypographyProps> = ({
|
|
16
|
+
animationDurationMs = 1000, disableAnimation, icon, label, metric, sx, ...props
|
|
17
|
+
}) => {
|
|
18
|
+
const [displayValue, setDisplayValue] = useState(0)
|
|
19
|
+
|
|
20
|
+
if (isUndefined(metric) && displayValue !== 0) {
|
|
21
|
+
setDisplayValue(0)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (isUndefined(metric)) return
|
|
26
|
+
const duration = animationDurationMs
|
|
27
|
+
const startTime = Date.now()
|
|
28
|
+
const startValue = 0
|
|
29
|
+
const endValue = metric
|
|
30
|
+
|
|
31
|
+
const animate = () => {
|
|
32
|
+
const now = Date.now()
|
|
33
|
+
const elapsed = now - startTime
|
|
34
|
+
const progress = Math.min(elapsed / duration, 1)
|
|
35
|
+
|
|
36
|
+
// Easing function for smooth animation (ease-out
|
|
37
|
+
const easeProgress = 1 - Math.pow(1 - progress, 3)
|
|
38
|
+
|
|
39
|
+
const currentValue = startValue + (endValue - startValue) * easeProgress
|
|
40
|
+
setDisplayValue(currentValue)
|
|
41
|
+
|
|
42
|
+
if (progress < 1) {
|
|
43
|
+
requestAnimationFrame(animate)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
globalThis.requestAnimationFrame(animate)
|
|
48
|
+
}, [animationDurationMs, metric])
|
|
49
|
+
|
|
50
|
+
// Check if metric is a whole number
|
|
51
|
+
const isWholeNumber = metric !== undefined && Number.isInteger(metric)
|
|
52
|
+
|
|
53
|
+
// Format based on whether the target is a whole number
|
|
54
|
+
const formattedValue = disableAnimation
|
|
55
|
+
? metric
|
|
56
|
+
: displayValue.toLocaleString(navigator.language, {
|
|
57
|
+
minimumFractionDigits: 0,
|
|
58
|
+
maximumFractionDigits: isWholeNumber ? 0 : 2,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Typography
|
|
63
|
+
variant="h4"
|
|
64
|
+
mb={1}
|
|
65
|
+
sx={{
|
|
66
|
+
display: 'flex', alignItems: 'end', gap: 0.5, ...sx,
|
|
67
|
+
}}
|
|
68
|
+
{...props}
|
|
69
|
+
>
|
|
70
|
+
<Icon fontSize="large">{icon}</Icon>
|
|
71
|
+
{formattedValue}
|
|
72
|
+
{' '}
|
|
73
|
+
<Typography component="span" variant="caption" lineHeight={1.86}>
|
|
74
|
+
{label}
|
|
75
|
+
</Typography>
|
|
76
|
+
</Typography>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './MetricTypography.tsx'
|
|
@@ -8,11 +8,9 @@ import {
|
|
|
8
8
|
} from '@xylabs/react-flexbox'
|
|
9
9
|
import type { QuickTipButtonProps } from '@xylabs/react-quick-tip-button'
|
|
10
10
|
import { QuickTipButton } from '@xylabs/react-quick-tip-button'
|
|
11
|
-
import type
|
|
11
|
+
import { type Hash, isDefined } from '@xylabs/sdk-js'
|
|
12
12
|
import type { HydratedBlockWithHashMeta } from '@xyo-network/xl1-protocol'
|
|
13
|
-
import React, {
|
|
14
|
-
Fragment, useMemo, useState,
|
|
15
|
-
} from 'react'
|
|
13
|
+
import React, { Fragment, useState } from 'react'
|
|
16
14
|
|
|
17
15
|
import { useTxsFromBlock } from '../../hooks/index.ts'
|
|
18
16
|
|
|
@@ -24,8 +22,16 @@ export const TransactionsQuickTipButton: React.FC<TransactionsQuickTipButtonQuic
|
|
|
24
22
|
const [transactions, transactionsError] = useTxsFromBlock(block)
|
|
25
23
|
|
|
26
24
|
const [copied, setCopied] = useState(false)
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
|
|
26
|
+
const [closeDialog, setCloseDialog] = useState(false)
|
|
27
|
+
const open = isDefined(transactionsError)
|
|
28
|
+
|
|
29
|
+
// if the error changes, reopen the dialog
|
|
30
|
+
const [previousTransactionError, setPreviousTransactionError] = useState<Error | undefined>(transactionsError)
|
|
31
|
+
if (isDefined(transactionsError) && transactionsError !== previousTransactionError) {
|
|
32
|
+
setPreviousTransactionError(transactionsError)
|
|
33
|
+
setCloseDialog(false)
|
|
34
|
+
}
|
|
29
35
|
|
|
30
36
|
const onCopy = async (transactionHash: Hash) => {
|
|
31
37
|
await navigator.clipboard.writeText(transactionHash)
|
|
@@ -49,8 +55,7 @@ export const TransactionsQuickTipButton: React.FC<TransactionsQuickTipButtonQuic
|
|
|
49
55
|
? null
|
|
50
56
|
: (
|
|
51
57
|
<FlexGrowCol gap={1} alignItems="stretch">
|
|
52
|
-
{
|
|
53
|
-
{transactions?.map(([transaction, hash]) => (
|
|
58
|
+
{transactions?.map(([_transaction, hash]) => (
|
|
54
59
|
<Fragment key={hash}>
|
|
55
60
|
<FlexGrowRow gap={2} justifyContent="start">
|
|
56
61
|
<ContentCopyIcon sx={{ cursor: 'pointer' }} onClick={() => void onCopy(hash)} />
|
|
@@ -73,7 +78,7 @@ export const TransactionsQuickTipButton: React.FC<TransactionsQuickTipButtonQuic
|
|
|
73
78
|
</FlexGrowCol>
|
|
74
79
|
)}
|
|
75
80
|
</QuickTipButton>
|
|
76
|
-
<Snackbar open={
|
|
81
|
+
<Snackbar open={open && closeDialog === false} onClose={() => setCloseDialog(true)}>
|
|
77
82
|
<ErrorRender error={transactionsError} scope="TransactionsQuickTipButton" />
|
|
78
83
|
</Snackbar>
|
|
79
84
|
</>
|
|
@@ -14,9 +14,9 @@ export interface ChainAnalyzersProviderProps extends PropsWithChildren {
|
|
|
14
14
|
|
|
15
15
|
export const ChainAnalyzersProvider: React.FC<ChainAnalyzersProviderProps> = ({ analyzers: analyzersProp, children }) => {
|
|
16
16
|
const [analyzersState, setAnalyzersState] = useState<ChainAnalyzers>(analyzersProp ?? {} as ChainAnalyzers)
|
|
17
|
-
const [statsUpdated, setStatsUpdated] = useState(
|
|
17
|
+
const [statsUpdated, setStatsUpdated] = useState(1)
|
|
18
18
|
|
|
19
|
-
const analyzers = useMemo(() => ({ ...analyzersProp, ...analyzersState }), [analyzersProp])
|
|
19
|
+
const analyzers = useMemo(() => ({ ...analyzersProp, ...analyzersState }), [analyzersProp, analyzersState])
|
|
20
20
|
|
|
21
21
|
const addAnalyzers: ChainAnalyzersState['addAnalyzers'] = useCallback((analyzers: ChainAnalyzersState['analyzers']) => {
|
|
22
22
|
if (isUndefined(analyzers)) return
|