@tradecanvas/react 1.0.14 → 1.1.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`, `watermarkText`, `onReady(chart)`, `onCrosshairMove`, `className`, `style`.
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`.
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,watermarkText:b,onReady:x,onCrosshairMove:S,className:C,style:w}=i,T=(0,e.useRef)(null),E=(0,e.useRef)(null),D=(0,e.useRef)(new Map),O=(0,e.useRef)({symbol:o,timeframe:s});return(0,e.useImperativeHandle)(a,()=>({getChart:()=>E.current,screenshot:e=>E.current?.screenshot(e),screenshotDataURL:()=>E.current?.screenshotDataURL()??null})),(0,e.useEffect)(()=>{let e=T.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}};b&&(n.watermark={text:b,fontSize:48,color:`rgba(255,255,255,0.03)`});let i=new t.Chart(e,n);if(E.current=i,D.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 x?.(i),()=>{i.disconnectStream(),i.destroy(),E.current=null,D.current.clear()}},[]),(0,e.useEffect)(()=>{let e=E.current;if(!e||d)return;let n=O.current;if(n.symbol===o&&n.timeframe===s)return;O.current={symbol:o,timeframe:s},e.disconnectStream();let r=f??new t.BinanceAdapter;e.connect({adapter:r,symbol:o,timeframe:s,historyLimit:p}),b!==void 0&&e.setWatermark(b)},[o,s,f,p,d,b]),(0,e.useEffect)(()=>{E.current?.setTheme(r(c))},[c]),(0,e.useEffect)(()=>{E.current?.setChartType(l)},[l]),(0,e.useEffect)(()=>{d&&E.current?.setData(d)},[d]),(0,e.useEffect)(()=>{let e=E.current;if(!e)return;let t=D.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&&E.current?.setSignalMarkers(g)},[g]),(0,e.useEffect)(()=>{_&&E.current?.setSignalMarkerStyle(_)},[_]),(0,e.useEffect)(()=>{v&&E.current?.setTradeZones(v)},[v]),(0,e.useEffect)(()=>{y&&E.current?.setTradeZoneStyle(y)},[y]),(0,e.useEffect)(()=>{let e=E.current;!e||!S||e.on(`crosshairMove`,S)},[S]),(0,n.jsx)(`div`,{ref:T,className:C,style:{width:`100%`,height:`100%`,...w}})});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,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;
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} 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 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 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 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":"yJAkDA,SAAS,EAAa,EAAoD,CAGxE,MAFI,CAAC,GAAS,IAAU,OAAe,EAAA,WACnC,IAAU,QAAgB,EAAA,YACvB,EAGT,IAAa,GAAA,EAAA,EAAA,YACX,SAAqB,EAAO,EAAK,CAC/B,GAAM,CACJ,SAAS,UACT,YAAY,KACZ,QAAQ,OACR,YAAY,cACZ,aAAa,EAAE,CACf,OACA,UACA,eAAe,IACf,WACA,YAAY,GACZ,gBACA,oBACA,aACA,iBACA,gBACA,UACA,kBACA,YACA,SACE,EAEE,GAAA,EAAA,EAAA,QAAsC,KAAK,CAC3C,GAAA,EAAA,EAAA,QAAgC,KAAK,CACrC,GAAA,EAAA,EAAA,QAA8C,IAAI,IAAM,CACxD,GAAA,EAAA,EAAA,QAAuB,CAAE,SAAQ,YAAW,CAAC,CAmInD,OAjIA,EAAA,EAAA,qBAAoB,OAAY,CAC9B,aAAgB,EAAS,QACzB,WAAa,GAAsB,EAAS,SAAS,WAAW,EAAS,CACzE,sBAAyB,EAAS,SAAS,mBAAmB,EAAI,KACnE,EAAE,EAEH,EAAA,EAAA,eAAgB,CACd,IAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,EAAW,OAEhB,IAAM,EAAqB,CACzB,YACA,MAAO,EAAa,EAAM,CAC1B,YACA,YAAa,EACb,UAAW,CAAE,KAAM,SAAU,CAC7B,SAAU,CACR,SAAU,GACV,cAAe,GACf,gBAAiB,GACjB,WAAY,GACZ,QAAS,GACT,OAAQ,GACR,OAAQ,GACR,UAAW,GACX,SAAU,GACV,WAAY,GACZ,OAAQ,GACR,aAAc,GACd,SAAU,GACV,UAAW,GACX,GAAG,EACJ,CACF,CAEG,IACF,EAAK,UAAY,CAAE,KAAM,EAAe,SAAU,GAAI,MAAO,yBAA0B,EAGzF,IAAM,EAAQ,IAAI,EAAA,MAAM,EAAW,EAAK,CAIxC,GAHA,EAAS,QAAU,EACnB,EAAgB,QAAU,IAAI,IAE1B,EACF,EAAM,QAAQ,EAAK,KACd,CACL,IAAM,EAAc,GAAW,IAAI,EAAA,eACnC,EAAM,QAAQ,CAAE,QAAS,EAAa,SAAQ,YAAW,eAAc,CAAC,CAK1E,OAFA,IAAU,EAAM,KAEH,CACX,EAAM,kBAAkB,CACxB,EAAM,SAAS,CACf,EAAS,QAAU,KACnB,EAAgB,QAAQ,OAAO,GAGhC,EAAE,CAAC,EAEN,EAAA,EAAA,eAAgB,CACd,IAAM,EAAQ,EAAS,QACvB,GAAI,CAAC,GAAS,EAAM,OACpB,IAAM,EAAO,EAAc,QAC3B,GAAI,EAAK,SAAW,GAAU,EAAK,YAAc,EAAW,OAC5D,EAAc,QAAU,CAAE,SAAQ,YAAW,CAE7C,EAAM,kBAAkB,CACxB,IAAM,EAAc,GAAW,IAAI,EAAA,eACnC,EAAM,QAAQ,CAAE,QAAS,EAAa,SAAQ,YAAW,eAAc,CAAC,CACpE,IAAkB,IAAA,IACpB,EAAM,aAAa,EAAc,EAElC,CAAC,EAAQ,EAAW,EAAS,EAAc,EAAM,EAAc,CAAC,EAEnE,EAAA,EAAA,eAAgB,CACd,EAAS,SAAS,SAAS,EAAa,EAAM,CAAC,EAC9C,CAAC,EAAM,CAAC,EAEX,EAAA,EAAA,eAAgB,CACd,EAAS,SAAS,aAAa,EAAU,EACxC,CAAC,EAAU,CAAC,EAEf,EAAA,EAAA,eAAgB,CACV,GAAM,EAAS,SAAS,QAAQ,EAAK,EACxC,CAAC,EAAK,CAAC,EAEV,EAAA,EAAA,eAAgB,CACd,IAAM,EAAQ,EAAS,QACvB,GAAI,CAAC,EAAO,OACZ,IAAM,EAAU,EAAgB,QAC1B,EAAU,IAAI,IAAI,EAAW,CACnC,IAAK,GAAM,CAAC,EAAM,KAAe,EAC1B,EAAQ,IAAI,EAAK,GACpB,EAAM,gBAAgB,EAAW,CACjC,EAAQ,OAAO,EAAK,EAGxB,IAAK,IAAM,KAAQ,EACjB,GAAI,CAAC,EAAQ,IAAI,EAAK,CAAE,CACtB,IAAM,EAAa,EAAM,aAAa,EAAK,CACvC,GAAY,EAAQ,IAAI,EAAM,EAAW,GAGhD,CAAC,EAAW,CAAC,EAEhB,EAAA,EAAA,eAAgB,CACV,GAAe,EAAS,SAAS,iBAAiB,EAAc,EACnE,CAAC,EAAc,CAAC,EAEnB,EAAA,EAAA,eAAgB,CACV,GAAmB,EAAS,SAAS,qBAAqB,EAAkB,EAC/E,CAAC,EAAkB,CAAC,EAEvB,EAAA,EAAA,eAAgB,CACV,GAAY,EAAS,SAAS,cAAc,EAAW,EAC1D,CAAC,EAAW,CAAC,EAEhB,EAAA,EAAA,eAAgB,CACV,GAAgB,EAAS,SAAS,kBAAkB,EAAe,EACtE,CAAC,EAAe,CAAC,EAEpB,EAAA,EAAA,eAAgB,CACd,IAAM,EAAQ,EAAS,QACnB,CAAC,GAAS,CAAC,GACf,EAAM,GAAG,gBAAiB,EAAwC,EACjE,CAAC,EAAgB,CAAC,EAGnB,EAAA,EAAA,KAAC,MAAD,CACE,IAAK,EACM,YACX,MAAO,CAAE,MAAO,OAAQ,OAAQ,OAAQ,GAAG,EAAO,CAClD,CAAA,EAGP"}
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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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Chart } from '@tradecanvas/chart';
2
+ import { ChartStyleOverrides } from '@tradecanvas/chart';
2
3
  import { ChartType } from '@tradecanvas/chart';
