@@ -68,16 +68,22 @@ export function ChartLegendCompound({
6868 return aggregateValues ( values , aggregation ) ;
6969 } , [ totals , dataKeys , aggregation ] ) ;
7070
71- // Calculate current total based on hover state
72- const currentTotal = useMemo ( ( ) => {
71+ // Calculate current total based on hover state (null when hovering a gap-filled point)
72+ const currentTotal = useMemo ( ( ) : number | null => {
7373 if ( ! highlight . activePayload ?. length ) return grandTotal ;
7474
75- // Collect all series values from the hovered data point
76- const values = highlight . activePayload
75+ // Collect all series values from the hovered data point, preserving nulls
76+ const rawValues = highlight . activePayload
7777 . filter ( ( item ) => item . value !== undefined && dataKeys . includes ( item . dataKey as string ) )
78- . map ( ( item ) => Number ( item . value ) || 0 ) ;
78+ . map ( ( item ) => item . value ) ;
7979
80- if ( values . length === 0 ) return 0 ;
80+ // Filter to non-null values only
81+ const values = rawValues
82+ . filter ( ( v ) : v is number => v != null )
83+ . map ( ( v ) => Number ( v ) || 0 ) ;
84+
85+ // All null → gap-filled point, return null to show dash
86+ if ( values . length === 0 ) return null ;
8187
8288 if ( ! aggregation ) {
8389 // Default: sum
@@ -101,17 +107,21 @@ export function ChartLegendCompound({
101107 return labelFormatter ? labelFormatter ( stringValue ) : stringValue ;
102108 } , [ highlight . activePayload , dataKey , effectiveTotalLabel , labelFormatter ] ) ;
103109
104- // Get current data for the legend based on hover state
105- const currentData = useMemo ( ( ) => {
110+ // Get current data for the legend based on hover state (values may be null for gap-filled points)
111+ const currentData = useMemo ( ( ) : Record < string , number | null > => {
106112 if ( ! highlight . activePayload ?. length ) return totals ;
107113
108- // If we have activePayload data from hovering over a bar
109- const hoverData = highlight . activePayload . reduce ( ( acc , item ) => {
110- if ( item . dataKey && item . value !== undefined ) {
111- acc [ item . dataKey ] = Number ( item . value ) || 0 ;
112- }
113- return acc ;
114- } , { } as Record < string , number > ) ;
114+ // If we have activePayload data from hovering over a bar/line
115+ const hoverData = highlight . activePayload . reduce (
116+ ( acc , item ) => {
117+ if ( item . dataKey && item . value !== undefined ) {
118+ // Preserve null for gap-filled points instead of coercing to 0
119+ acc [ item . dataKey ] = item . value != null ? Number ( item . value ) || 0 : null ;
120+ }
121+ return acc ;
122+ } ,
123+ { } as Record < string , number | null >
124+ ) ;
115125
116126 // Return a merged object - totals for keys not in the hover data
117127 return {
@@ -167,7 +177,11 @@ export function ChartLegendCompound({
167177 >
168178 < span className = "font-medium" > { currentTotalLabel } </ span >
169179 < span className = "font-medium tabular-nums" >
170- < AnimatedNumber value = { currentTotal } duration = { 0.25 } />
180+ { currentTotal != null ? (
181+ < AnimatedNumber value = { currentTotal } duration = { 0.25 } />
182+ ) : (
183+ "\u2013"
184+ ) }
171185 </ span >
172186 </ div >
173187
@@ -183,15 +197,15 @@ export function ChartLegendCompound({
183197 ) }
184198 >
185199 { legendItems . visible . map ( ( item ) => {
186- const total = currentData [ item . dataKey ] ?? 0 ;
200+ const total = currentData [ item . dataKey ] ?? null ;
187201 const isActive = highlight . activeBarKey === item . dataKey ;
188202
189203 return (
190204 < div
191205 key = { item . dataKey }
192206 className = { cn (
193207 "relative flex w-full cursor-pointer items-center justify-between gap-2 rounded px-2 py-1 transition" ,
194- total === 0 && "opacity-50"
208+ ( total == null || total === 0 ) && "opacity-50"
195209 ) }
196210 onMouseEnter = { ( ) => highlight . setHoveredLegendItem ( item . dataKey ) }
197211 onMouseLeave = { ( ) => highlight . reset ( ) }
@@ -221,7 +235,11 @@ export function ChartLegendCompound({
221235 isActive ? "text-text-bright" : "text-text-dimmed"
222236 ) }
223237 >
224- < AnimatedNumber value = { total } duration = { 0.25 } />
238+ { total != null ? (
239+ < AnimatedNumber value = { total } duration = { 0.25 } />
240+ ) : (
241+ "\u2013"
242+ ) }
225243 </ span >
226244 </ div >
227245 </ div >
@@ -233,7 +251,7 @@ export function ChartLegendCompound({
233251 ( legendItems . hoveredHiddenItem ? (
234252 < HoveredHiddenItemRow
235253 item = { legendItems . hoveredHiddenItem }
236- value = { currentData [ legendItems . hoveredHiddenItem . dataKey ] ?? 0 }
254+ value = { currentData [ legendItems . hoveredHiddenItem . dataKey ] ?? null }
237255 remainingCount = { legendItems . remaining - 1 }
238256 />
239257 ) : (
@@ -279,7 +297,7 @@ function ViewAllDataRow({ remainingCount, onViewAll }: ViewAllDataRowProps) {
279297
280298type HoveredHiddenItemRowProps = {
281299 item : { dataKey : string ; color ?: string ; label : React . ReactNode } ;
282- value : number ;
300+ value : number | null ;
283301 remainingCount : number ;
284302} ;
285303
@@ -305,7 +323,7 @@ function HoveredHiddenItemRow({ item, value, remainingCount }: HoveredHiddenItem
305323 { remainingCount > 0 && < span className = "text-text-dimmed" > +{ remainingCount } more</ span > }
306324 </ div >
307325 < span className = "tabular-nums text-text-bright" >
308- < AnimatedNumber value = { value } duration = { 0.25 } />
326+ { value != null ? < AnimatedNumber value = { value } duration = { 0.25 } /> : "\u2013" }
309327 </ span >
310328 </ div >
311329 </ div >
0 commit comments