@stellar-expert/ui-framework 1.19.2 → 1.20.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/charts/axis/axis.js +470 -0
- package/charts/axis/tick-positioner.js +172 -0
- package/charts/chart-default-options.js +158 -0
- package/charts/chart-loader.js +26 -0
- package/charts/chart-options-builder.js +81 -0
- package/charts/chart.js +99 -0
- package/charts/chart.scss +80 -0
- package/charts/core/animate.js +99 -0
- package/charts/core/chart.js +555 -0
- package/charts/core/color.js +89 -0
- package/charts/core/options.js +40 -0
- package/charts/core/svg-renderer.js +155 -0
- package/charts/core/time.js +129 -0
- package/charts/core/utilities.js +92 -0
- package/charts/globals.js +32 -0
- package/charts/index.js +4 -0
- package/charts/interaction/legend.js +125 -0
- package/charts/interaction/tooltip.js +185 -0
- package/charts/pie/pie-chart.js +269 -0
- package/charts/polar/polar-chart.js +99 -0
- package/charts/series/area-series.js +57 -0
- package/charts/series/candlestick-series.js +60 -0
- package/charts/series/column-series.js +55 -0
- package/charts/series/index.js +21 -0
- package/charts/series/line-series.js +21 -0
- package/charts/series/series.js +161 -0
- package/charts/stock/data-grouping.js +141 -0
- package/charts/stock/navigator.js +205 -0
- package/charts/stock/range-selector.js +140 -0
- package/effect/effect-description.js +1 -1
- package/index.d.ts +36 -0
- package/index.js +2 -0
- package/package.json +5 -2
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {isNumber} from '../core/utilities'
|
|
2
|
+
|
|
3
|
+
const DAY = 24 * 3600 * 1000
|
|
4
|
+
|
|
5
|
+
function buttonPeriodMs(b) {
|
|
6
|
+
if (b.type === 'month') return (b.count || 1) * 30 * DAY
|
|
7
|
+
if (b.type === 'year') return (b.count || 1) * 365 * DAY
|
|
8
|
+
if (b.type === 'day') return (b.count || 1) * DAY
|
|
9
|
+
return Infinity
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//Floating range-selector buttons (1m / 3m / 6m / 1y / All) for StockChart, mirroring the explorer's config.
|
|
13
|
+
export class RangeSelector {
|
|
14
|
+
constructor(chart) {
|
|
15
|
+
this.chart = chart
|
|
16
|
+
this.options = chart.options.rangeSelector
|
|
17
|
+
this.selected = 'all' //default view = full range
|
|
18
|
+
//if an initial xAxis.range is set, pre-select the matching button
|
|
19
|
+
const initialRange = chart.xAxis[0] && chart.xAxis[0].options.range
|
|
20
|
+
if (this.options && this.options.buttons && isNumber(initialRange)) {
|
|
21
|
+
let bestIdx = -1
|
|
22
|
+
let bestDiff = Infinity
|
|
23
|
+
this.options.buttons.forEach((b, i) => {
|
|
24
|
+
const diff = Math.abs(buttonPeriodMs(b) - initialRange)
|
|
25
|
+
if (diff < bestDiff) {
|
|
26
|
+
bestDiff = diff
|
|
27
|
+
bestIdx = i
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
if (bestIdx >= 0)
|
|
31
|
+
this.selected = bestIdx
|
|
32
|
+
}
|
|
33
|
+
if (this.options && this.options.buttons)
|
|
34
|
+
this.build()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
build() {
|
|
38
|
+
const chart = this.chart
|
|
39
|
+
//overlay wrapper — visual styling lives in .chart-range-selector (chart.scss); only the dynamic
|
|
40
|
+
//horizontal offset (plotLeft) is set inline in reposition()
|
|
41
|
+
const el = document.createElement('div')
|
|
42
|
+
el.className = 'chart-range-selector'
|
|
43
|
+
this.el = el
|
|
44
|
+
const zoomLabel = document.createElement('span')
|
|
45
|
+
zoomLabel.className = 'zoom-label'
|
|
46
|
+
zoomLabel.textContent = 'Zoom'
|
|
47
|
+
el.appendChild(zoomLabel)
|
|
48
|
+
this.zoomLabel = zoomLabel
|
|
49
|
+
|
|
50
|
+
//a button is disabled when the loaded data doesn't span its period —
|
|
51
|
+
//e.g. only ~1y of data → 'All' and '1y' work, but a hypothetical longer button would be greyed out
|
|
52
|
+
const xa = chart.xAxis[0]
|
|
53
|
+
const dataRange = (xa && isNumber(xa.dataMax) && isNumber(xa.dataMin)) ? xa.dataMax - xa.dataMin : Infinity
|
|
54
|
+
|
|
55
|
+
//controls are rendered as plain spans (NOT <button>/.button) so they keep the charts-lib's own
|
|
56
|
+
//self-contained style and never inherit the global project button look (skew/sizing/focus rules)
|
|
57
|
+
this.buttons = this.options.buttons.map((b, i) => {
|
|
58
|
+
const btn = document.createElement('span')
|
|
59
|
+
btn.className = 'chart-zoom-btn'
|
|
60
|
+
btn.setAttribute('role', 'button')
|
|
61
|
+
btn.textContent = b.text
|
|
62
|
+
//tolerance of one day absorbs the approximate month/year lengths
|
|
63
|
+
const disabled = b.type !== 'all' && buttonPeriodMs(b) > dataRange + DAY
|
|
64
|
+
if (!disabled) {
|
|
65
|
+
btn.tabIndex = 0
|
|
66
|
+
btn.addEventListener('click', () => this.apply(b, i))
|
|
67
|
+
btn.addEventListener('keydown', e => {
|
|
68
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
69
|
+
e.preventDefault()
|
|
70
|
+
this.apply(b, i)
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
el.appendChild(btn)
|
|
75
|
+
return {btn, def: b, disabled}
|
|
76
|
+
})
|
|
77
|
+
chart.container.appendChild(el)
|
|
78
|
+
this.highlight()
|
|
79
|
+
this.applyResponsiveSizing()
|
|
80
|
+
this.reposition()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//drop the "Zoom" label on narrow charts so 1y/All stay fully visible on popular mobile widths
|
|
84
|
+
//instead of clipping at the right edge. Re-run on every redraw via reposition().
|
|
85
|
+
applyResponsiveSizing() {
|
|
86
|
+
const compact = (this.chart.chartWidth || 600) < 420
|
|
87
|
+
if (this.zoomLabel)
|
|
88
|
+
this.zoomLabel.style.display = compact ? 'none' : ''
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
apply(b, i) {
|
|
92
|
+
const xAxis = this.chart.xAxis[0]
|
|
93
|
+
if (b.type === 'all') {
|
|
94
|
+
this.selected = 'all'
|
|
95
|
+
//explicit full extremes so the initial xAxis.range window doesn't re-apply
|
|
96
|
+
xAxis.setExtremes(xAxis.dataMin, xAxis.dataMax)
|
|
97
|
+
} else {
|
|
98
|
+
const count = b.count || 1
|
|
99
|
+
//the window always ENDS at the last data point; going back a calendar
|
|
100
|
+
//month/year/day for the start. Anchoring the end on dataMax keeps the right edge flush with the
|
|
101
|
+
//data instead of snapping forward to the next month boundary (which left a gap on the right).
|
|
102
|
+
const max = xAxis.dataMax
|
|
103
|
+
const d = new Date(max)
|
|
104
|
+
if (b.type === 'year')
|
|
105
|
+
d.setUTCFullYear(d.getUTCFullYear() - count)
|
|
106
|
+
else if (b.type === 'month')
|
|
107
|
+
d.setUTCMonth(d.getUTCMonth() - count)
|
|
108
|
+
else
|
|
109
|
+
d.setUTCDate(d.getUTCDate() - count)
|
|
110
|
+
this.selected = i
|
|
111
|
+
xAxis.setExtremes(d.getTime(), max)
|
|
112
|
+
}
|
|
113
|
+
this.highlight()
|
|
114
|
+
this.reposition()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
highlight() {
|
|
118
|
+
if (!this.buttons)
|
|
119
|
+
return
|
|
120
|
+
this.buttons.forEach(({btn, def, disabled}, i) => {
|
|
121
|
+
const active = (def.type === 'all' && this.selected === 'all') || this.selected === i
|
|
122
|
+
//charts-lib's own state classes (styled in chart.scss)
|
|
123
|
+
btn.classList.toggle('selected', active)
|
|
124
|
+
btn.classList.toggle('disabled', disabled)
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//called after each (re)render to sit above the plot area
|
|
129
|
+
reposition() {
|
|
130
|
+
this.applyResponsiveSizing()
|
|
131
|
+
if (this.el)
|
|
132
|
+
this.el.style.left = (this.chart.plotLeft) + 'px'
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
destroy() {
|
|
136
|
+
if (this.el && this.el.parentNode)
|
|
137
|
+
this.el.parentNode.removeChild(this.el)
|
|
138
|
+
this.el = null
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -219,7 +219,7 @@ export function EffectDescription({effect, operation}) {
|
|
|
219
219
|
case 'contractCodeUploaded':
|
|
220
220
|
case 'contractCodeRestored':
|
|
221
221
|
return <>Contract code {getEffectAction(effect, 'contractCode')}
|
|
222
|
-
<LedgerKeyHint effect={effect}><ContractCodeWasm wasm={effect.
|
|
222
|
+
<LedgerKeyHint effect={effect}><ContractCodeWasm wasm={effect.wasmHash || effect.wasm}/></LedgerKeyHint></>
|
|
223
223
|
case 'contractCreated':
|
|
224
224
|
case 'contractUpdated':
|
|
225
225
|
case 'contractRestored':
|
package/index.d.ts
CHANGED
|
@@ -1269,3 +1269,39 @@ declare global {
|
|
|
1269
1269
|
var explorerApiOrigin: string;
|
|
1270
1270
|
var horizonOrigin: string;
|
|
1271
1271
|
}
|
|
1272
|
+
|
|
1273
|
+
export interface ChartProps {
|
|
1274
|
+
/** Chart data and options */
|
|
1275
|
+
options?: Record<string, any>;
|
|
1276
|
+
/** Chart kind */
|
|
1277
|
+
type?: 'Chart' | 'StockChart';
|
|
1278
|
+
/** Chart title */
|
|
1279
|
+
title?: React.ReactNode;
|
|
1280
|
+
/** Render as inline-block (sparkline charts) */
|
|
1281
|
+
inline?: boolean;
|
|
1282
|
+
/** Apply data grouping */
|
|
1283
|
+
grouped?: boolean;
|
|
1284
|
+
/** Date range / range-selector */
|
|
1285
|
+
range?: true | false | 'year' | 'month';
|
|
1286
|
+
/** Hide the legend section */
|
|
1287
|
+
noLegend?: boolean;
|
|
1288
|
+
/** Container CSS class */
|
|
1289
|
+
container?: string;
|
|
1290
|
+
/** Additional CSS classes */
|
|
1291
|
+
className?: string;
|
|
1292
|
+
/** Inline styles */
|
|
1293
|
+
style?: React.CSSProperties;
|
|
1294
|
+
/** Additional engine modules */
|
|
1295
|
+
modules?: Function[];
|
|
1296
|
+
/** Optional header children */
|
|
1297
|
+
children?: React.ReactNode;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/** Chart component */
|
|
1301
|
+
export const Chart: React.FC<ChartProps>;
|
|
1302
|
+
|
|
1303
|
+
/** Charting engine namespace (Chart, StockChart, setOptions, getOptions, Color, Axis, merge) */
|
|
1304
|
+
export const ChartEngine: Record<string, any>;
|
|
1305
|
+
|
|
1306
|
+
/** Placeholder shown while a chart's data is loading */
|
|
1307
|
+
export const ChartLoader: React.FC<{ title?: React.ReactNode; unavailable?: boolean; container?: string }>;
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stellar-expert/ui-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "StellarExpert shared UI components library",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "./index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"sideEffects": [
|
|
9
|
-
"*.scss"
|
|
9
|
+
"*.scss",
|
|
10
|
+
"./charts/chart-default-options.js"
|
|
10
11
|
],
|
|
11
12
|
"keywords": [
|
|
12
13
|
"StellarExpert",
|
|
@@ -48,6 +49,8 @@
|
|
|
48
49
|
"api/*",
|
|
49
50
|
"asset/*",
|
|
50
51
|
"basic-styles/*",
|
|
52
|
+
"charts/*",
|
|
53
|
+
"charts/**/*",
|
|
51
54
|
"claimable-balance/*",
|
|
52
55
|
"contract/*",
|
|
53
56
|
"controls/*",
|