@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 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`, `data`, `adapter`, `historyLimit`, `features`, `autoScale`, `signalMarkers`, `signalMarkerStyle`, `tradeZones`, `tradeZoneStyle`, `overrides` (style overrides by key, all of your app's), `watermarkText`, `onReady(chart)`, `onCrosshairMove`, `className`, `style`.
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:p=500,features:m,autoScale:h=!0,signalMarkers:g,signalMarkerStyle:_,tradeZones:v,tradeZoneStyle:y,overrides:b,watermarkText:x,onReady:S,onCrosshairMove:C,className:w,style:T}=i,E=(0,e.useRef)(null),D=(0,e.useRef)(null),O=(0,e.useRef)(new Map),k=(0,e.useRef)({symbol:o,timeframe:s});(0,e.useImperativeHandle)(a,()=>({getChart:()=>D.current,screenshot:e=>D.current?.screenshot(e),screenshotDataURL:()=>D.current?.screenshotDataURL()??null})),(0,e.useEffect)(()=>{let e=E.current;if(!e)return;let n={chartType:l,theme:r(c),autoScale:h,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,...m}};x&&(n.watermark={text:x,fontSize:48,color:`rgba(255,255,255,0.03)`});let i=new t.Chart(e,n);if(D.current=i,O.current=new Map,d)i.setData(d);else{let e=f??new t.BinanceAdapter;i.connect({adapter:e,symbol:o,timeframe:s,historyLimit:p})}return S?.(i),()=>{i.disconnectStream(),i.destroy(),D.current=null,O.current.clear()}},[]),(0,e.useEffect)(()=>{let e=D.current;if(!e||d)return;let n=k.current;if(n.symbol===o&&n.timeframe===s)return;k.current={symbol:o,timeframe:s},e.disconnectStream();let r=f??new t.BinanceAdapter;e.connect({adapter:r,symbol:o,timeframe:s,historyLimit:p}),x!==void 0&&e.setWatermark(x)},[o,s,f,p,d,x]),(0,e.useEffect)(()=>{D.current?.setTheme(r(c))},[c]),(0,e.useEffect)(()=>{D.current?.setChartType(l)},[l]),(0,e.useEffect)(()=>{d&&D.current?.setData(d)},[d]),(0,e.useEffect)(()=>{let e=D.current;if(!e)return;let t=O.current,n=new Set(u);for(let[r,i]of t)n.has(r)||(e.removeIndicator(i),t.delete(r));for(let n of u)if(!t.has(n)){let r=e.addIndicator(n);r&&t.set(n,r)}},[u]),(0,e.useEffect)(()=>{g&&D.current?.setSignalMarkers(g)},[g]),(0,e.useEffect)(()=>{_&&D.current?.setSignalMarkerStyle(_)},[_]),(0,e.useEffect)(()=>{v&&D.current?.setTradeZones(v)},[v]),(0,e.useEffect)(()=>{y&&D.current?.setTradeZoneStyle(y)},[y]);let A=(0,e.useRef)(!1);return(0,e.useEffect)(()=>{b===void 0&&!A.current||(A.current=b!==void 0,D.current?.setOverrides(b??{}))},[b]),(0,e.useEffect)(()=>{let e=D.current;!e||!C||e.on(`crosshairMove`,C)},[C]),(0,n.jsx)(`div`,{ref:E,className:w,style:{width:`100%`,height:`100%`,...T}})});exports.TradeCanvas=i;
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
@@ -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
- indicators?: string[];
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 c } from "react/jsx-runtime";
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 l(e) {
5
+ function u(e) {
6
6
  return !e || e === "dark" ? o : e === "light" ? s : e;
7
7
  }
8
- var u = e(function(e, o) {
9
- let { symbol: s = "BTCUSDT", timeframe: u = "5m", theme: d = "dark", chartType: f = "candlestick", indicators: p = [], data: m, adapter: h, historyLimit: g = 500, features: _, autoScale: v = !0, signalMarkers: y, signalMarkerStyle: b, tradeZones: x, tradeZoneStyle: S, overrides: C, watermarkText: w, onReady: T, onCrosshairMove: E, className: D, style: O } = e, k = r(null), A = r(null), j = r(/* @__PURE__ */ new Map()), M = r({
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: () => A.current,
15
- screenshot: (e) => A.current?.screenshot(e),
16
- screenshotDataURL: () => A.current?.screenshotDataURL() ?? null
11
+ getChart: () => M.current,
12
+ screenshot: (e) => M.current?.screenshot(e),
13
+ screenshotDataURL: () => M.current?.screenshotDataURL() ?? null
17
14
  })), t(() => {
18
- let e = k.current;
15
+ let e = j.current;
19
16
  if (!e) return;
20
17
  let t = {
21
- chartType: f,
22
- theme: l(d),
23
- autoScale: v,
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
- w && (t.watermark = {
45
- text: w,
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 (A.current = n, j.current = /* @__PURE__ */ new Map(), m) n.setData(m);
51
- else {
52
- let e = h ?? new i();
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: u,
57
- historyLimit: g
58
- });
53
+ timeframe: d,
54
+ historyLimit: v
55
+ }), P.current = `${s}|${d}`;
59
56
  }
60
- return T?.(n), () => {
61
- n.disconnectStream(), n.destroy(), A.current = null, j.current.clear();
57
+ return D?.(n), () => {
58
+ n.disconnectStream(), n.destroy(), M.current = null, N.current.clear();
62
59
  };
63
60
  }, []), t(() => {
64
- let e = A.current;
65
- if (!e || m) return;
66
- let t = M.current;
67
- if (t.symbol === s && t.timeframe === u) return;
68
- M.current = {
69
- symbol: s,
70
- timeframe: u
71
- }, e.disconnectStream();
72
- let n = h ?? new i();
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: u,
77
- historyLimit: g
78
- }), w !== void 0 && e.setWatermark(w);
75
+ timeframe: d,
76
+ historyLimit: v
77
+ }), E !== void 0 && e.setWatermark(E);
79
78
  }, [
80
79
  s,
81
- u,
82
- h,
80
+ d,
83
81
  g,
84
- m,
85
- w
82
+ v,
83
+ h,
84
+ _,
85
+ E
86
86
  ]), t(() => {
87
- A.current?.setTheme(l(d));
88
- }, [d]), t(() => {
89
- A.current?.setChartType(f);
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
- m && A.current?.setData(m);
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
- y && A.current?.setSignalMarkers(y);
103
- }, [y]), t(() => {
104
- b && A.current?.setSignalMarkerStyle(b);
105
- }, [b]), t(() => {
106
- x && A.current?.setTradeZones(x);
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 && A.current?.setTradeZoneStyle(S);
109
- }, [S]);
110
- let N = r(!1);
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
- let e = A.current;
115
- !e || !E || e.on("crosshairMove", E);
116
- }, [E]), /* @__PURE__ */ c("div", {
117
- ref: k,
118
- className: D,
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
- ...O
119
+ ...A
123
120
  }
124
121
  });
125
122
  });
126
123
  //#endregion
127
- export { u as TradeCanvas };
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":"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"}
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.1.0",
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.13.0"
36
+ "@tradecanvas/chart": "1.14.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react": ">=18.0.0",