@grafana/ui
Version:
Grafana Components Library
168 lines (165 loc) • 6.66 kB
JavaScript
import { jsx } from 'react/jsx-runtime';
import { css } from '@emotion/css';
import { useCallback } from 'react';
import Calendar from 'react-calendar';
import { dateTimeParse } from '@grafana/data';
import { t } from '@grafana/i18n';
import { useStyles2 } from '../../../themes/ThemeContext.mjs';
import { Icon } from '../../Icon/Icon.mjs';
import { getWeekStart } from '../WeekStartPicker.mjs';
import { adjustDateForReactCalendar } from '../utils/adjustDateForReactCalendar.mjs';
const weekStartMap = {
saturday: "islamic",
sunday: "gregory",
monday: "iso8601"
};
function Body({ onChange, from, to, timeZone, weekStart }) {
const value = inputToValue(from, to, /* @__PURE__ */ new Date(), timeZone);
const onCalendarChange = useOnCalendarChange(onChange, timeZone);
const styles = useStyles2(getBodyStyles);
const weekStartValue = getWeekStart(weekStart);
return /* @__PURE__ */ jsx(
Calendar,
{
selectRange: true,
next2Label: null,
prev2Label: null,
className: styles.body,
tileClassName: styles.title,
value,
nextLabel: /* @__PURE__ */ jsx(Icon, { name: "angle-right" }),
nextAriaLabel: t("time-picker.calendar.next-month", "Next month"),
prevLabel: /* @__PURE__ */ jsx(Icon, { name: "angle-left" }),
prevAriaLabel: t("time-picker.calendar.previous-month", "Previous month"),
onChange: onCalendarChange,
locale: "en",
calendarType: weekStartMap[weekStartValue]
}
);
}
Body.displayName = "Body";
function inputToValue(from, to, invalidDateDefault = /* @__PURE__ */ new Date(), timezone) {
let fromAsDate = from.isValid() ? from.toDate() : invalidDateDefault;
let toAsDate = to.isValid() ? to.toDate() : invalidDateDefault;
if (timezone) {
fromAsDate = adjustDateForReactCalendar(fromAsDate, timezone);
toAsDate = adjustDateForReactCalendar(toAsDate, timezone);
}
if (fromAsDate > toAsDate) {
return [toAsDate, fromAsDate];
}
return [fromAsDate, toAsDate];
}
function useOnCalendarChange(onChange, timeZone) {
return useCallback(
(value) => {
if (!Array.isArray(value)) {
return console.error("onCalendarChange: should be run in selectRange={true}");
}
if (value[0] && value[1]) {
const from = dateTimeParse(dateInfo(value[0]), { timeZone });
const to = dateTimeParse(dateInfo(value[1]), { timeZone });
onChange(from, to);
}
},
[onChange, timeZone]
);
}
function dateInfo(date) {
return [date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()];
}
const getBodyStyles = (theme) => {
const hasActiveSelector = `.react-calendar__tile--hasActive:not(.react-calendar__tile--range)`;
return {
title: css({
color: theme.colors.text.primary,
backgroundColor: theme.colors.background.primary,
fontSize: theme.typography.size.md,
border: "1px solid transparent",
"&:hover, &:focus": {
position: "relative"
},
"&:disabled": {
color: theme.colors.action.disabledText,
cursor: "not-allowed"
}
}),
body: css({
zIndex: theme.zIndex.modal,
backgroundColor: theme.colors.background.elevated,
width: "268px",
".react-calendar__navigation": {
display: "flex"
},
".react-calendar__navigation__label, .react-calendar__navigation__arrow, .react-calendar__navigation": {
paddingTop: "4px",
backgroundColor: "inherit",
color: theme.colors.text.primary,
border: 0,
fontWeight: theme.typography.fontWeightMedium
},
".react-calendar__month-view__weekdays": {
backgroundColor: "inherit",
textAlign: "center",
color: theme.colors.primary.text,
abbr: {
border: 0,
textDecoration: "none",
cursor: "default",
display: "block",
padding: "4px 0 4px 0"
}
},
".react-calendar__month-view__days": {
backgroundColor: "inherit"
},
".react-calendar__tile, .react-calendar__tile--now": {
marginBottom: "4px",
backgroundColor: "inherit",
height: "26px"
},
".react-calendar__navigation__label, .react-calendar__navigation > button:focus, .time-picker-calendar-tile:focus": {
outline: 0
},
// The --hover modifier is active when the user is selecting a range and hovering over a tile - it shows the pending range.
// It is applied to all dates between the clicked date and the hovered date.
// The *clicked* date should have primary bg, while *pending* range dates should have hover bg.
".react-calendar__tile--hover": {
backgroundColor: theme.colors.action.hover,
// eslint-disable-next-line @grafana/no-border-radius-literal
borderRadius: 0
},
".react-calendar__tile--hoverStart": {
borderTopLeftRadius: theme.shape.radius.pill,
borderBottomLeftRadius: theme.shape.radius.pill
},
".react-calendar__tile--hoverEnd": {
borderTopRightRadius: theme.shape.radius.pill,
borderBottomRightRadius: theme.shape.radius.pill
},
// Addiitonally, when hovering a date before clicking any, it should show the hover bg.
".react-calendar__tile:hover:not(.react-calendar__tile--hover):not(.react-calendar__tile--active):not(.react-calendar__tile--hasActive)": {
backgroundColor: theme.colors.action.hover,
borderRadius: theme.shape.radius.pill
},
// When the user is selecting a range (they've clicked one date, tiles have --hover), both --rangeStart and --rangeEnd are on the tile.
// The --hover classes above handle the rounding of the tiles so they're contigious with the range
[`${hasActiveSelector}, .react-calendar__tile--rangeStart:not(.react-calendar__tile--hover)`]: {
borderTopLeftRadius: theme.shape.radius.pill,
borderBottomLeftRadius: theme.shape.radius.pill
},
[`${hasActiveSelector}, .react-calendar__tile--rangeEnd:not(.react-calendar__tile--hover)`]: {
borderTopRightRadius: theme.shape.radius.pill,
borderBottomRightRadius: theme.shape.radius.pill
},
[`${hasActiveSelector}, .react-calendar__tile--active, .react-calendar__tile--rangeEnd, .react-calendar__tile--rangeStart`]: {
color: theme.colors.primary.contrastText,
fontWeight: theme.typography.fontWeightMedium,
background: theme.colors.primary.main,
border: "0px"
}
})
};
};
export { Body, getBodyStyles, inputToValue };
//# sourceMappingURL=CalendarBody.mjs.map