@tradecanvas/react 1.1.0 → 1.2.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/README.md +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +69 -72
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Streams live Binance data by default. Pass `data={bars}` for static OHLC, or `ad
|
|
|
28
28
|
|
|
29
29
|
## Props
|
|
30
30
|
|
|
31
|
-
`symbol`, `timeframe`, `theme` (`'dark'` | `'light'` | `Theme`), `chartType`, `indicators
|
|
31
|
+
`symbol`, `timeframe`, `theme` (`'dark'` | `'light'` | `Theme`), `chartType`, `indicators` (ids, or `{ id, params, position }`), `data` (bars of your own; no stream), `adapter`, `stream` (`false`: no stream of its own), `historyLimit`, `features` (changes apply after mount too), `autoScale`, `signalMarkers`, `signalMarkerStyle`, `tradeZones`, `tradeZoneStyle`, `overrides` (style overrides by key, all of your app's), `watermarkText`, `onReady(chart)`, `onCrosshairMove`, `className`, `style`.
|
|
32
32
|
|
|
33
33
|
## Imperative access
|
|
34
34
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`react`),t=require(`@tradecanvas/chart`),n=require(`react/jsx-runtime`);function r(e){return!e||e===`dark`?t.DARK_THEME:e===`light`?t.LIGHT_THEME:e}var i=(0,e.forwardRef)(function(i,a){let{symbol:o=`BTCUSDT`,timeframe:s=`5m`,theme:c=`dark`,chartType:l=`candlestick`,indicators:u=[],data:d,adapter:f,historyLimit:
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`react`),t=require(`@tradecanvas/chart`),n=require(`react/jsx-runtime`);function r(e){return!e||e===`dark`?t.DARK_THEME:e===`light`?t.LIGHT_THEME:e}var i=(0,e.forwardRef)(function(i,a){let{symbol:o=`BTCUSDT`,timeframe:s=`5m`,theme:c=`dark`,chartType:l=`candlestick`,indicators:u=[],data:d,adapter:f,stream:p=!0,historyLimit:m=500,features:h,autoScale:g=!0,signalMarkers:_,signalMarkerStyle:v,tradeZones:y,tradeZoneStyle:b,overrides:x,watermarkText:S,onReady:C,onCrosshairMove:w,className:T,style:E}=i,D=(0,e.useRef)(null),O=(0,e.useRef)(null),k=(0,e.useRef)(new Map),A=(0,e.useRef)(null),j=(0,e.useRef)(JSON.stringify(h??null));(0,e.useImperativeHandle)(a,()=>({getChart:()=>O.current,screenshot:e=>O.current?.screenshot(e),screenshotDataURL:()=>O.current?.screenshotDataURL()??null})),(0,e.useEffect)(()=>{let e=D.current;if(!e)return;let n={chartType:l,theme:r(c),autoScale:g,rightMargin:5,crosshair:{mode:`magnet`},features:{drawings:!0,drawingMagnet:!0,drawingUndoRedo:!0,indicators:!0,trading:!0,volume:!0,legend:!0,crosshair:!0,keyboard:!0,screenshot:!0,alerts:!0,barCountdown:!0,logScale:!0,watermark:!0,...h}};S&&(n.watermark={text:S,fontSize:48,color:`rgba(255,255,255,0.03)`});let i=new t.Chart(e,n);if(O.current=i,k.current=new Map,d)i.setData(d);else if(p){let e=f??new t.BinanceAdapter;i.connect({adapter:e,symbol:o,timeframe:s,historyLimit:m}),A.current=`${o}|${s}`}return C?.(i),()=>{i.disconnectStream(),i.destroy(),O.current=null,k.current.clear()}},[]),(0,e.useEffect)(()=>{let e=O.current;if(!e)return;if(!p){A.current!==null&&e.disconnectStream(),A.current=null;return}if(d)return;let n=`${o}|${s}`;if(A.current===n)return;A.current=n,e.disconnectStream();let r=f??new t.BinanceAdapter;e.connect({adapter:r,symbol:o,timeframe:s,historyLimit:m}),S!==void 0&&e.setWatermark(S)},[o,s,f,m,d,p,S]),(0,e.useEffect)(()=>{let e=JSON.stringify(h??null);e!==j.current&&(j.current=e,h&&O.current?.setFeatures(h))},[h]),(0,e.useEffect)(()=>{O.current?.setTheme(r(c))},[c]),(0,e.useEffect)(()=>{O.current?.setChartType(l)},[l]),(0,e.useEffect)(()=>{d&&O.current?.setData(d)},[d]),(0,e.useEffect)(()=>{let e=O.current;e&&(0,t.syncIndicators)(e,u,k.current)},[u]),(0,e.useEffect)(()=>{_&&O.current?.setSignalMarkers(_)},[_]),(0,e.useEffect)(()=>{v&&O.current?.setSignalMarkerStyle(v)},[v]),(0,e.useEffect)(()=>{y&&O.current?.setTradeZones(y)},[y]),(0,e.useEffect)(()=>{b&&O.current?.setTradeZoneStyle(b)},[b]);let M=(0,e.useRef)(!1);return(0,e.useEffect)(()=>{x===void 0&&!M.current||(M.current=x!==void 0,O.current?.setOverrides(x??{}))},[x]),(0,e.useEffect)(()=>{let e=O.current;!e||!w||e.on(`crosshairMove`,w)},[w]),(0,n.jsx)(`div`,{ref:D,className:T,style:{width:`100%`,height:`100%`,...E}})});exports.TradeCanvas=i;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/TradeCanvas.tsx"],"sourcesContent":["import { useRef, useEffect, useImperativeHandle, forwardRef, type CSSProperties } from 'react';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n ChartOptions,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n StreamConfig,\n ChartStyleOverrides,\n} from '@tradecanvas/chart';\n\nexport interface TradeCanvasRef {\n getChart(): Chart | null;\n screenshot(filename?: string): void;\n screenshotDataURL(): string | null;\n}\n\nexport interface TradeCanvasProps {\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n indicators?: string[];\n data?: OHLCBar[];\n adapter?: DataAdapter;\n historyLimit?: number;\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n onReady?: (chart: Chart) => void;\n onCrosshairMove?: (payload: unknown) => void;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme | undefined): Theme {\n if (!theme || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme;\n}\n\nexport const TradeCanvas = forwardRef<TradeCanvasRef, TradeCanvasProps>(\n function TradeCanvas(props, ref) {\n const {\n symbol = 'BTCUSDT',\n timeframe = '5m' as TimeFrame,\n theme = 'dark',\n chartType = 'candlestick' as ChartType,\n indicators = [],\n data,\n adapter,\n historyLimit = 500,\n features,\n autoScale = true,\n signalMarkers,\n signalMarkerStyle,\n tradeZones,\n tradeZoneStyle,\n overrides,\n watermarkText,\n onReady,\n onCrosshairMove,\n className,\n style,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const chartRef = useRef<Chart | null>(null);\n const indicatorIdsRef = useRef<Map<string, string>>(new Map());\n const prevStreamRef = useRef({ symbol, timeframe });\n\n useImperativeHandle(ref, () => ({\n getChart: () => chartRef.current,\n screenshot: (filename?: string) => chartRef.current?.screenshot(filename),\n screenshotDataURL: () => chartRef.current?.screenshotDataURL() ?? null,\n }));\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const opts: ChartOptions = {\n chartType,\n theme: resolveTheme(theme),\n autoScale,\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...features,\n },\n };\n\n if (watermarkText) {\n opts.watermark = { text: watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' };\n }\n\n const chart = new Chart(container, opts);\n chartRef.current = chart;\n indicatorIdsRef.current = new Map();\n\n if (data) {\n chart.setData(data);\n } else {\n const dataAdapter = adapter ?? new BinanceAdapter();\n chart.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });\n }\n\n onReady?.(chart);\n\n return () => {\n chart.disconnectStream();\n chart.destroy();\n chartRef.current = null;\n indicatorIdsRef.current.clear();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart || data) return;\n const prev = prevStreamRef.current;\n if (prev.symbol === symbol && prev.timeframe === timeframe) return;\n prevStreamRef.current = { symbol, timeframe };\n\n chart.disconnectStream();\n const dataAdapter = adapter ?? new BinanceAdapter();\n chart.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });\n if (watermarkText !== undefined) {\n chart.setWatermark(watermarkText);\n }\n }, [symbol, timeframe, adapter, historyLimit, data, watermarkText]);\n\n useEffect(() => {\n chartRef.current?.setTheme(resolveTheme(theme));\n }, [theme]);\n\n useEffect(() => {\n chartRef.current?.setChartType(chartType);\n }, [chartType]);\n\n useEffect(() => {\n if (data) chartRef.current?.setData(data);\n }, [data]);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart) return;\n const current = indicatorIdsRef.current;\n const desired = new Set(indicators);\n for (const [name, instanceId] of current) {\n if (!desired.has(name)) {\n chart.removeIndicator(instanceId);\n current.delete(name);\n }\n }\n for (const name of indicators) {\n if (!current.has(name)) {\n const instanceId = chart.addIndicator(name);\n if (instanceId) current.set(name, instanceId);\n }\n }\n }, [indicators]);\n\n useEffect(() => {\n if (signalMarkers) chartRef.current?.setSignalMarkers(signalMarkers);\n }, [signalMarkers]);\n\n useEffect(() => {\n if (signalMarkerStyle) chartRef.current?.setSignalMarkerStyle(signalMarkerStyle);\n }, [signalMarkerStyle]);\n\n useEffect(() => {\n if (tradeZones) chartRef.current?.setTradeZones(tradeZones);\n }, [tradeZones]);\n\n useEffect(() => {\n if (tradeZoneStyle) chartRef.current?.setTradeZoneStyle(tradeZoneStyle);\n }, [tradeZoneStyle]);\n\n // All of the host's overrides: keys left out of the prop are taken away.\n // Without the prop, overrides set through the chart itself are left alone.\n const overridesGiven = useRef(false);\n useEffect(() => {\n if (overrides === undefined && !overridesGiven.current) return;\n overridesGiven.current = overrides !== undefined;\n chartRef.current?.setOverrides(overrides ?? {});\n }, [overrides]);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart || !onCrosshairMove) return;\n chart.on('crosshairMove', onCrosshairMove as (e: unknown) => void);\n }, [onCrosshairMove]);\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={{ width: '100%', height: '100%', ...style }}\n />\n );\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/TradeCanvas.tsx"],"sourcesContent":["import { useRef, useEffect, useImperativeHandle, forwardRef, type CSSProperties } from 'react';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n ChartOptions,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n StreamConfig,\n ChartStyleOverrides,\n IndicatorSpec,\n} from '@tradecanvas/chart';\n\nexport interface TradeCanvasRef {\n getChart(): Chart | null;\n screenshot(filename?: string): void;\n screenshotDataURL(): string | null;\n}\n\nexport interface TradeCanvasProps {\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /** Static bars: the chart shows these, and opens no stream of its own when it has them at mount. */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n onReady?: (chart: Chart) => void;\n onCrosshairMove?: (payload: unknown) => void;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme | undefined): Theme {\n if (!theme || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme;\n}\n\nexport const TradeCanvas = forwardRef<TradeCanvasRef, TradeCanvasProps>(\n function TradeCanvas(props, ref) {\n const {\n symbol = 'BTCUSDT',\n timeframe = '5m' as TimeFrame,\n theme = 'dark',\n chartType = 'candlestick' as ChartType,\n indicators = [],\n data,\n adapter,\n stream = true,\n historyLimit = 500,\n features,\n autoScale = true,\n signalMarkers,\n signalMarkerStyle,\n tradeZones,\n tradeZoneStyle,\n overrides,\n watermarkText,\n onReady,\n onCrosshairMove,\n className,\n style,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const chartRef = useRef<Chart | null>(null);\n const indicatorIdsRef = useRef<Map<string, string>>(new Map());\n /** The stream open now (`symbol|timeframe`), or null. */\n const streamKeyRef = useRef<string | null>(null);\n const featuresRef = useRef(JSON.stringify(features ?? null));\n\n useImperativeHandle(ref, () => ({\n getChart: () => chartRef.current,\n screenshot: (filename?: string) => chartRef.current?.screenshot(filename),\n screenshotDataURL: () => chartRef.current?.screenshotDataURL() ?? null,\n }));\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const opts: ChartOptions = {\n chartType,\n theme: resolveTheme(theme),\n autoScale,\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...features,\n },\n };\n\n if (watermarkText) {\n opts.watermark = { text: watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' };\n }\n\n const chart = new Chart(container, opts);\n chartRef.current = chart;\n indicatorIdsRef.current = new Map();\n\n if (data) {\n chart.setData(data);\n } else if (stream) {\n const dataAdapter = adapter ?? new BinanceAdapter();\n chart.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });\n streamKeyRef.current = `${symbol}|${timeframe}`;\n }\n\n onReady?.(chart);\n\n return () => {\n chart.disconnectStream();\n chart.destroy();\n chartRef.current = null;\n indicatorIdsRef.current.clear();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // A stream of its own while it has no data; `stream={false}` closes it. Data given later leaves it be.\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart) return;\n if (!stream) {\n if (streamKeyRef.current !== null) chart.disconnectStream();\n streamKeyRef.current = null;\n return;\n }\n if (data) return;\n const key = `${symbol}|${timeframe}`;\n if (streamKeyRef.current === key) return;\n streamKeyRef.current = key;\n\n chart.disconnectStream();\n const dataAdapter = adapter ?? new BinanceAdapter();\n chart.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });\n if (watermarkText !== undefined) {\n chart.setWatermark(watermarkText);\n }\n }, [symbol, timeframe, adapter, historyLimit, data, stream, watermarkText]);\n\n useEffect(() => {\n const next = JSON.stringify(features ?? null);\n if (next === featuresRef.current) return;\n featuresRef.current = next;\n if (features) chartRef.current?.setFeatures(features);\n }, [features]);\n\n useEffect(() => {\n chartRef.current?.setTheme(resolveTheme(theme));\n }, [theme]);\n\n useEffect(() => {\n chartRef.current?.setChartType(chartType);\n }, [chartType]);\n\n useEffect(() => {\n if (data) chartRef.current?.setData(data);\n }, [data]);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (chart) syncIndicators(chart, indicators, indicatorIdsRef.current);\n }, [indicators]);\n\n useEffect(() => {\n if (signalMarkers) chartRef.current?.setSignalMarkers(signalMarkers);\n }, [signalMarkers]);\n\n useEffect(() => {\n if (signalMarkerStyle) chartRef.current?.setSignalMarkerStyle(signalMarkerStyle);\n }, [signalMarkerStyle]);\n\n useEffect(() => {\n if (tradeZones) chartRef.current?.setTradeZones(tradeZones);\n }, [tradeZones]);\n\n useEffect(() => {\n if (tradeZoneStyle) chartRef.current?.setTradeZoneStyle(tradeZoneStyle);\n }, [tradeZoneStyle]);\n\n // All of the host's overrides: keys left out of the prop are taken away.\n // Without the prop, overrides set through the chart itself are left alone.\n const overridesGiven = useRef(false);\n useEffect(() => {\n if (overrides === undefined && !overridesGiven.current) return;\n overridesGiven.current = overrides !== undefined;\n chartRef.current?.setOverrides(overrides ?? {});\n }, [overrides]);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart || !onCrosshairMove) return;\n chart.on('crosshairMove', onCrosshairMove as (e: unknown) => void);\n }, [onCrosshairMove]);\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={{ width: '100%', height: '100%', ...style }}\n />\n );\n },\n);\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { CSSProperties } from 'react';
|
|
|
5
5
|
import { DataAdapter } from '@tradecanvas/chart';
|
|
6
6
|
import { FeaturesConfig } from '@tradecanvas/chart';
|
|
7
7
|
import { ForwardRefExoticComponent } from 'react';
|
|
8
|
+
import { IndicatorSpec } from '@tradecanvas/chart';
|
|
8
9
|
import { OHLCBar } from '@tradecanvas/chart';
|
|
9
10
|
import { RefAttributes } from 'react';
|
|
10
11
|
import { SignalMarker } from '@tradecanvas/chart';
|
|
@@ -21,10 +22,15 @@ export declare interface TradeCanvasProps {
|
|
|
21
22
|
timeframe?: TimeFrame;
|
|
22
23
|
theme?: 'dark' | 'light' | Theme;
|
|
23
24
|
chartType?: ChartType;
|
|
24
|
-
|
|
25
|
+
/** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */
|
|
26
|
+
indicators?: IndicatorSpec[];
|
|
27
|
+
/** Static bars: the chart shows these, and opens no stream of its own when it has them at mount. */
|
|
25
28
|
data?: OHLCBar[];
|
|
26
29
|
adapter?: DataAdapter;
|
|
30
|
+
/** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */
|
|
31
|
+
stream?: boolean;
|
|
27
32
|
historyLimit?: number;
|
|
33
|
+
/** What users can do on the chart; changes after mount are applied too (the keys given). */
|
|
28
34
|
features?: FeaturesConfig;
|
|
29
35
|
autoScale?: boolean;
|
|
30
36
|
signalMarkers?: SignalMarker[];
|
package/dist/index.js
CHANGED
|
@@ -1,26 +1,23 @@
|
|
|
1
1
|
import { forwardRef as e, useEffect as t, useImperativeHandle as n, useRef as r } from "react";
|
|
2
|
-
import { BinanceAdapter as i, Chart as a, DARK_THEME as o, LIGHT_THEME as s } from "@tradecanvas/chart";
|
|
3
|
-
import { jsx as
|
|
2
|
+
import { BinanceAdapter as i, Chart as a, DARK_THEME as o, LIGHT_THEME as s, syncIndicators as c } from "@tradecanvas/chart";
|
|
3
|
+
import { jsx as l } from "react/jsx-runtime";
|
|
4
4
|
//#region src/TradeCanvas.tsx
|
|
5
|
-
function
|
|
5
|
+
function u(e) {
|
|
6
6
|
return !e || e === "dark" ? o : e === "light" ? s : e;
|
|
7
7
|
}
|
|
8
|
-
var
|
|
9
|
-
let { symbol: s = "BTCUSDT", timeframe:
|
|
10
|
-
symbol: s,
|
|
11
|
-
timeframe: u
|
|
12
|
-
});
|
|
8
|
+
var d = e(function(e, o) {
|
|
9
|
+
let { symbol: s = "BTCUSDT", timeframe: d = "5m", theme: f = "dark", chartType: p = "candlestick", indicators: m = [], data: h, adapter: g, stream: _ = !0, historyLimit: v = 500, features: y, autoScale: b = !0, signalMarkers: x, signalMarkerStyle: S, tradeZones: C, tradeZoneStyle: w, overrides: T, watermarkText: E, onReady: D, onCrosshairMove: O, className: k, style: A } = e, j = r(null), M = r(null), N = r(/* @__PURE__ */ new Map()), P = r(null), F = r(JSON.stringify(y ?? null));
|
|
13
10
|
n(o, () => ({
|
|
14
|
-
getChart: () =>
|
|
15
|
-
screenshot: (e) =>
|
|
16
|
-
screenshotDataURL: () =>
|
|
11
|
+
getChart: () => M.current,
|
|
12
|
+
screenshot: (e) => M.current?.screenshot(e),
|
|
13
|
+
screenshotDataURL: () => M.current?.screenshotDataURL() ?? null
|
|
17
14
|
})), t(() => {
|
|
18
|
-
let e =
|
|
15
|
+
let e = j.current;
|
|
19
16
|
if (!e) return;
|
|
20
17
|
let t = {
|
|
21
|
-
chartType:
|
|
22
|
-
theme:
|
|
23
|
-
autoScale:
|
|
18
|
+
chartType: p,
|
|
19
|
+
theme: u(f),
|
|
20
|
+
autoScale: b,
|
|
24
21
|
rightMargin: 5,
|
|
25
22
|
crosshair: { mode: "magnet" },
|
|
26
23
|
features: {
|
|
@@ -38,92 +35,92 @@ var u = e(function(e, o) {
|
|
|
38
35
|
barCountdown: !0,
|
|
39
36
|
logScale: !0,
|
|
40
37
|
watermark: !0,
|
|
41
|
-
...
|
|
38
|
+
...y
|
|
42
39
|
}
|
|
43
40
|
};
|
|
44
|
-
|
|
45
|
-
text:
|
|
41
|
+
E && (t.watermark = {
|
|
42
|
+
text: E,
|
|
46
43
|
fontSize: 48,
|
|
47
44
|
color: "rgba(255,255,255,0.03)"
|
|
48
45
|
});
|
|
49
46
|
let n = new a(e, t);
|
|
50
|
-
if (
|
|
51
|
-
else {
|
|
52
|
-
let e =
|
|
47
|
+
if (M.current = n, N.current = /* @__PURE__ */ new Map(), h) n.setData(h);
|
|
48
|
+
else if (_) {
|
|
49
|
+
let e = g ?? new i();
|
|
53
50
|
n.connect({
|
|
54
51
|
adapter: e,
|
|
55
52
|
symbol: s,
|
|
56
|
-
timeframe:
|
|
57
|
-
historyLimit:
|
|
58
|
-
})
|
|
53
|
+
timeframe: d,
|
|
54
|
+
historyLimit: v
|
|
55
|
+
}), P.current = `${s}|${d}`;
|
|
59
56
|
}
|
|
60
|
-
return
|
|
61
|
-
n.disconnectStream(), n.destroy(),
|
|
57
|
+
return D?.(n), () => {
|
|
58
|
+
n.disconnectStream(), n.destroy(), M.current = null, N.current.clear();
|
|
62
59
|
};
|
|
63
60
|
}, []), t(() => {
|
|
64
|
-
let e =
|
|
65
|
-
if (!e
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
61
|
+
let e = M.current;
|
|
62
|
+
if (!e) return;
|
|
63
|
+
if (!_) {
|
|
64
|
+
P.current !== null && e.disconnectStream(), P.current = null;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (h) return;
|
|
68
|
+
let t = `${s}|${d}`;
|
|
69
|
+
if (P.current === t) return;
|
|
70
|
+
P.current = t, e.disconnectStream();
|
|
71
|
+
let n = g ?? new i();
|
|
73
72
|
e.connect({
|
|
74
73
|
adapter: n,
|
|
75
74
|
symbol: s,
|
|
76
|
-
timeframe:
|
|
77
|
-
historyLimit:
|
|
78
|
-
}),
|
|
75
|
+
timeframe: d,
|
|
76
|
+
historyLimit: v
|
|
77
|
+
}), E !== void 0 && e.setWatermark(E);
|
|
79
78
|
}, [
|
|
80
79
|
s,
|
|
81
|
-
|
|
82
|
-
h,
|
|
80
|
+
d,
|
|
83
81
|
g,
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
v,
|
|
83
|
+
h,
|
|
84
|
+
_,
|
|
85
|
+
E
|
|
86
86
|
]), t(() => {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
let e = JSON.stringify(y ?? null);
|
|
88
|
+
e !== F.current && (F.current = e, y && M.current?.setFeatures(y));
|
|
89
|
+
}, [y]), t(() => {
|
|
90
|
+
M.current?.setTheme(u(f));
|
|
90
91
|
}, [f]), t(() => {
|
|
91
|
-
|
|
92
|
-
}, [m]), t(() => {
|
|
93
|
-
let e = A.current;
|
|
94
|
-
if (!e) return;
|
|
95
|
-
let t = j.current, n = new Set(p);
|
|
96
|
-
for (let [r, i] of t) n.has(r) || (e.removeIndicator(i), t.delete(r));
|
|
97
|
-
for (let n of p) if (!t.has(n)) {
|
|
98
|
-
let r = e.addIndicator(n);
|
|
99
|
-
r && t.set(n, r);
|
|
100
|
-
}
|
|
92
|
+
M.current?.setChartType(p);
|
|
101
93
|
}, [p]), t(() => {
|
|
102
|
-
|
|
103
|
-
}, [
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
94
|
+
h && M.current?.setData(h);
|
|
95
|
+
}, [h]), t(() => {
|
|
96
|
+
let e = M.current;
|
|
97
|
+
e && c(e, m, N.current);
|
|
98
|
+
}, [m]), t(() => {
|
|
99
|
+
x && M.current?.setSignalMarkers(x);
|
|
107
100
|
}, [x]), t(() => {
|
|
108
|
-
S &&
|
|
109
|
-
}, [S])
|
|
110
|
-
|
|
111
|
-
return t(() => {
|
|
112
|
-
C === void 0 && !N.current || (N.current = C !== void 0, A.current?.setOverrides(C ?? {}));
|
|
101
|
+
S && M.current?.setSignalMarkerStyle(S);
|
|
102
|
+
}, [S]), t(() => {
|
|
103
|
+
C && M.current?.setTradeZones(C);
|
|
113
104
|
}, [C]), t(() => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
105
|
+
w && M.current?.setTradeZoneStyle(w);
|
|
106
|
+
}, [w]);
|
|
107
|
+
let I = r(!1);
|
|
108
|
+
return t(() => {
|
|
109
|
+
T === void 0 && !I.current || (I.current = T !== void 0, M.current?.setOverrides(T ?? {}));
|
|
110
|
+
}, [T]), t(() => {
|
|
111
|
+
let e = M.current;
|
|
112
|
+
!e || !O || e.on("crosshairMove", O);
|
|
113
|
+
}, [O]), /* @__PURE__ */ l("div", {
|
|
114
|
+
ref: j,
|
|
115
|
+
className: k,
|
|
119
116
|
style: {
|
|
120
117
|
width: "100%",
|
|
121
118
|
height: "100%",
|
|
122
|
-
...
|
|
119
|
+
...A
|
|
123
120
|
}
|
|
124
121
|
});
|
|
125
122
|
});
|
|
126
123
|
//#endregion
|
|
127
|
-
export {
|
|
124
|
+
export { d as TradeCanvas };
|
|
128
125
|
|
|
129
126
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/TradeCanvas.tsx"],"sourcesContent":["import { useRef, useEffect, useImperativeHandle, forwardRef, type CSSProperties } from 'react';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n ChartOptions,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n StreamConfig,\n ChartStyleOverrides,\n} from '@tradecanvas/chart';\n\nexport interface TradeCanvasRef {\n getChart(): Chart | null;\n screenshot(filename?: string): void;\n screenshotDataURL(): string | null;\n}\n\nexport interface TradeCanvasProps {\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n indicators?: string[];\n data?: OHLCBar[];\n adapter?: DataAdapter;\n historyLimit?: number;\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n onReady?: (chart: Chart) => void;\n onCrosshairMove?: (payload: unknown) => void;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme | undefined): Theme {\n if (!theme || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme;\n}\n\nexport const TradeCanvas = forwardRef<TradeCanvasRef, TradeCanvasProps>(\n function TradeCanvas(props, ref) {\n const {\n symbol = 'BTCUSDT',\n timeframe = '5m' as TimeFrame,\n theme = 'dark',\n chartType = 'candlestick' as ChartType,\n indicators = [],\n data,\n adapter,\n historyLimit = 500,\n features,\n autoScale = true,\n signalMarkers,\n signalMarkerStyle,\n tradeZones,\n tradeZoneStyle,\n overrides,\n watermarkText,\n onReady,\n onCrosshairMove,\n className,\n style,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const chartRef = useRef<Chart | null>(null);\n const indicatorIdsRef = useRef<Map<string, string>>(new Map());\n const prevStreamRef = useRef({ symbol, timeframe });\n\n useImperativeHandle(ref, () => ({\n getChart: () => chartRef.current,\n screenshot: (filename?: string) => chartRef.current?.screenshot(filename),\n screenshotDataURL: () => chartRef.current?.screenshotDataURL() ?? null,\n }));\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const opts: ChartOptions = {\n chartType,\n theme: resolveTheme(theme),\n autoScale,\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...features,\n },\n };\n\n if (watermarkText) {\n opts.watermark = { text: watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' };\n }\n\n const chart = new Chart(container, opts);\n chartRef.current = chart;\n indicatorIdsRef.current = new Map();\n\n if (data) {\n chart.setData(data);\n } else {\n const dataAdapter = adapter ?? new BinanceAdapter();\n chart.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });\n }\n\n onReady?.(chart);\n\n return () => {\n chart.disconnectStream();\n chart.destroy();\n chartRef.current = null;\n indicatorIdsRef.current.clear();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart || data) return;\n const prev = prevStreamRef.current;\n if (prev.symbol === symbol && prev.timeframe === timeframe) return;\n prevStreamRef.current = { symbol, timeframe };\n\n chart.disconnectStream();\n const dataAdapter = adapter ?? new BinanceAdapter();\n chart.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });\n if (watermarkText !== undefined) {\n chart.setWatermark(watermarkText);\n }\n }, [symbol, timeframe, adapter, historyLimit, data, watermarkText]);\n\n useEffect(() => {\n chartRef.current?.setTheme(resolveTheme(theme));\n }, [theme]);\n\n useEffect(() => {\n chartRef.current?.setChartType(chartType);\n }, [chartType]);\n\n useEffect(() => {\n if (data) chartRef.current?.setData(data);\n }, [data]);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart) return;\n const current = indicatorIdsRef.current;\n const desired = new Set(indicators);\n for (const [name, instanceId] of current) {\n if (!desired.has(name)) {\n chart.removeIndicator(instanceId);\n current.delete(name);\n }\n }\n for (const name of indicators) {\n if (!current.has(name)) {\n const instanceId = chart.addIndicator(name);\n if (instanceId) current.set(name, instanceId);\n }\n }\n }, [indicators]);\n\n useEffect(() => {\n if (signalMarkers) chartRef.current?.setSignalMarkers(signalMarkers);\n }, [signalMarkers]);\n\n useEffect(() => {\n if (signalMarkerStyle) chartRef.current?.setSignalMarkerStyle(signalMarkerStyle);\n }, [signalMarkerStyle]);\n\n useEffect(() => {\n if (tradeZones) chartRef.current?.setTradeZones(tradeZones);\n }, [tradeZones]);\n\n useEffect(() => {\n if (tradeZoneStyle) chartRef.current?.setTradeZoneStyle(tradeZoneStyle);\n }, [tradeZoneStyle]);\n\n // All of the host's overrides: keys left out of the prop are taken away.\n // Without the prop, overrides set through the chart itself are left alone.\n const overridesGiven = useRef(false);\n useEffect(() => {\n if (overrides === undefined && !overridesGiven.current) return;\n overridesGiven.current = overrides !== undefined;\n chartRef.current?.setOverrides(overrides ?? {});\n }, [overrides]);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart || !onCrosshairMove) return;\n chart.on('crosshairMove', onCrosshairMove as (e: unknown) => void);\n }, [onCrosshairMove]);\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={{ width: '100%', height: '100%', ...style }}\n />\n );\n },\n);\n"],"mappings":";;;;AAqDA,SAAS,EAAa,GAAoD;AAGxE,QAFI,CAAC,KAAS,MAAU,SAAe,IACnC,MAAU,UAAgB,IACvB;;AAGT,IAAa,IAAc,EACzB,SAAqB,GAAO,GAAK;CAC/B,IAAM,EACJ,YAAS,WACT,eAAY,MACZ,WAAQ,QACR,eAAY,eACZ,gBAAa,EAAE,EACf,SACA,YACA,kBAAe,KACf,aACA,eAAY,IACZ,kBACA,sBACA,eACA,mBACA,cACA,kBACA,YACA,oBACA,cACA,aACE,GAEE,IAAe,EAAuB,KAAK,EAC3C,IAAW,EAAqB,KAAK,EACrC,IAAkB,kBAA4B,IAAI,KAAK,CAAC,EACxD,IAAgB,EAAO;EAAE;EAAQ;EAAW,CAAC;AAyHnD,CAvHA,EAAoB,UAAY;EAC9B,gBAAgB,EAAS;EACzB,aAAa,MAAsB,EAAS,SAAS,WAAW,EAAS;EACzE,yBAAyB,EAAS,SAAS,mBAAmB,IAAI;EACnE,EAAE,EAEH,QAAgB;EACd,IAAM,IAAY,EAAa;AAC/B,MAAI,CAAC,EAAW;EAEhB,IAAM,IAAqB;GACzB;GACA,OAAO,EAAa,EAAM;GAC1B;GACA,aAAa;GACb,WAAW,EAAE,MAAM,UAAU;GAC7B,UAAU;IACR,UAAU;IACV,eAAe;IACf,iBAAiB;IACjB,YAAY;IACZ,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,WAAW;IACX,UAAU;IACV,YAAY;IACZ,QAAQ;IACR,cAAc;IACd,UAAU;IACV,WAAW;IACX,GAAG;IACJ;GACF;AAED,EAAI,MACF,EAAK,YAAY;GAAE,MAAM;GAAe,UAAU;GAAI,OAAO;GAA0B;EAGzF,IAAM,IAAQ,IAAI,EAAM,GAAW,EAAK;AAIxC,MAHA,EAAS,UAAU,GACnB,EAAgB,0BAAU,IAAI,KAAK,EAE/B,EACF,GAAM,QAAQ,EAAK;OACd;GACL,IAAM,IAAc,KAAW,IAAI,GAAgB;AACnD,KAAM,QAAQ;IAAE,SAAS;IAAa;IAAQ;IAAW;IAAc,CAAC;;AAK1E,SAFA,IAAU,EAAM,QAEH;AAIX,GAHA,EAAM,kBAAkB,EACxB,EAAM,SAAS,EACf,EAAS,UAAU,MACnB,EAAgB,QAAQ,OAAO;;IAGhC,EAAE,CAAC,EAEN,QAAgB;EACd,IAAM,IAAQ,EAAS;AACvB,MAAI,CAAC,KAAS,EAAM;EACpB,IAAM,IAAO,EAAc;AAC3B,MAAI,EAAK,WAAW,KAAU,EAAK,cAAc,EAAW;AAG5D,EAFA,EAAc,UAAU;GAAE;GAAQ;GAAW,EAE7C,EAAM,kBAAkB;EACxB,IAAM,IAAc,KAAW,IAAI,GAAgB;AAEnD,EADA,EAAM,QAAQ;GAAE,SAAS;GAAa;GAAQ;GAAW;GAAc,CAAC,EACpE,MAAkB,KAAA,KACpB,EAAM,aAAa,EAAc;IAElC;EAAC;EAAQ;EAAW;EAAS;EAAc;EAAM;EAAc,CAAC,EAEnE,QAAgB;AACd,IAAS,SAAS,SAAS,EAAa,EAAM,CAAC;IAC9C,CAAC,EAAM,CAAC,EAEX,QAAgB;AACd,IAAS,SAAS,aAAa,EAAU;IACxC,CAAC,EAAU,CAAC,EAEf,QAAgB;AACd,EAAI,KAAM,EAAS,SAAS,QAAQ,EAAK;IACxC,CAAC,EAAK,CAAC,EAEV,QAAgB;EACd,IAAM,IAAQ,EAAS;AACvB,MAAI,CAAC,EAAO;EACZ,IAAM,IAAU,EAAgB,SAC1B,IAAU,IAAI,IAAI,EAAW;AACnC,OAAK,IAAM,CAAC,GAAM,MAAe,EAC/B,CAAK,EAAQ,IAAI,EAAK,KACpB,EAAM,gBAAgB,EAAW,EACjC,EAAQ,OAAO,EAAK;AAGxB,OAAK,IAAM,KAAQ,EACjB,KAAI,CAAC,EAAQ,IAAI,EAAK,EAAE;GACtB,IAAM,IAAa,EAAM,aAAa,EAAK;AAC3C,GAAI,KAAY,EAAQ,IAAI,GAAM,EAAW;;IAGhD,CAAC,EAAW,CAAC,EAEhB,QAAgB;AACd,EAAI,KAAe,EAAS,SAAS,iBAAiB,EAAc;IACnE,CAAC,EAAc,CAAC,EAEnB,QAAgB;AACd,EAAI,KAAmB,EAAS,SAAS,qBAAqB,EAAkB;IAC/E,CAAC,EAAkB,CAAC,EAEvB,QAAgB;AACd,EAAI,KAAY,EAAS,SAAS,cAAc,EAAW;IAC1D,CAAC,EAAW,CAAC,EAEhB,QAAgB;AACd,EAAI,KAAgB,EAAS,SAAS,kBAAkB,EAAe;IACtE,CAAC,EAAe,CAAC;CAIpB,IAAM,IAAiB,EAAO,GAAM;AAapC,QAZA,QAAgB;AACV,QAAc,KAAA,KAAa,CAAC,EAAe,YAC/C,EAAe,UAAU,MAAc,KAAA,GACvC,EAAS,SAAS,aAAa,KAAa,EAAE,CAAC;IAC9C,CAAC,EAAU,CAAC,EAEf,QAAgB;EACd,IAAM,IAAQ,EAAS;AACnB,GAAC,KAAS,CAAC,KACf,EAAM,GAAG,iBAAiB,EAAwC;IACjE,CAAC,EAAgB,CAAC,EAGnB,kBAAC,OAAD;EACE,KAAK;EACM;EACX,OAAO;GAAE,OAAO;GAAQ,QAAQ;GAAQ,GAAG;GAAO;EAClD,CAAA;EAGP"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/TradeCanvas.tsx"],"sourcesContent":["import { useRef, useEffect, useImperativeHandle, forwardRef, type CSSProperties } from 'react';\nimport {\n Chart,\n BinanceAdapter,\n DARK_THEME,\n LIGHT_THEME,\n syncIndicators,\n} from '@tradecanvas/chart';\nimport type {\n ChartType,\n TimeFrame,\n ChartOptions,\n FeaturesConfig,\n Theme,\n OHLCBar,\n SignalMarker,\n TradeZone,\n SignalMarkerStyle,\n TradeZoneStyle,\n DataAdapter,\n StreamConfig,\n ChartStyleOverrides,\n IndicatorSpec,\n} from '@tradecanvas/chart';\n\nexport interface TradeCanvasRef {\n getChart(): Chart | null;\n screenshot(filename?: string): void;\n screenshotDataURL(): string | null;\n}\n\nexport interface TradeCanvasProps {\n symbol?: string;\n timeframe?: TimeFrame;\n theme?: 'dark' | 'light' | Theme;\n chartType?: ChartType;\n /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */\n indicators?: IndicatorSpec[];\n /** Static bars: the chart shows these, and opens no stream of its own when it has them at mount. */\n data?: OHLCBar[];\n adapter?: DataAdapter;\n /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */\n stream?: boolean;\n historyLimit?: number;\n /** What users can do on the chart; changes after mount are applied too (the keys given). */\n features?: FeaturesConfig;\n autoScale?: boolean;\n signalMarkers?: SignalMarker[];\n signalMarkerStyle?: SignalMarkerStyle;\n tradeZones?: TradeZone[];\n tradeZoneStyle?: TradeZoneStyle;\n /** Style overrides, by key: all of your app's (`chart.setOverrides`). */\n overrides?: ChartStyleOverrides;\n watermarkText?: string;\n onReady?: (chart: Chart) => void;\n onCrosshairMove?: (payload: unknown) => void;\n className?: string;\n style?: CSSProperties;\n}\n\nfunction resolveTheme(theme: 'dark' | 'light' | Theme | undefined): Theme {\n if (!theme || theme === 'dark') return DARK_THEME;\n if (theme === 'light') return LIGHT_THEME;\n return theme;\n}\n\nexport const TradeCanvas = forwardRef<TradeCanvasRef, TradeCanvasProps>(\n function TradeCanvas(props, ref) {\n const {\n symbol = 'BTCUSDT',\n timeframe = '5m' as TimeFrame,\n theme = 'dark',\n chartType = 'candlestick' as ChartType,\n indicators = [],\n data,\n adapter,\n stream = true,\n historyLimit = 500,\n features,\n autoScale = true,\n signalMarkers,\n signalMarkerStyle,\n tradeZones,\n tradeZoneStyle,\n overrides,\n watermarkText,\n onReady,\n onCrosshairMove,\n className,\n style,\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const chartRef = useRef<Chart | null>(null);\n const indicatorIdsRef = useRef<Map<string, string>>(new Map());\n /** The stream open now (`symbol|timeframe`), or null. */\n const streamKeyRef = useRef<string | null>(null);\n const featuresRef = useRef(JSON.stringify(features ?? null));\n\n useImperativeHandle(ref, () => ({\n getChart: () => chartRef.current,\n screenshot: (filename?: string) => chartRef.current?.screenshot(filename),\n screenshotDataURL: () => chartRef.current?.screenshotDataURL() ?? null,\n }));\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const opts: ChartOptions = {\n chartType,\n theme: resolveTheme(theme),\n autoScale,\n rightMargin: 5,\n crosshair: { mode: 'magnet' },\n features: {\n drawings: true,\n drawingMagnet: true,\n drawingUndoRedo: true,\n indicators: true,\n trading: true,\n volume: true,\n legend: true,\n crosshair: true,\n keyboard: true,\n screenshot: true,\n alerts: true,\n barCountdown: true,\n logScale: true,\n watermark: true,\n ...features,\n },\n };\n\n if (watermarkText) {\n opts.watermark = { text: watermarkText, fontSize: 48, color: 'rgba(255,255,255,0.03)' };\n }\n\n const chart = new Chart(container, opts);\n chartRef.current = chart;\n indicatorIdsRef.current = new Map();\n\n if (data) {\n chart.setData(data);\n } else if (stream) {\n const dataAdapter = adapter ?? new BinanceAdapter();\n chart.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });\n streamKeyRef.current = `${symbol}|${timeframe}`;\n }\n\n onReady?.(chart);\n\n return () => {\n chart.disconnectStream();\n chart.destroy();\n chartRef.current = null;\n indicatorIdsRef.current.clear();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // A stream of its own while it has no data; `stream={false}` closes it. Data given later leaves it be.\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart) return;\n if (!stream) {\n if (streamKeyRef.current !== null) chart.disconnectStream();\n streamKeyRef.current = null;\n return;\n }\n if (data) return;\n const key = `${symbol}|${timeframe}`;\n if (streamKeyRef.current === key) return;\n streamKeyRef.current = key;\n\n chart.disconnectStream();\n const dataAdapter = adapter ?? new BinanceAdapter();\n chart.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });\n if (watermarkText !== undefined) {\n chart.setWatermark(watermarkText);\n }\n }, [symbol, timeframe, adapter, historyLimit, data, stream, watermarkText]);\n\n useEffect(() => {\n const next = JSON.stringify(features ?? null);\n if (next === featuresRef.current) return;\n featuresRef.current = next;\n if (features) chartRef.current?.setFeatures(features);\n }, [features]);\n\n useEffect(() => {\n chartRef.current?.setTheme(resolveTheme(theme));\n }, [theme]);\n\n useEffect(() => {\n chartRef.current?.setChartType(chartType);\n }, [chartType]);\n\n useEffect(() => {\n if (data) chartRef.current?.setData(data);\n }, [data]);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (chart) syncIndicators(chart, indicators, indicatorIdsRef.current);\n }, [indicators]);\n\n useEffect(() => {\n if (signalMarkers) chartRef.current?.setSignalMarkers(signalMarkers);\n }, [signalMarkers]);\n\n useEffect(() => {\n if (signalMarkerStyle) chartRef.current?.setSignalMarkerStyle(signalMarkerStyle);\n }, [signalMarkerStyle]);\n\n useEffect(() => {\n if (tradeZones) chartRef.current?.setTradeZones(tradeZones);\n }, [tradeZones]);\n\n useEffect(() => {\n if (tradeZoneStyle) chartRef.current?.setTradeZoneStyle(tradeZoneStyle);\n }, [tradeZoneStyle]);\n\n // All of the host's overrides: keys left out of the prop are taken away.\n // Without the prop, overrides set through the chart itself are left alone.\n const overridesGiven = useRef(false);\n useEffect(() => {\n if (overrides === undefined && !overridesGiven.current) return;\n overridesGiven.current = overrides !== undefined;\n chartRef.current?.setOverrides(overrides ?? {});\n }, [overrides]);\n\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart || !onCrosshairMove) return;\n chart.on('crosshairMove', onCrosshairMove as (e: unknown) => void);\n }, [onCrosshairMove]);\n\n return (\n <div\n ref={containerRef}\n className={className}\n style={{ width: '100%', height: '100%', ...style }}\n />\n );\n },\n);\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradecanvas/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "React component for @tradecanvas/chart — reactive props, ref forwarding, zero boilerplate.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"README.md"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@tradecanvas/chart": "1.
|
|
36
|
+
"@tradecanvas/chart": "1.14.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"react": ">=18.0.0",
|