@@ -4,14 +4,15 @@ import { composeRefs } from '@radix-ui/react-compose-refs'
44import type { Scope } from '@radix-ui/react-context'
55import { DismissableLayer } from '@radix-ui/react-dismissable-layer'
66import { Slot } from '@radix-ui/react-slot'
7- import { sub , formatDistanceStrict } from 'date-fns'
7+ import { sub , add , Duration } from 'date-fns'
88import React , { useCallback , useMemo , useId , useState , useEffect } from 'react'
99import { useTimeSliceState , type DateRange } from './hooks/use-time-slice-state'
1010import {
1111 useSegmentNavigation ,
1212 buildSegments
1313} from './hooks/use-segment-navigation/use-segment-navigation'
1414import { parseDateInput } from './utils/date-parser'
15+ import { formatTimeRange } from './utils/time-range'
1516
1617export type TimeZone = keyof typeof Timezone
1718
@@ -83,14 +84,28 @@ const TimeSlice: React.FC<TimeSliceProps> = ({
8384
8485 const calculateIsRelative = useCallback ( ( range : DateRange ) : boolean => {
8586 let shouldBeRelative = false
86- if (
87- range . endDate &&
88- new Date ( ) . getTime ( ) - range . endDate . getTime ( ) < 1000 * 60
89- ) {
90- if ( range . endDate . getTime ( ) - new Date ( ) . getTime ( ) <= 1000 * 60 ) {
87+ const nowMs = new Date ( ) . getTime ( )
88+ const THRESHOLD_MS = 5000
89+
90+ if ( range . endDate ) {
91+ const endDateMs = range . endDate . getTime ( )
92+ if (
93+ endDateMs > nowMs - THRESHOLD_MS &&
94+ endDateMs <= nowMs + THRESHOLD_MS
95+ ) {
9196 shouldBeRelative = true
9297 }
9398 }
99+
100+ if ( ! shouldBeRelative && range . startDate && range . endDate ) {
101+ const startDateMs = range . startDate . getTime ( )
102+ const endDateMs = range . endDate . getTime ( )
103+
104+ if ( Math . abs ( startDateMs - nowMs ) <= THRESHOLD_MS && endDateMs > nowMs ) {
105+ shouldBeRelative = true
106+ }
107+ }
108+
94109 return shouldBeRelative
95110 } , [ ] )
96111
@@ -117,17 +132,13 @@ const TimeSlice: React.FC<TimeSliceProps> = ({
117132 startDate ?: Date
118133 endDate ?: Date
119134 isRelative : boolean
120- } ) : string => {
121- if ( ! startDate || ! endDate ) return ''
122- if ( isRelative && endDate > startDate ) {
123- const human = formatDistanceStrict ( startDate , endDate , {
124- roundingMethod : 'round'
125- } )
126- return `Past ${ human } `
127- } else {
128- return buildSegments ( startDate , endDate , timeZone ) . text
129- }
130- } ,
135+ } ) =>
136+ formatTimeRange ( {
137+ start : startDate ,
138+ end : endDate ,
139+ relative : isRelative ,
140+ timeZone
141+ } ) ,
131142 [ timeZone ]
132143 )
133144
@@ -502,11 +513,33 @@ const TimeSliceShortcut = React.forwardRef<
502513 ( e : React . MouseEvent < HTMLDivElement > ) => {
503514 e . preventDefault ( )
504515 const now = new Date ( )
505- const startDate = sub ( now , duration )
506- const endDate = now
516+ let finalStartDate : Date
517+ let finalEndDate : Date
518+
519+ const isFutureIntent = Object . values ( duration ) . some (
520+ ( val ) => val !== undefined && val < 0
521+ )
522+
523+ const normalizedDuration : Duration = { }
524+ ; ( Object . keys ( duration ) as Array < keyof typeof duration > ) . forEach (
525+ ( key ) => {
526+ const value = duration [ key ]
527+ if ( value !== undefined ) {
528+ normalizedDuration [ key ] = Math . abs ( value )
529+ }
530+ }
531+ )
532+
533+ if ( isFutureIntent ) {
534+ finalStartDate = now
535+ finalEndDate = add ( now , normalizedDuration )
536+ } else {
537+ finalStartDate = sub ( now , normalizedDuration )
538+ finalEndDate = now
539+ }
507540
508541 setInternalIsRelative ( true )
509- setDateRange ( { startDate, endDate } )
542+ setDateRange ( { startDate : finalStartDate , endDate : finalEndDate } )
510543 setOpen ( false )
511544 if ( inputRef . current ) {
512545 inputRef . current . blur ( )
0 commit comments