11import { GlobeAltIcon , GlobeAmericasIcon } from "@heroicons/react/20/solid" ;
22import { Laptop } from "lucide-react" ;
3- import { Fragment , type ReactNode , useSyncExternalStore } from "react" ;
3+ import { Fragment , memo , type ReactNode , useMemo , useSyncExternalStore } from "react" ;
44import { CopyButton } from "./CopyButton" ;
55import { useLocales } from "./LocaleProvider" ;
66import { Paragraph } from "./Paragraph" ;
@@ -63,16 +63,7 @@ export const DateTime = ({
6363 const locales = useLocales ( ) ;
6464 const localTimeZone = useLocalTimeZone ( ) ;
6565
66- const realDate = typeof date === "string" ? new Date ( date ) : date ;
67-
68- const tooltipContent = (
69- < TooltipContent
70- realDate = { realDate }
71- timeZone = { timeZone }
72- localTimeZone = { localTimeZone }
73- locales = { locales }
74- />
75- ) ;
66+ const realDate = useMemo ( ( ) => ( typeof date === "string" ? new Date ( date ) : date ) , [ date ] ) ;
7667
7768 const formattedDateTime = (
7869 < Fragment >
@@ -90,7 +81,20 @@ export const DateTime = ({
9081
9182 if ( ! showTooltip ) return formattedDateTime ;
9283
93- return < SimpleTooltip button = { formattedDateTime } content = { tooltipContent } side = "right" /> ;
84+ return (
85+ < SimpleTooltip
86+ button = { formattedDateTime }
87+ content = {
88+ < TooltipContent
89+ realDate = { realDate }
90+ timeZone = { timeZone }
91+ localTimeZone = { localTimeZone }
92+ locales = { locales }
93+ />
94+ }
95+ side = "right"
96+ />
97+ ) ;
9498} ;
9599
96100export function formatDateTime (
@@ -224,7 +228,7 @@ function formatTimeOnly(
224228 } ) . format ( date ) ;
225229}
226230
227- export const DateTimeAccurate = ( {
231+ const DateTimeAccurateInner = ( {
228232 date,
229233 timeZone = "UTC" ,
230234 previousDate = null ,
@@ -242,13 +246,15 @@ export const DateTimeAccurate = ({
242246 : null ;
243247
244248 // Smart formatting based on whether date changed
245- const formattedDateTime = hideDate
246- ? formatTimeOnly ( realDate , localTimeZone , locales , hour12 )
247- : realPrevDate
248- ? isSameDay ( realDate , realPrevDate )
249+ const formattedDateTime = useMemo ( ( ) => {
250+ return hideDate
249251 ? formatTimeOnly ( realDate , localTimeZone , locales , hour12 )
250- : formatDateTimeAccurate ( realDate , localTimeZone , locales , hour12 )
251- : formatDateTimeAccurate ( realDate , localTimeZone , locales , hour12 ) ;
252+ : realPrevDate
253+ ? isSameDay ( realDate , realPrevDate )
254+ ? formatTimeOnly ( realDate , localTimeZone , locales , hour12 )
255+ : formatDateTimeAccurate ( realDate , localTimeZone , locales , hour12 )
256+ : formatDateTimeAccurate ( realDate , localTimeZone , locales , hour12 ) ;
257+ } , [ realDate , localTimeZone , locales , hour12 , hideDate , previousDate ] ) ;
252258
253259 if ( ! showTooltip )
254260 return < Fragment > { formattedDateTime . replace ( / \s / g, String . fromCharCode ( 32 ) ) } </ Fragment > ;
@@ -271,6 +277,28 @@ export const DateTimeAccurate = ({
271277 ) ;
272278} ;
273279
280+ function areDateTimePropsEqual ( prev : DateTimeProps , next : DateTimeProps ) : boolean {
281+ // Compare Date objects by timestamp value, not reference
282+ const prevTime = prev . date instanceof Date ? prev . date . getTime ( ) : prev . date ;
283+ const nextTime = next . date instanceof Date ? next . date . getTime ( ) : next . date ;
284+ if ( prevTime !== nextTime ) return false ;
285+
286+ const prevPrevTime =
287+ prev . previousDate instanceof Date ? prev . previousDate . getTime ( ) : prev . previousDate ;
288+ const nextPrevTime =
289+ next . previousDate instanceof Date ? next . previousDate . getTime ( ) : next . previousDate ;
290+ if ( prevPrevTime !== nextPrevTime ) return false ;
291+
292+ return (
293+ prev . timeZone === next . timeZone &&
294+ prev . showTooltip === next . showTooltip &&
295+ prev . hideDate === next . hideDate &&
296+ prev . hour12 === next . hour12
297+ ) ;
298+ }
299+
300+ export const DateTimeAccurate = memo ( DateTimeAccurateInner , areDateTimePropsEqual ) ;
301+
274302function formatDateTimeAccurate (
275303 date : Date ,
276304 timeZone : string ,
@@ -333,14 +361,17 @@ function DateTimeTooltipContent({
333361 isoDateTime,
334362 icon,
335363} : DateTimeTooltipContentProps ) {
336- const getUtcOffset = ( ) => {
337- if ( title !== "Local" ) return "" ;
338- const offset = - new Date ( ) . getTimezoneOffset ( ) ;
339- const sign = offset >= 0 ? "+" : "-" ;
340- const hours = Math . abs ( Math . floor ( offset / 60 ) ) ;
341- const minutes = Math . abs ( offset % 60 ) ;
342- return `(UTC ${ sign } ${ hours } ${ minutes ? `:${ minutes . toString ( ) . padStart ( 2 , "0" ) } ` : "" } )` ;
343- } ;
364+ const getUtcOffset = useMemo (
365+ ( ) => ( ) => {
366+ if ( title !== "Local" ) return "" ;
367+ const offset = - new Date ( ) . getTimezoneOffset ( ) ;
368+ const sign = offset >= 0 ? "+" : "-" ;
369+ const hours = Math . abs ( Math . floor ( offset / 60 ) ) ;
370+ const minutes = Math . abs ( offset % 60 ) ;
371+ return `(UTC ${ sign } ${ hours } ${ minutes ? `:${ minutes . toString ( ) . padStart ( 2 , "0" ) } ` : "" } )` ;
372+ } ,
373+ [ title ]
374+ ) ;
344375
345376 return (
346377 < div className = "flex flex-col gap-1" >
0 commit comments