import React, { useCallback } from 'react'; import { useStyles2 } from '../../../themes'; import Calendar from 'react-calendar'; import { css } from '@emotion/css'; import { Icon } from '../../Icon/Icon'; import { TimePickerCalendarProps } from './TimePickerCalendar'; import { GrafanaTheme2, dateTime, dateTimeParse, DateTime, TimeZone } from '@grafana/data'; export function Body({ onChange, from, to, timeZone }: TimePickerCalendarProps) { const value = inputToValue(from, to); const onCalendarChange = useOnCalendarChange(onChange, timeZone); const styles = useStyles2(getBodyStyles); return ( } prevLabel={} onChange={onCalendarChange} locale="en" /> ); } Body.displayName = 'Body'; export function inputToValue(from: DateTime, to: DateTime, invalidDateDefault: Date = new Date()): Date[] { const fromAsDate = from.toDate(); const toAsDate = to.toDate(); const fromAsValidDate = dateTime(fromAsDate).isValid() ? fromAsDate : invalidDateDefault; const toAsValidDate = dateTime(toAsDate).isValid() ? toAsDate : invalidDateDefault; if (fromAsValidDate > toAsValidDate) { return [toAsValidDate, fromAsValidDate]; } return [fromAsValidDate, toAsValidDate]; } function useOnCalendarChange(onChange: (from: DateTime, to: DateTime) => void, timeZone?: TimeZone) { return useCallback( (value: Date | Date[]) => { if (!Array.isArray(value)) { return console.error('onCalendarChange: should be run in selectRange={true}'); } const from = dateTimeParse(dateInfo(value[0]), { timeZone }); const to = dateTimeParse(dateInfo(value[1]), { timeZone }); onChange(from, to); }, [onChange, timeZone] ); } function dateInfo(date: Date): number[] { return [date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()]; } export const getBodyStyles = (theme: GrafanaTheme2) => { return { title: css` color: ${theme.colors.text}; background-color: ${theme.colors.background.primary}; font-size: ${theme.typography.size.md}; border: 1px solid transparent; &:hover { position: relative; } `, body: css` z-index: ${theme.zIndex.modal}; background-color: ${theme.colors.background.primary}; width: 268px; .react-calendar__navigation__label, .react-calendar__navigation__arrow, .react-calendar__navigation { padding-top: 4px; background-color: inherit; color: ${theme.colors.text}; border: 0; font-weight: ${theme.typography.fontWeightMedium}; } .react-calendar__month-view__weekdays { background-color: inherit; text-align: center; color: ${theme.colors.primary.text}; abbr { border: 0; text-decoration: none; cursor: default; display: block; padding: 4px 0 4px 0; } } .react-calendar__month-view__days { background-color: inherit; } .react-calendar__tile, .react-calendar__tile--now { margin-bottom: 4px; background-color: inherit; height: 26px; } .react-calendar__navigation__label, .react-calendar__navigation > button:focus, .time-picker-calendar-tile:focus { outline: 0; } .react-calendar__tile--active, .react-calendar__tile--active:hover { color: ${theme.colors.primary.contrastText}; font-weight: ${theme.typography.fontWeightMedium}; background: ${theme.colors.primary.main}; box-shadow: none; border: 0px; } .react-calendar__tile--rangeEnd, .react-calendar__tile--rangeStart { padding: 0; border: 0px; color: ${theme.colors.primary.contrastText}; font-weight: ${theme.typography.fontWeightMedium}; background: ${theme.colors.primary.main}; abbr { background-color: ${theme.colors.primary.main}; border-radius: 100px; display: block; padding-top: 2px; height: 26px; } } .react-calendar__tile--rangeStart { border-top-left-radius: 20px; border-bottom-left-radius: 20px; } .react-calendar__tile--rangeEnd { border-top-right-radius: 20px; border-bottom-right-radius: 20px; } `, }; };