@tradecanvas/react 1.2.6 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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,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;
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,options:C,onReady:w,onCrosshairMove:T,className:E,style:D}=i,O=(0,e.useRef)(null),k=(0,e.useRef)(null),A=(0,e.useRef)(new Map),j=(0,e.useRef)(null),M=(0,e.useRef)(JSON.stringify(h??null));(0,e.useImperativeHandle)(a,()=>({getChart:()=>k.current,screenshot:e=>k.current?.screenshot(e),screenshotDataURL:()=>k.current?.screenshotDataURL()??null})),(0,e.useEffect)(()=>{let e=O.current;if(!e)return;let n={rightMargin:5,crosshair:{mode:`magnet`},...C,chartType:l,theme:r(c),autoScale:g,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,...C?.features,...h}};S&&(n.watermark={text:S,fontSize:48,color:`rgba(255,255,255,0.03)`});let i=new t.Chart(e,n);if(k.current=i,A.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}),j.current=`${o}|${s}`}return w?.(i),()=>{i.disconnectStream(),i.destroy(),k.current=null,A.current.clear()}},[]),(0,e.useEffect)(()=>{let e=k.current;if(!e)return;if(!p){j.current!==null&&e.disconnectStream(),j.current=null;return}if(d)return;let n=`${o}|${s}`;if(j.current===n)return;j.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!==M.current&&(M.current=e,h&&k.current?.setFeatures(h))},[h]),(0,e.useEffect)(()=>{k.current?.setTheme(r(c))},[c]),(0,e.useEffect)(()=>{k.current?.setChartType(l)},[l]),(0,e.useEffect)(()=>{d&&k.current?.setData(d)},[d]),(0,e.useEffect)(()=>{let e=k.current;e&&(0,t.syncIndicators)(e,u,A.current)},[u]),(0,e.useEffect)(()=>{_&&k.current?.setSignalMarkers(_)},[_]),(0,e.useEffect)(()=>{v&&k.current?.setSignalMarkerStyle(v)},[v]),(0,e.useEffect)(()=>{y&&k.current?.setTradeZones(y)},[y]),(0,e.useEffect)(()=>{b&&k.current?.setTradeZoneStyle(b)},[b]);let N=(0,e.useRef)(!1);return(0,e.useEffect)(()=>{x===void 0&&!N.current||(N.current=x!==void 0,k.current?.setOverrides(x??{}))},[x]),(0,e.useEffect)(()=>{let e=k.current;!e||!T||e.on(`crosshairMove`,T)},[T]),(0,n.jsx)(`div`,{ref:O,className:E,style:{width:`100%`,height:`100%`,...D}})});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 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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"}
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 /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\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 options,\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 rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...options,\n chartType,\n theme: resolveTheme(theme),\n autoScale,\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 ...options?.features,\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
@@ -1,4 +1,5 @@
1
1
  import { Chart } from '@tradecanvas/chart';
2
+ import { ChartOptions } from '@tradecanvas/chart';
2
3
  import { ChartStyleOverrides } from '@tradecanvas/chart';
3
4
  import { ChartType } from '@tradecanvas/chart';
4
5
  import { CSSProperties } from 'react';