3
4
  import { CSSProperties } from 'react';
4
5
  import { DataAdapter } from '@tradecanvas/chart';
@@ -30,6 +31,8 @@ export declare interface TradeCanvasProps {
30
31
  signalMarkerStyle?: SignalMarkerStyle;
31
32
  tradeZones?: TradeZone[];
32
33
  tradeZoneStyle?: TradeZoneStyle;
34
+ /** Style overrides, by key: all of your app's (`chart.setOverrides`). */
35
+ overrides?: ChartStyleOverrides;
33
36
  watermarkText?: string;
34
37
  onReady?: (chart: Chart) => void;
35
38
  onCrosshairMove?: (payload: unknown) => void;
package/dist/index.js CHANGED
@@ -6,16 +6,16 @@ function l(e) {
6
6
  return !e || e === "dark" ? o : e === "light" ? s : e;
7
7
  }
8
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, watermarkText: C, onReady: w, onCrosshairMove: T, className: E, style: D } = e, O = r(null), k = r(null), A = r(/* @__PURE__ */ new Map()), j = r({
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
10
  symbol: s,
11
11
  timeframe: u
12
12
  });
13
- return n(o, () => ({
14
- getChart: () => k.current,
15
- screenshot: (e) => k.current?.screenshot(e),
16
- screenshotDataURL: () => k.current?.screenshotDataURL() ?? null
13
+ n(o, () => ({
14
+ getChart: () => A.current,
15
+ screenshot: (e) => A.current?.screenshot(e),
16
+ screenshotDataURL: () => A.current?.screenshotDataURL() ?? null
17
17
  })), t(() => {
18
- let e = O.current;
18
+ let e = k.current;
19
19
  if (!e) return;
20
20
  let t = {
21
21
  chartType: f,
@@ -41,13 +41,13 @@ var u = e(function(e, o) {
41
41
  ..._
42
42
  }
43
43
  };
44
- C && (t.watermark = {
45
- text: C,
44
+ w && (t.watermark = {
45
+ text: w,
46
46
  fontSize: 48,
47
47
  color: "rgba(255,255,255,0.03)"
48
48
  });
49
49
  let n = new a(e, t);
50
- if (k.current = n, A.current = /* @__PURE__ */ new Map(), m) n.setData(m);
50
+ if (A.current = n, j.current = /* @__PURE__ */ new Map(), m) n.setData(m);
51
51
  else {
52
52
  let e = h ?? new i();
53
53
  n.connect({
@@ -57,15 +57,15 @@ var u = e(function(e, o) {
57
57
  historyLimit: g
58
58
  });
59
59
  }
60
- return w?.(n), () => {
61
- n.disconnectStream(), n.destroy(), k.current = null, A.current.clear();
60
+ return T?.(n), () => {
61
+ n.disconnectStream(), n.destroy(), A.current = null, j.current.clear();
62
62
  };
63
63
  }, []), t(() => {
64
- let e = k.current;
64
+ let e = A.current;
65
65
  if (!e || m) return;
66
- let t = j.current;
66
+ let t = M.current;
67
67
  if (t.symbol === s && t.timeframe === u) return;
68
- j.current = {
68
+ M.current = {
69
69
  symbol: s,
70
70
  timeframe: u
71
71
  }, e.disconnectStream();
@@ -75,47 +75,51 @@ var u = e(function(e, o) {
75
75
  symbol: s,
76
76
  timeframe: u,
77
77
  historyLimit: g
78
- }), C !== void 0 && e.setWatermark(C);
78
+ }), w !== void 0 && e.setWatermark(w);
79
79
  }, [
80
80
  s,
81
81
  u,
82
82
  h,
83
83
  g,
84
84
  m,
85
- C
85
+ w
86
86
  ]), t(() => {
87
- k.current?.setTheme(l(d));
87
+ A.current?.setTheme(l(d));
88
88
  }, [d]), t(() => {
89
- k.current?.setChartType(f);
89
+ A.current?.setChartType(f);
90
90
  }, [f]), t(() => {
91
- m && k.current?.setData(m);
91
+ m && A.current?.setData(m);
92
92
  }, [m]), t(() => {
93
- let e = k.current;
93
+ let e = A.current;
94
94
  if (!e) return;
95
- let t = A.current, n = new Set(p);
95
+ let t = j.current, n = new Set(p);
96
96
  for (let [r, i] of t) n.has(r) || (e.removeIndicator(i), t.delete(r));
97
97
  for (let n of p) if (!t.has(n)) {
98
98
  let r = e.addIndicator(n);
99
99
  r && t.set(n, r);
100
100
  }
101
101
  }, [p]), t(() => {
102
- y && k.current?.setSignalMarkers(y);
102
+ y && A.current?.setSignalMarkers(y);
103
103
  }, [y]), t(() => {
104
- b && k.current?.setSignalMarkerStyle(b);
104
+ b && A.current?.setSignalMarkerStyle(b);
105
105
  }, [b]), t(() => {
106
- x && k.current?.setTradeZones(x);
106
+ x && A.current?.setTradeZones(x);
107
107
  }, [x]), t(() => {
108
- S && k.current?.setTradeZoneStyle(S);
109
- }, [S]), t(() => {
110
- let e = k.current;
111
- !e || !T || e.on("crosshairMove", T);
112
- }, [T]), /* @__PURE__ */ c("div", {
113
- ref: O,
114
- className: E,
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 ?? {}));
113
+ }, [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,
115
119
  style: {
116
120
  width: "100%",
117
121
  height: "100%",
118
- ...D
122
+ ...O
119
123
  }
120
124
  });
121
125
  });
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} 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 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 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 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} 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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradecanvas/react",
3
- "version": "1.0.14",
3
+ "version": "1.1.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.11.0"
36
+ "@tradecanvas/chart": "1.13.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react": ">=18.0.0",