@@ -1,4 +1,4 @@
import { useMemo } from 'react' ;
import { useMemo , type ReactNode } from 'react' ;
import type {
EarningsRecent ,
FundamentalResponse ,
@@ -13,7 +13,7 @@ interface FundamentalsPanelProps {
/** Favorable / neutral / adverse — always paired with the read text. */
type Tone = 'good' | 'flat' | 'bad' ;
// Horizon tokens (native to the rest of the product) .
// Horizon tokens.
const HZ = {
text : '#EDEEF3' ,
muted : '#9AA0B0' ,
@@ -57,6 +57,22 @@ function money(v: number | null | undefined): string {
function signedPp ( v : number ) : string {
return ` ${ v >= 0 ? '+' : '' } ${ Math . round ( v * 10 ) / 10 } pp ` ;
}
function capitalize ( s : string ) : string {
return s . length ? s [ 0 ] . toUpperCase ( ) + s . slice ( 1 ) : s ;
}
function finiteOrNull ( v : number | null | undefined ) : number | null {
return v != null && Number . isFinite ( v ) ? v : null ;
}
function latestHistory ( metric : MetricItem | undefined ) : number [ ] {
const run : number [ ] = [ ] ;
const history = metric ? . history ? ? [ ] ;
for ( let i = history . length - 1 ; i >= 0 ; i -= 1 ) {
const value = finiteOrNull ( history [ i ] . value ) ;
if ( value == null ) break ;
run . unshift ( value ) ;
}
return run ;
}
/** Parse YYYY-MM-DD as a LOCAL calendar date (no UTC off-by-one west of UTC). */
function parseLocalDate ( s : string ) : Date {
@@ -80,16 +96,14 @@ export function FundamentalsPanel({ data }: FundamentalsPanelProps) {
const hasAny = ( data . metrics ? ? [ ] ) . some ( ( m ) = > m . value != null ) || ! ! val || ! ! earnings ? . next
|| ( earnings ? . recent ? . length ? ? 0 ) > 0 ;
// Operating trend: value vs a truthful reference (prior quarter / prior avg / zero).
const trendRows : { key : string ; label : string ; kind : 'growth' | 'margin' | 'share' } [ ] = [
{ key : 'revenue_growth_yoy' , label : 'Revenue growth' , kind : 'growth' } ,
{ key : 'eps_growth_yoy' , label : 'EPS growth' , kind : 'growth' } ,
{ key : 'operating_margin' , label : 'Operating margin' , kind : 'margin' } ,
{ key : 'fcf_margin' , label : 'FCF margin' , kind : 'margin' } ,
{ key : 'share_count_change_yoy' , label : 'Share count' , kind : 'share' } ,
{ key : 'share_count_change_yoy' , label : 'Share count YoY ' , kind : 'share' } ,
] ;
// Valuation & balance: favorable percentile vs peer median.
const valueRows : {
label : string ; value : number | null ; industry : MetricIndustry | null ;
readKey : string ; fmt : ( v : number | null ) = > string ;
@@ -103,23 +117,25 @@ export function FundamentalsPanel({ data }: FundamentalsPanelProps) {
return (
< section className = "glass p-5" aria-label = "Fundamentals" >
< div className = "mb-1 flex flex-wrap items-baseline justify-between gap-x-3 gap-y-0.5" >
< h3 className = "text-xs font-medium uppercase tracking-widest" style = { { color : HZ.muted } } > Fundamentals < / h3 >
{ data . reads ? . header && (
< p className = "text-[11.5px] sm:text-right" style = { { color : HZ.muted } } > { data . reads . header } < / p >
) }
< / div >
< h3 className = "text-[10px] font-medium uppercase tracking-widest" style = { { color : HZ.muted } } > Fundamentals < / h3 >
{ data . reads ? . header ? (
< p className = "mt-0.5 text-[15px] leading-snug" style = { { color : HZ.text } } >
{ capitalize ( data . reads . header ) }
< / p >
) : ! hasAny ? (
< p className = "mt-1 text-[15px] leading-snug" style = { { color : HZ.muted } } >
No fundamentals reported yet .
< / p >
) : null }
{ ! hasAny ? (
< p className = "mt-3 text-sm" style = { { color : HZ.muted } } > No fundamentals reported yet . < / p >
) : (
{ hasAny && (
< >
< EarningsStrip earnings = { earnings } / >
< div className = "mt-4 grid gap-x-8 gap-y-5 sm:grid-cols-2" >
< div >
< SectionLabel > Operating trend < / SectionLabel >
< div className = "mt-2 space-y-3.5" >
< SectionHead label = "Operating trend" axis = "less favorable ← ref → more favorable" / >
< div className = "mt-2.5 space-y-3.5" >
{ trendRows . map ( ( r ) = > (
< TrendRow key = { r . key } label = { r . label } kind = { r . kind }
metric = { metrics [ r . key ] } read = { reads [ r . key ] } / >
@@ -127,8 +143,8 @@ export function FundamentalsPanel({ data }: FundamentalsPanelProps) {
< / div >
< / div >
< div >
< SectionLabel > Valuation & amp ; balance < / SectionLabel >
< div className = "mt-2 space-y-3.5" >
< SectionHead label = "Valuation & balance" axis = "less favorable ← median → more favorable" / >
< div className = "mt-2.5 space-y-3.5" >
{ valueRows . map ( ( r ) = > (
< ValueRow key = { r . label } { ...r } read = { reads [ r . readKey ] } / >
) ) }
@@ -144,147 +160,158 @@ export function FundamentalsPanel({ data }: FundamentalsPanelProps) {
) ;
}
function SectionLabel ( { children } : { children : React.ReactNode } ) {
return < span className = "text-[10px] font-medium uppercase tracking-widest" style = { { color : HZ.muted } } > { children } < / span > ;
function SectionHead ( { label , axis } : { label : string ; axis : string } ) {
return (
< div className = "flex flex-wrap items-baseline justify-between gap-x-2" >
< span className = "text-[10px] font-medium uppercase tracking-widest" style = { { color : HZ.muted } } > { label } < / span >
< span className = "text-[11px]" style = { { color : HZ.track } } > { axis } < / span >
< / div >
) ;
}
// ---- operating-trend row: value vs reference, shown as a delta rail ----------
function Bullet ( { label , value , rail , comparison } : {
label : string ; value : ReactNode ; rail : ReactNode | null ; comparison : ReactNode ;
} ) {
return (
< div >
< div className = "flex items-baseline justify-between gap-2" >
< span className = "truncate text-sm" style = { { color : HZ.muted } } > { label } < / span >
< span className = "num text-[15px]" style = { { color : HZ.text } } > { value } < / span >
< / div >
{ rail && < div className = "mt-1.5" > { rail } < / div > }
< div className = { rail ? 'mt-1 text-[11.5px] leading-snug' : 'mt-1.5 text-[11.5px] leading-snug' } >
{ comparison }
< / div >
< / div >
) ;
}
// ---- operating-trend row (delta vs reference, favorable = right) ------------
function TrendRow ( { label , kind , metric , read } : {
label : string ; kind : 'growth' | 'margin' | 'share' ;
metric : MetricItem | undefined ; read : string | null | undefined ;
} ) {
const tone = readTone ( read ) ;
const value = metric ? . value ? ? null ;
const history = ( metric ? . history ? ? [ ] ) . map ( ( h ) = > h . value ) . filter ( ( v ) : v is number = > v != null ) ;
const value = finiteOrNull ( metric ? . value ) ;
const history = latestHistory ( metric ) ;
// reference + neutral band per the backend's deterministic rules
let ref : number | null = null ;
let refLabel = '' ;
let refWord = '' ;
let halfRange = 8 ;
let neutral = 2 ;
let favSign = 1 ; // +1: higher is favorable; -1: lower is favorable
if ( kind === 'growth' ) {
ref = history . length >= 2 ? history [ history . length - 2 ] : null ;
refLabel = ref ! = null ? ` prior ${ pct ( ref ) } ` : '' ;
halfRange = 8 ; neutral = 2 ;
refWord = 'prior' ; halfRange = 8 ; neutral = 2 ; favSign = 1 ;
} else if ( kind === 'margin' ) {
const prior = history . slice ( 0 , - 1 ) ;
ref = prior . length ? prior . reduce ( ( a , b ) = > a + b , 0 ) / prior.length : null ;
refLabel = ref ! = null ? ` avg ${ pct ( ref ) } ` : '' ;
halfRange = 4 ; neutral = 1 ;
refWord = 'avg' ; halfRange = 4 ; neutral = 1 ; favSign = 1 ;
} else {
ref = 0 ; refLabel = 'vs zero ' ; halfRange = 5 ; neutral = 1 ;
ref = 0 ; refWord = '' ; halfRange = 5 ; neutral = 1 ; favSign = - 1 ; // buyback (negative) is favorable
}
const delta = value != null && ref != null ? value - ref : null ;
return (
< div >
< div className = "flex items-baseline justify-between gap-2" >
< span className = "truncate text-sm" style = { { color : HZ.muted } } > { label } < / span >
< span className = "num text-sm" style = { { color : HZ.text } } > { pct ( value ) } < / span >
< / div >
< div className = "text-[11.5px] font-medium" style = { { color : toneColor ( tone ) } } > { read ? ? '—' } < / div >
{ delta != null ? (
< div className = "mt-1 flex items-center gap-2" >
< span className = "w-20 shrink-0 text-[10px]" style = { { color : HZ.muted } } > { refLabel } < / span >
< DeltaRail delta = { delta } halfRange = { halfRange } neutral = { neutral } tone = { tone }
ariaLabel = { ` ${ label } ${ pct ( value ) } , ${ refLabel || 'reference' } , change ${ signedPp ( delta ) } , ${ read ? ? 'no read' } ` } / >
< span className = "num w-14 shrink-0 text-right text-[10px]" style = { { color : toneColor ( tone ) } } > { signedPp ( delta ) } < / span >
< / div >
) : (
value == null && < div className = "mt-1 text-[10px]" style = { { color : HZ.track } } > n / a < / div >
const comparison = value == null ? (
< span style = { { color : HZ.track } } > n / a < / span >
) : delta == null ? (
< span style = { { color : HZ.track } } > history n / a < / span >
) : (
< span style = { { color : toneColor ( tone ) } } >
{ kind !== 'share' && (
< span className = "num" > { signedPp ( delta ) } vs { refWord } · < / span >
) }
< / div >
{ read ? ? '—' }
< / span >
) ;
const rail = delta != null
? < DeltaRail favOffset = { favSign * delta } halfRange = { halfRange } neutral = { neutral } tone = { tone }
ariaLabel = { ` ${ label } ${ pct ( value ) } , ${ delta != null ? ` ${ signedPp ( delta ) } vs reference ` : '' } , ${ read ? ? 'no read' } ` } / >
: null ;
return < Bullet label = { label } value = { pct ( value ) } rail = { rail } comparison = { comparison } / > ;
}
/** A c omparison rail centered on a reference line (not a progress bar): a dot at
* the current delta with a bar connecting it back to the reference . */
function DeltaRail ( { delta , halfRange , neutral , tone , ariaLabel } : {
delta : number ; halfRange : number ; neutral : number ; tone : Tone ; ariaLabel : string ;
/** C omparison rail centered on a reference line (not a progress bar). favOffset > 0
* is favorable and moves the dot RIGHT for every metric . */
function DeltaRail ( { favOffset , halfRange , neutral , tone , ariaLabel } : {
favOffset : number ; halfRange : number ; neutral : number ; tone : Tone ; ariaLabel : string ;
} ) {
const clamped = Math . max ( - halfRange , Math . min ( halfRange , delta ) ) ;
const pos = 50 + ( clamped / halfRange ) * 50 ; // %
const clamped = Math . max ( - halfRange , Math . min ( halfRange , favOffset ) ) ;
const pos = 50 + ( clamped / halfRange ) * 50 ;
const barLeft = Math . min ( 50 , pos ) ;
const barWidth = Math . abs ( pos - 50 ) ;
const bandHalf = ( neutral / halfRange ) * 50 ;
const color = toneColor ( tone ) ;
return (
< span className = "relative block h-1.5 flex-1 rounded-full" role = "img" aria-label = { ariaLabel }
< span className = "relative block h-1.5 min-w-[7rem] flex-1 rounded-full" role = "img" aria-label = { ariaLabel }
style = { { background : 'rgba(93,99,115,0.22)' } } >
< span className = "absolute inset-y-0 rounded-full" aria - hidden
style = { { left : ` ${ 50 - bandHalf } % ` , width : ` ${ 2 * bandHalf } % ` , background : 'rgba(93,99,115,0.4)' } } / >
< span className = "absolute inset-y-[-2px] w-px" aria - hidden style = { { left : '50%' , background : 'rgba(237,238,243,0.55)' } } / >
< span className = "absolute inset-y-0 rounded-full" aria - hidden style = { { left : ` ${ barLeft } % ` , width : ` ${ barWidth } % ` , background : color } } / >
< span className = "absolute top-1/2 h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full" aria - hidden
style = { { left : ` ${ pos } % ` , background : color , boxShadow : '0 0 0 2px #11131C' } } / >
< span className = "absolute inset-y-0 rounded-full" aria - hidden style = { { left : ` ${ barLeft } % ` , width : ` ${ barWidth } % ` , background : toneColor ( tone ) } } / >
< Dot pos = { pos } tone = { tone } / >
< / span >
) ;
}
// ---- valuation/balance row: favorable percentile vs peer median -------------
// ---- valuation/balance row ( favorable percentile vs median) --- -------------
function ValueRow ( { label , value , industry , read , fmt } : {
label : string ; value : number | null ; industry : MetricIndustry | null ;
read : string | null | undefined ; fmt : ( v : number | null ) = > string ;
} ) {
const tone = readTone ( read ) ;
return (
< div >
< div className = "flex items-baseline justify-between gap-2" >
< span className = "truncate text-sm" style = { { color : HZ.muted } } > { label } < / span >
< span className = "num text-sm" style = { { color : HZ.text } } > { fmt ( value ) } < / span >
< / div >
{ value == null ? (
< div className = "mt-1 text-[10px]" style = { { color : HZ.track } } > n / a < / div >
) : industry ? (
< >
< div className = "text-[11.5px] font-medium" style = { { color : toneColor ( tone ) } } > { read ? ? 'in line' } < / div >
< div className = "mt-1 flex items-center gap-2" >
< span className = "w-3 text-[9px]" style = { { color : HZ.track } } > 0 < / span >
< PercentileRail percentile = { industry . favorable_percentile } tone = { tone }
ariaLabel = { ` ${ label } : ${ industry . favorable_percentile } th favorable percentile vs ${ industry . label } , median ${ fmt ( industry . median ) } , ${ industry . peer_count } peers ` } / >
< span className = "w-6 text-right text-[9px]" style = { { color : HZ.track } } > 100 < / span >
< / div >
< div className = "mt-0.5 pl-5 text-[10px]" style = { { color : HZ.muted } } >
median { fmt ( industry . median ) } · { industry . peer_count } peers
< / div >
< / >
) : (
< div className = "text-[11px]" style = { { color : HZ.track } } > peers n / a < / div >
) }
< / div >
const safeValue = finiteOrNull ( value ) ;
const rail = safeValue == null || ! industry
? null
: < PercentileRail percentile = { industry . favorable_percentile } tone = { tone }
ariaLabel = { ` ${ label } : ${ industry . favorable_percentile } th favorable percentile vs ${ industry . label } , median ${ fmt ( industry . median ) } , ${ industry . peer_count } peers ` } / > ;
const comparison = safeValue == null ? (
< span style = { { color : HZ.track } } > n / a < / span >
) : industry ? (
< span style = { { color : toneColor ( tone ) } } >
{ read ? ? 'in line' } < span style = { { color : HZ.muted } } > · median { fmt ( industry . median ) } · { industry . peer_count } peers < / span >
< / span >
) : (
< span style = { { color : HZ.track } } > peers n / a < / span >
) ;
return < Bullet label = { label } value = { fmt ( safeValue ) } rail = { rail } comparison = { comparison } / > ;
}
/** P ercentile rail 0-100 with the peer median fixed at 50; right = more favorable
* (the percentile is already polarity-aware). */
/** 0-100 favorable-p ercentile rail with the peer median fixed at 50; right = more favorable. */
function PercentileRail ( { percentile , tone , ariaLabel } : {
percentile : number ; tone : Tone ; ariaLabel : string ;
} ) {
const p = Math . max ( 0 , Math . min ( 100 , percentile ) ) ;
const barLeft = Math . min ( 50 , p ) ;
const barWidth = Math . abs ( p - 50 ) ;
const color = toneColor ( tone ) ;
return (
< span className = "relative block h-1.5 flex-1 rounded-full" role = "img" aria-label = { ariaLabel }
< span className = "relative block h-1.5 min-w-[7rem] flex-1 rounded-full" role = "img" aria-label = { ariaLabel }
style = { { background : 'rgba(93,99,115,0.22)' } } >
< span className = "absolute inset-y-[-2px] w-px" aria - hidden style = { { left : '50%' , background : 'rgba(237,238,243,0.55)' } } / >
< span className = "absolute inset-y-0 rounded-full" aria - hidden style = { { left : ` ${ barLeft } % ` , width : ` ${ barWidth } % ` , background : color } } / >
< span className = "absolute top-1/2 h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full" aria - hidden
style = { { left : ` ${ p } % ` , background : color , boxShadow : '0 0 0 2px #11131C' } } / >
< span className = "absolute inset-y-0 rounded-full" aria - hidden style = { { left : ` ${ barLeft } % ` , width : ` ${ barWidth } % ` , background : toneColor ( tone ) } } / >
< Dot pos = { p } tone = { tone } / >
< / span >
) ;
}
// ---- earnings + provenance (unchanged behavior) ----------------------------
function Dot ( { pos , tone } : { pos : number ; tone : Tone } ) {
return (
< span className = "absolute top-1/2 h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full" aria - hidden
style = { { left : ` ${ pos } % ` , background : toneColor ( tone ) , boxShadow : '0 0 0 2px #11131C' } } / >
) ;
}
// ---- earnings + provenance -------------------------------------------------
function Provenance ( { provenance , priceDate , marketCap } : {
provenance : MetricItem | null ; priceDate : string | null ; marketCap : number | null ;
} ) {
if ( ! provenance ? . period_end && ! priceDate ) return null ;
return (
< p className = "mt-4 border-t border-white/10 pt-2 text-[10 px] leading-relaxed" style = { { color : HZ.track } } >
< p className = "mt-4 border-t border-white/10 pt-2 text-[11 px] leading-relaxed" style = { { color : HZ.track } } >
{ provenance ? . period_end && (
< > SEC filings · latest { shortDate ( provenance . period_end ) }
{ provenance . filed_date && < > ( filed { shortDate ( provenance . filed_date ) } ) < / > } < / >
@@ -301,7 +328,7 @@ function EarningsStrip({ earnings }: { earnings: FundamentalResponse['earnings']
const recent = earnings ? . recent ? ? [ ] ;
const when = next ? ( next . days_until === 0 ? 'today' : ` ${ next . days_until } d ` ) : null ;
return (
< div className = "mt-2 flex flex-wrap items-center justify-between gap-x-4 gap-y-1" >
< div className = "mt-2 flex flex-wrap items-center justify-between gap-x-4 gap-y-1.5 " >
< span className = "text-sm" style = { { color : HZ.text } } >
< span style = { { color : HZ.muted } } > Next earnings < / span >
{ next ? (
@@ -315,26 +342,56 @@ function EarningsStrip({ earnings }: { earnings: FundamentalResponse['earnings']
< span style = { { color : HZ.muted } } > no date < / span >
) }
< / span >
{ recent . length > 0 && (
< span className = "flex items-center gap-1.5" >
< span className = "text-[10px] uppercase tracking-widest" style = { { color : HZ.track } } > Last { recent . length } < / span >
{ recent . slice ( ) . reverse ( ) . map ( ( e , i ) = > < EarningsBar key = { i } e = { e } / > ) }
< / span >
) }
{ recent . length > 0 && < SurpriseSpark recent = { recent } / > }
< / div >
) ;
}
function EarningsBar ( { e } : { e : EarningsRecent } ) {
const beat = e . eps_actual != null && e . eps_estimate != null ? e . eps_actual - e.eps_estimate : null ;
const tone : Tone = beat == null ? 'flat' : beat > 0 ? 'good' : beat < 0 ? 'bad' : 'flat' ;
const label = beat == null ? 'n/a' : beat > 0 ? 'beat' : beat < 0 ? 'miss' : 'in line' ;
const arrow = beat == null ? '·' : beat > 0 ? '▲' : beat < 0 ? '▼' : '– ' ;
/** Four tiny diverging bars around a zero baseline: beat above (cyan), miss below
* (coral), height ~ |surprise %|. Reads as a beat/miss history at a glance. */
function SurpriseSpark ( { recent } : { recent : EarningsRecent [ ] } ) {
const ordered = recent . slice ( ) . reverse ( ) ;
const description = ordered . map ( ( e ) = > {
const surprise = e . surprise_pct ;
const amount = surprise != null ? ` ${ surprise > 0 ? '+' : '' } ${ surprise } % ` : '' ;
return ` ${ e . announce_date } ${ surpriseLabel ( e ) } ${ amount } ` ;
} ) . join ( ', ' ) ;
return (
< span className = "num text-xs" style = { { color : toneColor ( tone ) } }
title = { ` ${ e . announce_date } : ${ label } ${ e . surprise_pct != null ? ` ${ e . surprise_pct > 0 ? '+' : '' } ${ e . surprise_pct } % ` : '' } ` }
aria-label = { ` ${ e . announce_date } ${ label } ` } >
{ arrow }
< span className = "flex items-center gap-2" >
< span className = "text-[10px] uppercase tracking-widest" style = { { color : HZ.track } } >
EPS surprises
< / span >
< span
className = "relative flex h-7 items-center gap-1.5 px-0.5"
role = "img"
tabIndex = { 0 }
title = { description }
aria-label = { ` Recent EPS surprises, oldest to newest: ${ description } ` }
>
< span className = "absolute inset-x-0 top-1/2 h-px" aria - hidden style = { { background : 'rgba(93,99,115,0.5)' } } / >
{ ordered . map ( ( e , i ) = > < SurpriseBar key = { i } e = { e } / > ) }
< / span >
< / span >
) ;
}
function surpriseLabel ( e : EarningsRecent ) : string {
const beat = e . eps_actual != null && e . eps_estimate != null ? e . eps_actual - e.eps_estimate : null ;
return beat == null ? 'n/a' : beat > 0 ? 'beat' : beat < 0 ? 'miss' : 'in line' ;
}
function SurpriseBar ( { e } : { e : EarningsRecent } ) {
const beat = e . eps_actual != null && e . eps_estimate != null ? e . eps_actual - e.eps_estimate : null ;
const tone : Tone = beat == null ? 'flat' : beat > 0 ? 'good' : beat < 0 ? 'bad' : 'flat' ;
const s = e . surprise_pct ;
const mag = s != null ? Math . min ( Math . abs ( s ) , 15 ) / 15 : 0 ; // cap at 15%
const h = beat == null ? 2 : 3 + mag * 9 ; // px
const up = ( beat ? ? 0 ) >= 0 ;
return (
< span className = "relative z-[1] block h-7 w-2"
title = { ` ${ e . announce_date } : ${ surpriseLabel ( e ) } ${ s != null ? ` ${ s > 0 ? '+' : '' } ${ s } % ` : '' } ` } >
< span className = "absolute inset-x-0 rounded-[1px]" aria - hidden
style = { { height : h , background : toneColor ( tone ) , . . . ( up ? { bottom : '50%' } : { top : '50%' } ) } } / >
< / span >
) ;
}