11import {
22 createOptionsChart ,
33 createSeriesMarkers ,
4- type IPaneApi ,
54 type ISeriesApi ,
65 type SeriesMarker ,
76} from "lightweight-charts" ;
87import {
9- type Accessor ,
108 createContext ,
119 createEffect ,
1210 createMemo ,
@@ -22,10 +20,10 @@ import {
2220} from "solid-js" ;
2321
2422import { SERIES_DEFINITION_MAP } from "./constants" ;
25- import { PriceChartContext , usePriceChart } from "./contexts/chart" ;
2623import type {
2724 BuiltInSeriesType ,
2825 ChartCommonProps ,
26+ ChartContextType ,
2927 ChartWithPaneState ,
3028 CustomSeriesProps ,
3129 IOptionsChartApi ,
@@ -35,6 +33,19 @@ import type {
3533 SeriesPrimitive ,
3634 SeriesProps ,
3735} from "./types" ;
36+ import { attachPanePrimitives , detachPanePrimitives } from "./utils" ;
37+
38+ const PriceChartContext = createContext < ChartContextType < IOptionsChartApi , number > > ( ) ;
39+
40+ export const usePriceChart = ( ) => {
41+ const ctx = useContext ( PriceChartContext ) ;
42+
43+ if ( ! ctx ) {
44+ throw new Error ( "[solid-lightweight-charts] No parent PriceChart component found!" ) ;
45+ }
46+
47+ return ctx ;
48+ } ;
3849
3950type OptionsChartOptions = NonNullable < Parameters < typeof createOptionsChart > [ 1 ] > ;
4051
@@ -48,7 +59,7 @@ type OptionsChartOptions = NonNullable<Parameters<typeof createOptionsChart>[1]>
4859 * @property onCreateChart - Callback invoked with the chart instance after creation
4960 * @property onResize - Callback triggered on manual resize (only if `autoSize: false`)
5061 */
51- type OptionsChartProps = ChartCommonProps < IOptionsChartApi > & OptionsChartOptions ;
62+ type OptionsChartProps = ChartCommonProps < IOptionsChartApi , number > & OptionsChartOptions ;
5263
5364/**
5465 * A SolidJS wrapper component for rendering horizontally price-scaled charts using
@@ -76,27 +87,31 @@ type OptionsChartProps = ChartCommonProps<IOptionsChartApi> & OptionsChartOption
7687export const PriceChart = ( props : ParentProps < OptionsChartProps > ) : JSX . Element => {
7788 let chartContainer ! : HTMLDivElement ;
7889
79- const [ containerProps , options ] = splitProps ( props , [
90+ const _props = mergeProps (
91+ {
92+ autoSize : true ,
93+ width : 0 ,
94+ height : 0 ,
95+ forceRepaintOnResize : false ,
96+ primitives : [ ] as PanePrimitive < number > [ ] ,
97+ } ,
98+ props ,
99+ ) ;
100+
101+ const [ containerProps , options ] = splitProps ( _props , [
80102 "id" ,
81103 "class" ,
82104 "ref" ,
83105 "style" ,
106+ "primitives" ,
107+ "onPrimitivesAttached" ,
108+ "onPrimitivesDetached" ,
84109 "onCreateChart" ,
85110 "onResize" ,
86111 "children" ,
87112 ] ) ;
88113
89- const _options = mergeProps (
90- {
91- autoSize : true ,
92- width : 0 ,
93- height : 0 ,
94- forceRepaintOnResize : false ,
95- } ,
96- options ,
97- ) ;
98-
99- const [ resizeProps , chartOptions ] = splitProps ( _options , [
114+ const [ resizeProps , chartOptions ] = splitProps ( options , [
100115 "width" ,
101116 "height" ,
102117 "forceRepaintOnResize" ,
@@ -105,7 +120,7 @@ export const PriceChart = (props: ParentProps<OptionsChartProps>): JSX.Element =
105120 const [ chart , setChart ] = createSignal < IOptionsChartApi > ( ) ;
106121
107122 onMount ( ( ) => {
108- props . ref ?.( chartContainer ) ;
123+ _props . ref ?.( chartContainer ) ;
109124 const chart = createOptionsChart (
110125 chartContainer ,
111126 chartOptions ,
@@ -133,6 +148,15 @@ export const PriceChart = (props: ParentProps<OptionsChartProps>): JSX.Element =
133148 } ) ;
134149 } ) ;
135150
151+ const primitives = ( ) => _props . primitives ;
152+
153+ const onChartPrimitivesAttached = ( primitives : PanePrimitive < number > [ ] ) => {
154+ containerProps . onPrimitivesAttached ?.( primitives ) ;
155+ } ;
156+ const onChartPrimitivesDetached = ( primitives : PanePrimitive < number > [ ] ) => {
157+ containerProps . onPrimitivesDetached ?.( primitives ) ;
158+ } ;
159+
136160 return (
137161 < >
138162 < div
@@ -143,7 +167,9 @@ export const PriceChart = (props: ParentProps<OptionsChartProps>): JSX.Element =
143167 />
144168 < Show when = { chart ( ) } >
145169 { ( chart ) => (
146- < PriceChartContext . Provider value = { chart } >
170+ < PriceChartContext . Provider
171+ value = { { chart, primitives, onChartPrimitivesAttached, onChartPrimitivesDetached } }
172+ >
147173 { containerProps . children }
148174 </ PriceChartContext . Provider >
149175 ) }
@@ -155,12 +181,12 @@ export const PriceChart = (props: ParentProps<OptionsChartProps>): JSX.Element =
155181const PaneContext = createContext < PaneContextType < number > > ( {
156182 paneIdx : ( ) => 0 ,
157183 panePrimitives : ( ) => [ ] ,
158- attachPanePrimitives : ( ) => { } ,
159- detachPanePrimitives : ( ) => { } ,
184+ onPanePrimitivesAttached : ( ) => { } ,
185+ onPanePrimitivesDetached : ( ) => { } ,
160186} ) ;
161187
162188const Pane = ( props : PaneProps < number > ) => {
163- const chart = usePriceChart ( ) as unknown as Accessor < ChartWithPaneState < IOptionsChartApi > > ;
189+ const { chart } = usePriceChart ( ) ;
164190
165191 const _props = mergeProps (
166192 {
@@ -169,37 +195,22 @@ const Pane = (props: PaneProps<number>) => {
169195 props ,
170196 ) ;
171197
172- const paneIdx = createMemo ( ( ) => _props . index ?? chart ( ) . __getNextPaneIndex ( ) ) ;
198+ const paneIdx = createMemo (
199+ ( ) => _props . index ?? ( chart ( ) as ChartWithPaneState < IOptionsChartApi > ) . __getNextPaneIndex ( ) ,
200+ ) ;
173201 const panePrimitives = ( ) => _props . primitives ;
174202
175- const attachPanePrimitives = ( primitives : PanePrimitive < number > [ ] , pane ?: IPaneApi < number > ) => {
176- if ( ! pane ) return ;
177-
178- // Since pane primitives are reactive, we need to detach them first to avoid unnecessary re-attachments
179- for ( const primitive of primitives ) {
180- pane . detachPrimitive ( primitive ) ;
181- }
182-
183- for ( const primitive of primitives ) {
184- pane . attachPrimitive ( primitive ) ;
185- }
186-
203+ const onPanePrimitivesAttached = ( primitives : PanePrimitive < number > [ ] ) => {
187204 _props . onAttachPrimitives ?.( primitives ) ;
188205 } ;
189206
190- const detachPanePrimitives = ( primitives : PanePrimitive < number > [ ] , pane ?: IPaneApi < number > ) => {
191- if ( ! pane ) return ;
192-
193- for ( const primitive of primitives ) {
194- pane . detachPrimitive ( primitive ) ;
195- }
196-
207+ const onPanePrimitivesDetached = ( primitives : PanePrimitive < number > [ ] ) => {
197208 _props . onDetachPrimitives ?.( primitives ) ;
198209 } ;
199210
200211 return (
201212 < PaneContext . Provider
202- value = { { paneIdx, panePrimitives, attachPanePrimitives , detachPanePrimitives } }
213+ value = { { paneIdx, panePrimitives, onPanePrimitivesAttached , onPanePrimitivesDetached } }
203214 >
204215 { props . children }
205216 </ PaneContext . Provider >
@@ -226,8 +237,13 @@ const Pane = (props: PaneProps<number>) => {
226237PriceChart . Pane = Pane ;
227238
228239const Series = < T extends BuiltInSeriesType > ( props : SeriesProps < T , number > ) => {
229- const chart = usePriceChart ( ) ;
230- const { paneIdx, panePrimitives, attachPanePrimitives, detachPanePrimitives } =
240+ const {
241+ chart,
242+ primitives : chartPrimitives ,
243+ onChartPrimitivesAttached,
244+ onChartPrimitivesDetached,
245+ } = usePriceChart ( ) ;
246+ const { paneIdx, panePrimitives, onPanePrimitivesAttached, onPanePrimitivesDetached } =
231247 useContext ( PaneContext ) ;
232248
233249 const _props = mergeProps (
@@ -270,12 +286,17 @@ const Series = <T extends BuiltInSeriesType>(props: SeriesProps<T, number>) => {
270286 } ) ;
271287
272288 createEffect ( ( ) => {
273- const currentPanePrimitives = panePrimitives ( ) ;
289+ // If paneIdx is 0, use the primitives from the chart context, otherwise use the primitives from the pane context
290+ const currentPanePrimitives = paneIdx ( ) === 0 ? chartPrimitives ( ) : panePrimitives ( ) ;
291+ const attachCallback = paneIdx ( ) === 0 ? onChartPrimitivesAttached : onPanePrimitivesAttached ;
292+ const detachCallback = paneIdx ( ) === 0 ? onChartPrimitivesDetached : onPanePrimitivesDetached ;
274293
275294 attachPanePrimitives ( currentPanePrimitives , seriesPane ) ;
295+ attachCallback ( currentPanePrimitives ) ;
276296
277297 onCleanup ( ( ) => {
278298 detachPanePrimitives ( currentPanePrimitives , seriesPane ) ;
299+ detachCallback ( currentPanePrimitives ) ;
279300 } ) ;
280301 } ) ;
281302
@@ -328,8 +349,13 @@ const Series = <T extends BuiltInSeriesType>(props: SeriesProps<T, number>) => {
328349PriceChart . Series = Series ;
329350
330351const CustomSeries = ( props : CustomSeriesProps < number > ) => {
331- const chart = usePriceChart ( ) ;
332- const { paneIdx, panePrimitives, attachPanePrimitives, detachPanePrimitives } =
352+ const {
353+ chart,
354+ primitives : chartPrimitives ,
355+ onChartPrimitivesAttached,
356+ onChartPrimitivesDetached,
357+ } = usePriceChart ( ) ;
358+ const { paneIdx, panePrimitives, onPanePrimitivesAttached, onPanePrimitivesDetached } =
333359 useContext ( PaneContext ) ;
334360
335361 const _props = mergeProps (
@@ -362,12 +388,17 @@ const CustomSeries = (props: CustomSeriesProps<number>) => {
362388 } ) ;
363389
364390 createEffect ( ( ) => {
365- const currentPanePrimitives = panePrimitives ( ) ;
391+ // If paneIdx is 0, use the primitives from the chart context, otherwise use the primitives from the pane context
392+ const currentPanePrimitives = paneIdx ( ) === 0 ? chartPrimitives ( ) : panePrimitives ( ) ;
393+ const attachCallback = paneIdx ( ) === 0 ? onChartPrimitivesAttached : onPanePrimitivesAttached ;
394+ const detachCallback = paneIdx ( ) === 0 ? onChartPrimitivesDetached : onPanePrimitivesDetached ;
366395
367396 attachPanePrimitives ( currentPanePrimitives , seriesPane ) ;
397+ attachCallback ( currentPanePrimitives ) ;
368398
369399 onCleanup ( ( ) => {
370400 detachPanePrimitives ( currentPanePrimitives , seriesPane ) ;
401+ detachCallback ( currentPanePrimitives ) ;
371402 } ) ;
372403 } ) ;
373404
0 commit comments