@@ -40,6 +41,13 @@ export declare interface TradeCanvasProps {
40
41
  /** Style overrides, by key: all of your app's (`chart.setOverrides`). */
41
42
  overrides?: ChartStyleOverrides;
42
43
  watermarkText?: string;
44
+ /**
45
+ * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,
46
+ * `renderer`…), merged over the component's defaults at mount; later
47
+ * changes are not applied. `chartType`, `theme` and `autoScale` always come
48
+ * from their props.
49
+ */
50
+ options?: Partial<ChartOptions>;
43
51
  onReady?: (chart: Chart) => void;
44
52
  onCrosshairMove?: (payload: unknown) => void;
45
53
  className?: string;
package/dist/index.js CHANGED
@@ -6,20 +6,21 @@ function u(e) {
6
6
  return !e || e === "dark" ? o : e === "light" ? s : e;
7
7
  }
8
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));
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, options: D, onReady: O, onCrosshairMove: k, className: A, style: j } = e, M = r(null), N = r(null), P = r(/* @__PURE__ */ new Map()), F = r(null), I = r(JSON.stringify(y ?? null));
10
10
  n(o, () => ({
11
- getChart: () => M.current,
12
- screenshot: (e) => M.current?.screenshot(e),
13
- screenshotDataURL: () => M.current?.screenshotDataURL() ?? null
11
+ getChart: () => N.current,
12
+ screenshot: (e) => N.current?.screenshot(e),
13
+ screenshotDataURL: () => N.current?.screenshotDataURL() ?? null
14
14
  })), t(() => {
15
- let e = j.current;
15
+ let e = M.current;
16
16
  if (!e) return;
17
17
  let t = {
18
+ rightMargin: 5,
19
+ crosshair: { mode: "magnet" },
20
+ ...D,
18
21
  chartType: p,
19
22
  theme: u(f),
20
23
  autoScale: b,
21
- rightMargin: 5,
22
- crosshair: { mode: "magnet" },
23
24
  features: {
24
25
  drawings: !0,
25
26
  drawingMagnet: !0,
@@ -35,6 +36,7 @@ var d = e(function(e, o) {
35
36
  barCountdown: !0,
36
37
  logScale: !0,
37
38
  watermark: !0,
39
+ ...D?.features,
38
40
  ...y
39
41
  }
40
42
  };
@@ -44,7 +46,7 @@ var d = e(function(e, o) {
44
46
  color: "rgba(255,255,255,0.03)"
45
47
  });
46
48
  let n = new a(e, t);
47
- if (M.current = n, N.current = /* @__PURE__ */ new Map(), h) n.setData(h);
49
+ if (N.current = n, P.current = /* @__PURE__ */ new Map(), h) n.setData(h);
48
50
  else if (_) {
49
51
  let e = g ?? new i();
50
52
  n.connect({
@@ -52,22 +54,22 @@ var d = e(function(e, o) {
52
54
  symbol: s,
53
55
  timeframe: d,
54
56
  historyLimit: v
55
- }), P.current = `${s}|${d}`;
57
+ }), F.current = `${s}|${d}`;
56
58
  }
57
- return D?.(n), () => {
58
- n.disconnectStream(), n.destroy(), M.current = null, N.current.clear();
59
+ return O?.(n), () => {
60
+ n.disconnectStream(), n.destroy(), N.current = null, P.current.clear();
59
61
  };
60
62
  }, []), t(() => {
61
- let e = M.current;
63
+ let e = N.current;
62
64
  if (!e) return;
63
65
  if (!_) {
64
- P.current !== null && e.disconnectStream(), P.current = null;
66
+ F.current !== null && e.disconnectStream(), F.current = null;
65
67
  return;
66
68
  }
67
69
  if (h) return;
68
70
  let t = `${s}|${d}`;
69
- if (P.current === t) return;
70
- P.current = t, e.disconnectStream();
71
+ if (F.current === t) return;
72
+ F.current = t, e.disconnectStream();
71
73
  let n = g ?? new i();
72
74
  e.connect({
73
75
  adapter: n,
@@ -85,38 +87,38 @@ var d = e(function(e, o) {
85
87
  E
86
88
  ]), t(() => {
87
89
  let e = JSON.stringify(y ?? null);
88
- e !== F.current && (F.current = e, y && M.current?.setFeatures(y));
90
+ e !== I.current && (I.current = e, y && N.current?.setFeatures(y));
89
91
  }, [y]), t(() => {
90
- M.current?.setTheme(u(f));
92
+ N.current?.setTheme(u(f));
91
93
  }, [f]), t(() => {
92
- M.current?.setChartType(p);
94
+ N.current?.setChartType(p);
93
95
  }, [p]), t(() => {
94
- h && M.current?.setData(h);
96
+ h && N.current?.setData(h);
95
97
  }, [h]), t(() => {
96
- let e = M.current;
97
- e && c(e, m, N.current);
98
+ let e = N.current;
99
+ e && c(e, m, P.current);
98
100
  }, [m]), t(() => {
99
- x && M.current?.setSignalMarkers(x);
101
+ x && N.current?.setSignalMarkers(x);
100
102
  }, [x]), t(() => {
101
- S && M.current?.setSignalMarkerStyle(S);
103
+ S && N.current?.setSignalMarkerStyle(S);
102
104
  }, [S]), t(() => {
103
- C && M.current?.setTradeZones(C);
105
+ C && N.current?.setTradeZones(C);
104
106
  }, [C]), t(() => {
105
- w && M.current?.setTradeZoneStyle(w);
107
+ w && N.current?.setTradeZoneStyle(w);
106
108
  }, [w]);
107
- let I = r(!1);
109
+ let L = r(!1);
108
110
  return t(() => {
109
- T === void 0 && !I.current || (I.current = T !== void 0, M.current?.setOverrides(T ?? {}));
111
+ T === void 0 && !L.current || (L.current = T !== void 0, N.current?.setOverrides(T ?? {}));
110
112
  }, [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,
113
+ let e = N.current;
114
+ !e || !k || e.on("crosshairMove", k);
115
+ }, [k]), /* @__PURE__ */ l("div", {
116
+ ref: M,
117
+ className: A,
116
118
  style: {
117
119
  width: "100%",
118
120
  height: "100%",
119
- ...A
121
+ ...j
120
122
  }
121
123
  });
122
124
  });
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 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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"}
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 /**\n * Chart options the props don't cover (`maxBarSpacing`, `rightMargin`,\n * `renderer`…), merged over the component's defaults at mount; later\n * changes are not applied. `chartType`, `theme` and `autoScale` always come\n * from their props.\n */\n options?: Partial<ChartOptions>;\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 options,\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 rightMargin: 5,\n crosshair: { mode: 'magnet' },\n ...options,\n chartType,\n theme: resolveTheme(theme),\n autoScale,\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 ...options?.features,\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,9 +1,13 @@
1
1
  {
2
2
  "name": "@tradecanvas/react",
3
- "version": "1.2.6",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "description": "React component for @tradecanvas/chart — reactive props, ref forwarding, zero boilerplate.",
6
6
  "license": "MIT",
7
+ "funding": {
8
+ "type": "github",
9
+ "url": "https://github.com/sponsors/bonguynvan"
10
+ },
7
11
  "repository": {
8
12
  "type": "git",
9
13
  "url": "https://github.com/bonguynvan/tradecanvas.git",
@@ -33,7 +37,7 @@
33
37
  "README.md"
34
38
  ],
35
39
  "dependencies": {
36
- "@tradecanvas/chart": "1.18.1"
40
+ "@tradecanvas/chart": "1.19.1"
37
41
  },
38
42
  "peerDependencies": {
39
43
  "react": ">=18.0.0",