date-fns#set TypeScript Examples
The following examples show how to use
date-fns#set.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Insights.ts From nyxo-app with GNU General Public License v3.0 | 6 votes |
dummyInsights: InsightState = {
bedTimeWindow: {
start: set(new Date(), { hours: 22, minutes: 0, seconds: 0 }).toISOString(),
end: set(new Date(), {
hours: 23,
minutes: 30,
seconds: 0
}).toISOString(),
center: set(new Date(), {
hours: 22,
minutes: 45,
seconds: 0
}).toISOString()
}
}
Example #2
Source File: DateTimeUtils.ts From UUI with MIT License | 5 votes |
export function getZeroDate() {
return set(new Date(0), { hours: 0 })
}
Example #3
Source File: DateTimePicker.tsx From UUI with MIT License | 4 votes |
DateTimePicker = UUIFunctionComponent({
name: 'DateTimePicker',
nodes: {
Root: 'div',
CalendarIcon: Icons.Calendar,
Popover: UUIPopover,
TextField: UUITextField,
Activator: 'div',
Container: 'div',
Toolbar: 'div',
Main: 'div',
SelectZone: 'div',
Section: 'div',
YearMonthSelect: UUIYearMonthSelect,
DateSelect: UUIDateSelect,
TimeSelect: UUITimeSelect,
DateTimeShortcut: UUIDateTimeShortcut,
},
propTypes: DateTimePickerPropTypes,
}, (props: DateTimePickerFeatureProps, { nodes }) => {
const {
Root, CalendarIcon, Popover, TextField,
Activator, Container, Main, SelectZone, Section,
YearMonthSelect, DateSelect, TimeSelect, DateTimeShortcut,
} = nodes
const timeSelectRef = useRef<any | null>(null)
const [active, setActive] = useState(false)
const [yearMonth, setYearMonth] = useState<Date>(props.value || new Date())
const initialInnerValue = useMemo(() => {
return {
date: props.value,
input: props.value === null ? '' : formatDateTime(props.value),
}
}, [props.value])
const [innerValue, setInnerValue, resetInnerValue] = usePendingValue<DateTimePickerInnerValue>(initialInnerValue, (value) => {
props.onChange(value.date)
}, { resetWhenInitialValueChanged: true })
const timeSelectScrollToValue = useCallback((value: Date, animate?: boolean) => {
if (timeSelectRef.current) {
timeSelectRef.current.scrollToValue(value, animate)
}
}, [])
const openPopover = useCallback(() => { setActive(true) }, [])
const closePopover = useCallback(() => { setActive(false) }, [])
const handleUserValueChange = useCallback((value: Date | null) => {
props.onChange(value)
setYearMonth(value || new Date())
}, [props])
const handleUserInputChange = useCallback((value: string) => {
if (value === '') {
handleUserValueChange(null)
timeSelectScrollToValue(getZeroDate())
} else {
setInnerValue((oldValue) => ({ ...oldValue, input: value }))
}
}, [handleUserValueChange, setInnerValue, timeSelectScrollToValue])
const handleUserInputCommit = useCallback(() => {
const input = innerValue.input
if (input === '') return;
const originalInput = formatDateTime(innerValue.date)
if (originalInput === input) return;
try {
const result = tryParseDateTimeFromString(input)
handleUserValueChange(result)
timeSelectScrollToValue(result)
} catch {
resetInnerValue()
}
}, [handleUserValueChange, innerValue, resetInnerValue, timeSelectScrollToValue])
const handleDateSelect = useCallback((value: Date) => {
setInnerValue((oldValue) => {
const newDate = set(oldValue.date || getZeroDate(), {
year: value.getFullYear(),
month: value.getMonth(),
date: value.getDate(),
})
const newInput = formatDateTime(newDate)
return { date: newDate, input: newInput }
})
}, [setInnerValue])
const handleTimeSelect = useCallback((value: Date) => {
setInnerValue((oldValue) => {
const newDate = set(oldValue.date || new Date(), {
hours: value.getHours(),
minutes: value.getMinutes(),
seconds: value.getSeconds(),
milliseconds: value.getMilliseconds(),
})
const newInput = formatDateTime(newDate)
return { date: newDate, input: newInput }
})
}, [setInnerValue])
const handleShortcutSelect = useCallback((date: Date) => {
props.onChange(date)
timeSelectScrollToValue(date || getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}, [closePopover, props, timeSelectScrollToValue])
return (
<Root>
<Popover
placement={'bottom-start'}
active={active}
onClickAway={() => {
resetInnerValue();
timeSelectScrollToValue(props.value || getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
activator={
<Activator>
<TextField
placeholder={props.placeholder}
value={innerValue.input}
onChange={handleUserInputChange}
customize={{
Root: {
onClick: () => {
openPopover()
}
},
Input: {
onBlur: () => {
handleUserInputCommit()
},
onKeyDown: (event) => {
if (event.key === 'Enter') {
handleUserInputCommit()
}
}
}
}}
/>
<CalendarIcon />
</Activator>
}
>
<Container>
<Main>
{props.shortcuts && (
<DateTimeShortcut
options={props.shortcuts}
onSelect={handleShortcutSelect}
/>
)}
<SelectZone>
<YearMonthSelect
value={yearMonth}
onChange={(value) => { setYearMonth(value) }}
/>
<Section>
<DateSelect
yearMonth={yearMonth}
selectedDates={innerValue.date ? [innerValue.date] : []}
onSelect={handleDateSelect}
/>
<TimeSelect
ref={timeSelectRef}
value={innerValue.date || getZeroDate()}
onChange={handleTimeSelect}
/>
</Section>
</SelectZone>
</Main>
<PickerButtons
// confirmLabel={props.confirmLabel}
// cancelLabel={props.cancelLabel}
onCancel={() => {
resetInnerValue()
timeSelectScrollToValue(props.value || getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
onConfirm={() => {
setInnerValue((value) => value, true)
timeSelectScrollToValue(innerValue.date || getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
/>
</Container>
</Popover>
</Root>
)
})
Example #4
Source File: DateTimeRangePicker.tsx From UUI with MIT License | 4 votes |
DateTimeRangePicker = UUIFunctionComponent({
name: 'DateTimeRangePicker',
nodes: {
Root: 'div',
ConnectIcon: Icons.ArrowRight,
CalendarIcon: Icons.Calendar,
Popover: UUIPopover,
TextField: UUITextField,
Activator: 'div',
Container: 'div',
Toolbar: 'div',
Main: 'div',
StartSection: 'div',
EndSection: 'div',
Section: 'div',
PickerButtons: UUIPickerButtons,
YearMonthSelect: UUIYearMonthSelect,
DateSelect: UUIDateSelect,
TimeSelect: UUITimeSelect,
DateTimeShortcut: UUIDateTimeShortcut,
},
propTypes: DateTimeRangePickerPropTypes,
}, (props: DateTimeRangePickerFeatureProps, { nodes }) => {
const {
Root, ConnectIcon, CalendarIcon, Popover, TextField,
Activator, Container, Main, StartSection, EndSection, Section,
YearMonthSelect, DateSelect, TimeSelect, DateTimeShortcut, PickerButtons,
} = nodes
const startTimeSelectRef = useRef<any | null>(null)
const endTimeSelectRef = useRef<any | null>(null)
const startInputRef = useRef<HTMLInputElement | null>(null)
const endInputRef = useRef<HTMLInputElement | null>(null)
const [active, setActive] = useState(false)
const [whichFocusing, setWhichFocusing] = useState<'start' | 'end'>()
const [hoverDate, setHoverDate] = useState<Date>()
const initialInnerValue = useMemo(() => {
if (props.value === null) {
return {
startDate: null,
endDate: null,
startInput: '',
endInput: '',
startYearMonth: startOfMonth(new Date),
endYearMonth: add(startOfMonth(new Date), { months: 1 }),
}
}
return {
startDate: props.value[0],
endDate: props.value[1],
startInput: formatDateTime(props.value[0]),
endInput: formatDateTime(props.value[1]),
startYearMonth: startOfMonth(props.value[0]),
endYearMonth: isSameMonth(props.value[0], props.value[1]) ? add(startOfMonth(props.value[1]), { months: 1 }) : props.value[1],
}
}, [props.value])
const [innerValue, setInnerValue, resetInnerValue] = usePendingValue<DateTimeRangePickerInnerValue>(initialInnerValue, (value) => {
if (value.startDate && value.endDate) {
handleValueOnChange([value.startDate, value.endDate])
closePopover()
}
}, { resetWhenInitialValueChanged: true })
const selectedDates = useMemo(() => {
return compact([innerValue.startDate, innerValue.endDate])
}, [innerValue.endDate, innerValue.startDate])
const timeSelectScrollToValue = useCallback((type: 'start' | 'end', value: Date, animate?: boolean) => {
if (type === 'start' && startTimeSelectRef.current) {
startTimeSelectRef.current.scrollToValue(value, animate)
}
if (type === 'end' && endTimeSelectRef.current) {
endTimeSelectRef.current.scrollToValue(value, animate)
}
}, [])
const openPopover = useCallback(() => { setActive(true) }, [])
const closePopover = useCallback(() => { setActive(false) }, [])
const handleValueOnChange = useCallback((value: DateTimeRangePickerValue | null) => {
const sortedValue = value?.sort((i, j) => Number(i) - Number(j)) || null
props.onChange(sortedValue)
}, [props])
/**
*
*/
const handleInputOnSubmit = useCallback((type: 'start' | 'end') => {
if (innerValue.startDate && innerValue.endDate) {
const originalInput = formatDateTime(type === 'start' ? innerValue.startDate : innerValue.endDate)
const input = type === 'start' ? innerValue.startInput : innerValue.endInput
if (originalInput === input) return;
try {
if (input === '') {
handleValueOnChange(null)
} else {
const result = tryParseDateTimeFromString(input)
handleValueOnChange(type === 'start' ? [result, innerValue.endDate] : [innerValue.startDate, result])
}
} catch {
resetInnerValue()
}
}
}, [handleValueOnChange, innerValue.endInput, innerValue.endDate, innerValue.startInput, innerValue.startDate, resetInnerValue])
/**
* handle user change year or month in YearMonthSelect.
*/
const handleStartYearMonthSelect = useCallback((value: Date) => {
setInnerValue((oldValue) => {
const startYearMonthDate = value
let endYearMonthDate = oldValue.endYearMonth
if (!isBefore(startYearMonthDate, endYearMonthDate)) {
endYearMonthDate = add(startYearMonthDate, { months: 1 })
}
return {
...oldValue,
startYearMonth: startYearMonthDate,
endYearMonth: endYearMonthDate,
}
})
}, [setInnerValue])
const handleEndYearMonthSelect = useCallback((value: Date) => {
setInnerValue((oldValue) => {
const endYearMonthDate = value
let startYearMonthDate = oldValue.startYearMonth
if (!isAfter(endYearMonthDate, startYearMonthDate)) {
startYearMonthDate = add(endYearMonthDate, { months: -1 })
}
return {
...oldValue,
startYearMonth: startYearMonthDate,
endYearMonth: endYearMonthDate,
}
})
}, [setInnerValue])
/**
* handle user select date in DateSelect.
*/
const handleDateSelect = useCallback((value: Date) => {
let newStartValue = innerValue.startDate
let newEndValue = innerValue.endDate
if (
(newStartValue !== null && newEndValue !== null) ||
(newStartValue === null && newEndValue === null)
) {
if (whichFocusing === 'end') {
newStartValue = null
newEndValue = value
} else {
newStartValue = value
newEndValue = null
}
} else {
if (newStartValue === null) newStartValue = value
if (newEndValue === null) newEndValue = value
if (isAfter(newStartValue, newEndValue)) {
const tmp = new Date(newStartValue)
newStartValue = new Date(newEndValue)
newEndValue = tmp
}
}
setInnerValue((oldValue) => {
return {
...oldValue,
startDate: newStartValue,
startInput: formatDateTime(newStartValue),
endDate: newEndValue,
endInput: formatDateTime(newEndValue),
}
})
}, [innerValue.endDate, innerValue.startDate, setInnerValue, whichFocusing])
/**
* handle user select date in TimeSelect.
*/
const handleTimeSelect = useCallback((type: 'start' | 'end') => {
return (value: Date) => {
setInnerValue((oldValue) => {
const oldDate = type === 'start' ? oldValue.startDate : oldValue.endDate
const newDate = set(oldDate || getZeroDate(), {
hours: value.getHours(),
minutes: value.getMinutes(),
seconds: value.getSeconds(),
})
const newInput = formatDateTime(newDate)
return {
...oldValue,
...(type === 'start' ? {
startDate: newDate,
startInput: newInput,
} : {}),
...(type === 'end' ? {
endDate: newDate,
endInput: newInput,
} : {}),
}
})
}
}, [setInnerValue])
return (
<Root>
<Popover
placement={'bottom-start'}
active={active}
onClickAway={() => {
resetInnerValue();
timeSelectScrollToValue('start', props.value ? props.value[0] : getZeroDate(), false)
timeSelectScrollToValue('end', props.value ? props.value[1] : getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
activator={
<Activator
onClick={() => {
openPopover()
setTimeout(() => {
const focusedElement = ReactHelper.document?.activeElement
if (startInputRef.current === focusedElement || endInputRef.current === focusedElement) return;
if (startInputRef.current) {
startInputRef.current.focus()
}
}, 0)
}}
>
<TextField
placeholder={props.startPlaceholder}
value={innerValue.startInput}
onChange={(value) => { setInnerValue((oldValue) => ({ ...oldValue, startInput: value })) }}
customize={{
Input: {
ref: startInputRef,
onFocus: () => {
setWhichFocusing('start')
},
onBlur: () => {
setWhichFocusing(undefined)
handleInputOnSubmit('start')
},
onKeyDown: (event) => {
if (event.key === 'Enter') {
handleInputOnSubmit('start')
}
}
}
}}
/>
<ConnectIcon />
<TextField
placeholder={props.endPlaceholder}
value={innerValue.endInput}
onChange={(value) => { setInnerValue((oldValue) => ({ ...oldValue, endInput: value })) }}
customize={{
Input: {
ref: endInputRef,
onFocus: () => {
setWhichFocusing('end')
},
onBlur: () => {
setWhichFocusing(undefined)
handleInputOnSubmit('end')
},
onKeyDown: (event) => {
if (event.key === 'Enter') {
handleInputOnSubmit('end')
}
}
}
}}
/>
<CalendarIcon />
</Activator>
}
>
<Container>
<Main tabIndex={-1}>
{props.shortcuts && (
<DateTimeShortcut
options={props.shortcuts}
onSelect={(value) => {
handleValueOnChange(value)
timeSelectScrollToValue('start', value ? value[0] : getZeroDate(), false)
timeSelectScrollToValue('end', value ? value[1] : getZeroDate(), false)
closePopover()
}}
/>
)}
<StartSection>
<YearMonthSelect
value={innerValue.startYearMonth}
onChange={handleStartYearMonthSelect}
/>
<Section>
<DateSelect
yearMonth={innerValue.startYearMonth}
selectedDates={selectedDates}
onSelect={handleDateSelect}
hoverDate={hoverDate}
onHoverDateChange={(date) => { setHoverDate(date) }}
/>
<TimeSelect
ref={startTimeSelectRef}
value={innerValue.startDate || getZeroDate()}
onChange={handleTimeSelect('start')}
/>
</Section>
</StartSection>
<EndSection>
<YearMonthSelect
value={innerValue.endYearMonth}
onChange={handleEndYearMonthSelect}
/>
<Section>
<DateSelect
yearMonth={innerValue.endYearMonth}
selectedDates={selectedDates}
onSelect={handleDateSelect}
hoverDate={hoverDate}
onHoverDateChange={(date) => { setHoverDate(date) }}
/>
<TimeSelect
ref={endTimeSelectRef}
value={innerValue.endDate || getZeroDate()}
onChange={handleTimeSelect('end')}
/>
</Section>
</EndSection>
</Main>
<PickerButtons
confirmLabel={props.confirmLabel}
cancelLabel={props.cancelLabel}
onCancel={() => {
resetInnerValue()
timeSelectScrollToValue('start', props.value ? props.value[0] : getZeroDate(), false)
timeSelectScrollToValue('end', props.value ? props.value[1] : getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
onConfirm={() => {
setInnerValue((value) => value, true)
if (innerValue.startDate && innerValue.endDate) {
let data = [innerValue.startDate, innerValue.endDate]
if (isAfter(innerValue.startDate, innerValue.endDate)) {
data = data.reverse()
}
timeSelectScrollToValue('start', data[0], false)
timeSelectScrollToValue('end', data[1], false)
} else {
timeSelectScrollToValue('start', getZeroDate(), false)
timeSelectScrollToValue('end', getZeroDate(), false)
}
setTimeout(() => { closePopover() }, 10)
}}
/>
</Container>
</Popover>
</Root>
)
})
Example #5
Source File: TimePicker.tsx From UUI with MIT License | 4 votes |
TimePicker = UUIFunctionComponent({
name: 'TimePicker',
nodes: {
Root: 'div',
ClockIcon: Icons.Clock,
Popover: UUIPopover,
TextField: UUITextField,
Activator: 'div',
Container: 'div',
Toolbar: 'div',
Main: 'div',
TimeSelect: UUITimeSelect,
DateTimeShortcut: UUIDateTimeShortcut,
PickerButtons: UUIPickerButtons,
},
propTypes: TimePickerPropTypes,
}, (props: TimePickerFeatureProps, { nodes }) => {
const {
Root, ClockIcon, Popover, TextField,
Activator, Container, Toolbar, Main,
DateTimeShortcut, TimeSelect, PickerButtons,
} = nodes
const timeSelectRef = useRef<any | null>(null)
const [active, setActive] = useState(false)
const initialInnerValue = useMemo(() => {
return {
date: props.value,
input: props.value === null ? '' : formatTime(props.value),
}
}, [props.value])
const [innerValue, setInnerValue, resetInnerValue] = usePendingValue<TimePickerInnerValue>(initialInnerValue, (value) => {
props.onChange(value.date)
}, { resetWhenInitialValueChanged: true })
const timeSelectScrollToValue = useCallback((value: Date, animate?: boolean) => {
if (timeSelectRef.current) {
timeSelectRef.current.scrollToValue(value, animate)
}
}, [])
const openPopover = useCallback(() => { setActive(true) }, [])
const closePopover = useCallback(() => { setActive(false) }, [])
const handleValueOnChange = useCallback((value: Date | null) => {
props.onChange(value)
}, [props])
const handleInputOnSubmit = useCallback(() => {
const originalInput = formatTime(innerValue.date)
const input = innerValue.input
if (originalInput === input) return;
try {
if (input === '') {
handleValueOnChange(null)
timeSelectScrollToValue(getZeroDate())
} else {
const result = tryParseTimeFromString(input)
handleValueOnChange(result)
timeSelectScrollToValue(result)
}
} catch {
resetInnerValue()
}
}, [handleValueOnChange, innerValue, resetInnerValue, timeSelectScrollToValue])
const handleTimeSelect = useCallback((value: Date) => {
setInnerValue((oldValue) => {
const newDate = set(oldValue.date || getZeroDate(), {
hours: value.getHours(),
minutes: value.getMinutes(),
seconds: value.getSeconds(),
})
const newInput = formatTime(newDate)
return { date: newDate, input: newInput }
})
}, [setInnerValue])
const handleShortcutSelect = useCallback((date: Date) => {
props.onChange(date)
timeSelectScrollToValue(date || getZeroDate(), false)
closePopover()
}, [closePopover, props, timeSelectScrollToValue])
return (
<Root>
<Popover
placement={'bottom-start'}
active={active}
onClickAway={() => {
resetInnerValue();
timeSelectScrollToValue(props.value || getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
activator={
<Activator>
<TextField
placeholder={props.placeholder}
value={innerValue.input}
onChange={(value) => { setInnerValue((oldValue) => ({ ...oldValue, input: value })) }}
customize={{
Root: {
onClick: () => {
openPopover()
}
},
Input: {
onBlur: () => {
handleInputOnSubmit()
},
onKeyDown: (event) => {
if (event.key === 'Enter') {
handleInputOnSubmit()
}
}
}
}}
/>
<ClockIcon />
</Activator>
}
>
<Container>
<Toolbar>
{props.shortcuts && (
<DateTimeShortcut
options={props.shortcuts}
onSelect={handleShortcutSelect}
/>
)}
</Toolbar>
<Main>
<TimeSelect
ref={timeSelectRef}
value={innerValue.date || getZeroDate()}
onChange={handleTimeSelect}
/>
<PickerButtons
confirmLabel={props.confirmLabel}
cancelLabel={props.cancelLabel}
onCancel={() => {
resetInnerValue()
timeSelectScrollToValue(props.value || getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
onConfirm={() => {
setInnerValue((value) => value, true)
timeSelectScrollToValue(innerValue.date || getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
/>
</Main>
</Container>
</Popover>
</Root>
)
})
Example #6
Source File: TimeRangePicker.tsx From UUI with MIT License | 4 votes |
TimeRangePicker = UUIFunctionComponent({
name: 'TimeRangePicker',
nodes: {
Root: 'div',
ConnectIcon: Icons.ArrowRight,
ClockIcon: Icons.Clock,
Popover: UUIPopover,
TextField: UUITextField,
Activator: 'div',
Container: 'div',
Toolbar: 'div',
Main: 'div',
StartSection: 'div',
EndSection: 'div',
PickerButtons: UUIPickerButtons,
TimeSelect: UUITimeSelect,
DateTimeShortcut: UUIDateTimeShortcut,
},
propTypes: TimeRangePickerPropTypes,
}, (props: TimeRangePickerFeatureProps, { nodes }) => {
const {
Root, ConnectIcon, ClockIcon, Popover, TextField,
Activator, Container, Toolbar, Main, StartSection, EndSection,
TimeSelect, DateTimeShortcut, PickerButtons,
} = nodes
const startTimeSelectRef = useRef<any | null>(null)
const endTimeSelectRef = useRef<any | null>(null)
const startInputRef = useRef<HTMLInputElement | null>(null)
const endInputRef = useRef<HTMLInputElement | null>(null)
const [active, setActive] = useState(false)
const initialInnerValue = useMemo(() => {
if (props.value === null) {
return {
startDate: null,
endDate: null,
startInput: '',
endInput: '',
}
}
return {
startDate: props.value[0],
endDate: props.value[1],
startInput: formatTime(props.value[0]),
endInput: formatTime(props.value[1]),
}
}, [props.value])
const [innerValue, setInnerValue, resetInnerValue] = usePendingValue<TimeRangePickerInnerValue>(initialInnerValue, (value) => {
if (value.startDate && value.endDate) {
handleValueOnChange([value.startDate, value.endDate])
closePopover()
}
}, { resetWhenInitialValueChanged: true })
const timeSelectScrollToValue = useCallback((type: 'start' | 'end', value: Date, animate?: boolean) => {
if (type === 'start' && startTimeSelectRef.current) {
startTimeSelectRef.current.scrollToValue(value, animate)
}
if (type === 'end' && endTimeSelectRef.current) {
endTimeSelectRef.current.scrollToValue(value, animate)
}
}, [])
const openPopover = useCallback(() => { setActive(true) }, [])
const closePopover = useCallback(() => { setActive(false) }, [])
const handleValueOnChange = useCallback((value: TimeRangePickerValue | null) => {
const sortedValue = value?.sort((i, j) => Number(i) - Number(j)) || null
props.onChange(sortedValue)
}, [props])
/**
*
*/
const handleInputOnSubmit = useCallback((type: 'start' | 'end') => {
if (innerValue.startDate && innerValue.endDate) {
const originalInput = formatTime(type === 'start' ? innerValue.startDate : innerValue.endDate)
const input = type === 'start' ? innerValue.startInput : innerValue.endInput
if (originalInput === input) return;
try {
if (input === '') {
handleValueOnChange(null)
} else {
const result = tryParseTimeFromString(input)
handleValueOnChange(type === 'start' ? [result, innerValue.endDate] : [innerValue.startDate, result])
}
} catch {
resetInnerValue()
}
}
}, [handleValueOnChange, innerValue.endInput, innerValue.endDate, innerValue.startInput, innerValue.startDate, resetInnerValue])
/**
* handle user select date in TimeSelect.
*/
const handleTimeSelect = useCallback((type: 'start' | 'end') => {
return (value: Date) => {
setInnerValue((oldValue) => {
const oldDate = type === 'start' ? oldValue.startDate : oldValue.endDate
const newDate = set(oldDate || getZeroDate(), {
hours: value.getHours(),
minutes: value.getMinutes(),
seconds: value.getSeconds(),
})
const newInput = formatTime(newDate)
return {
...oldValue,
...(type === 'start' ? {
startDate: newDate,
startInput: newInput,
} : {}),
...(type === 'end' ? {
endDate: newDate,
endInput: newInput,
} : {}),
}
})
}
}, [setInnerValue])
return (
<Root>
<Popover
placement={'bottom-start'}
active={active}
onClickAway={() => {
resetInnerValue();
timeSelectScrollToValue('start', props.value ? props.value[0] : getZeroDate(), false)
timeSelectScrollToValue('end', props.value ? props.value[1] : getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
activator={
<Activator
onClick={() => {
openPopover()
setTimeout(() => {
const focusedElement = ReactHelper.document?.activeElement
if (startInputRef.current === focusedElement || endInputRef.current === focusedElement) return;
if (startInputRef.current) {
startInputRef.current.focus()
}
}, 0)
}}
>
<TextField
placeholder={props.startPlaceholder}
value={innerValue.startInput}
onChange={(value) => { setInnerValue((oldValue) => ({ ...oldValue, startInput: value })) }}
customize={{
Input: {
ref: startInputRef,
onBlur: () => {
handleInputOnSubmit('start')
},
onKeyDown: (event) => {
if (event.key === 'Enter') {
handleInputOnSubmit('start')
}
}
}
}}
/>
<ConnectIcon />
<TextField
placeholder={props.endPlaceholder}
value={innerValue.endInput}
onChange={(value) => { setInnerValue((oldValue) => ({ ...oldValue, endInput: value })) }}
customize={{
Input: {
ref: endInputRef,
onBlur: () => {
handleInputOnSubmit('end')
},
onKeyDown: (event) => {
if (event.key === 'Enter') {
handleInputOnSubmit('end')
}
}
}
}}
/>
<ClockIcon />
</Activator>
}
>
<Container>
<Main tabIndex={-1}>
<Toolbar>
{props.shortcuts && (
<DateTimeShortcut
options={props.shortcuts}
onSelect={(value) => {
handleValueOnChange(value)
timeSelectScrollToValue('start', value ? value[0] : getZeroDate(), false)
timeSelectScrollToValue('end', value ? value[1] : getZeroDate(), false)
closePopover()
}}
/>
)}
</Toolbar>
<StartSection>
<TimeSelect
ref={startTimeSelectRef}
value={innerValue.startDate || getZeroDate()}
onChange={handleTimeSelect('start')}
/>
</StartSection>
<EndSection>
<TimeSelect
ref={endTimeSelectRef}
value={innerValue.endDate || getZeroDate()}
onChange={handleTimeSelect('end')}
/>
</EndSection>
</Main>
<PickerButtons
confirmLabel={props.confirmLabel}
cancelLabel={props.cancelLabel}
onCancel={() => {
resetInnerValue()
timeSelectScrollToValue('start', props.value ? props.value[0] : getZeroDate(), false)
timeSelectScrollToValue('end', props.value ? props.value[1] : getZeroDate(), false)
setTimeout(() => { closePopover() }, 10)
}}
onConfirm={() => {
setInnerValue((value) => value, true)
if (innerValue.startDate && innerValue.endDate) {
let data = [innerValue.startDate, innerValue.endDate]
if (isAfter(innerValue.startDate, innerValue.endDate)) {
data = data.reverse()
}
timeSelectScrollToValue('start', data[0], false)
timeSelectScrollToValue('end', data[1], false)
} else {
timeSelectScrollToValue('start', getZeroDate(), false)
timeSelectScrollToValue('end', getZeroDate(), false)
}
setTimeout(() => { closePopover() }, 10)
}}
/>
</Container>
</Popover>
</Root>
)
})
Example #7
Source File: TimeSelect.tsx From UUI with MIT License | 4 votes |
TimeSelect = UUIFunctionComponent({
name: 'TimeSelect',
nodes: {
Root: 'div',
SelectZone: 'div',
Separator: 'div',
OptionList: 'div',
Option: 'div',
},
propTypes: TimeSelectPropTypes,
}, (props: TimeSelectFeatureProps, { nodes, NodeDataProps, ref }) => {
const {
Root, SelectZone, Separator,
OptionList, Option,
} = nodes
const allOptions = useMemo(() => {
return {
hours: range(0, 24),
minutes: range(0, 60),
seconds: range(0, 60),
}
}, [])
const activeOptionValue = {
hours: props.value.getHours(),
minutes: props.value.getMinutes(),
seconds: props.value.getSeconds(),
}
const [disableHandleScroll, setDisableHandleScroll] = useState(false)
const hourListRef = useRef<HTMLDivElement | null>(null)
const minuteListRef = useRef<HTMLDivElement | null>(null)
const secondListRef = useRef<HTMLDivElement | null>(null)
const getItemHeight = useCallback((target: HTMLElement) => {
const styles = window.getComputedStyle(target)
const optionHeightPx = styles.getPropertyValue('--option-height')
return Number(optionHeightPx.replace('px', ''))
}, [])
const scrollToValue = useCallback((value: Date, animate?: boolean) => {
setDisableHandleScroll(true)
const targetScrollTo = (ref: React.MutableRefObject<HTMLDivElement | null>, value: number, animate?: boolean) => {
const target = ref.current as HTMLElement
const itemHeight = getItemHeight(target)
target.scrollTo({ top: value * itemHeight, behavior: animate ? "smooth" : "auto" })
}
targetScrollTo(hourListRef, value.getHours(), animate)
targetScrollTo(minuteListRef, value.getMinutes(), animate)
targetScrollTo(secondListRef, value.getSeconds(), animate)
setTimeout(() => {
setDisableHandleScroll(false)
}, 500)
}, [getItemHeight])
useImperativeHandle(ref, () => {
return {
scrollToValue: scrollToValue,
}
})
const scrollTo = useCallback((target: HTMLElement, top: number) => {
target.scrollTo({ top, behavior: "smooth" })
}, [])
const debouncedScrollOnChange = useRef({
hours: debounce(scrollTo, 300),
minutes: debounce(scrollTo, 300),
seconds: debounce(scrollTo, 300),
})
const handleScroll = useCallback((type: TimeSelectType) => {
if (disableHandleScroll) return;
const options = allOptions[type]
return (event: React.UIEvent<HTMLDivElement, UIEvent>) => {
const target = event.target as HTMLElement
const itemHeight = getItemHeight(target)
const scrollTop = target.scrollTop
const currentIndex = Math.round((scrollTop) / itemHeight)
const newValue = options[currentIndex];
props.onChange(set(props.value, { [type]: newValue }))
debouncedScrollOnChange.current[type](target, currentIndex * itemHeight)
}
}, [allOptions, disableHandleScroll, getItemHeight, props])
return (
<Root>
{TimeSelectTypeArray.map((type, index) => {
return (
<React.Fragment key={type}>
{index !== 0 && (
<Separator>:</Separator>
)}
<OptionList
ref={[hourListRef, minuteListRef, secondListRef][index]}
key={`option-list-${type}`}
onScroll={handleScroll(type)}
>
{allOptions[type].map((option) => {
const active = activeOptionValue[type] === option
return (
<Option
{...NodeDataProps({
'active': active,
})}
key={`${type}-${option}`}
onClick={() => {
const newValue = set(props.value, { [type]: option })
props.onChange(newValue)
scrollToValue(newValue)
}}
>{padStart(String(option), 2, '0')}</Option>
)
})}
</OptionList>
</React.Fragment>
)
})}
<SelectZone />
</Root>
)
})