@grafana/ui
Version:
Grafana Components Library
335 lines (327 loc) • 12.1 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var jsxRuntime = require('react/jsx-runtime');
var css = require('@emotion/css');
var react = require('@floating-ui/react');
var dialog = require('@react-aria/dialog');
var focus = require('@react-aria/focus');
var overlays = require('@react-aria/overlays');
var React = require('react');
var Calendar = require('react-calendar');
var reactUse = require('react-use');
var data = require('@grafana/data');
var e2eSelectors = require('@grafana/e2e-selectors');
var i18n = require('@grafana/i18n');
var ThemeContext = require('../../../themes/ThemeContext.cjs');
var floating = require('../../../utils/floating.cjs');
var Button = require('../../Button/Button.cjs');
var InlineField = require('../../Forms/InlineField.cjs');
var Icon = require('../../Icon/Icon.cjs');
var Input = require('../../Input/Input.cjs');
var Stack = require('../../Layout/Stack/Stack.cjs');
var getModalStyles = require('../../Modal/getModalStyles.cjs');
var Portal = require('../../Portal/Portal.cjs');
var TimeOfDayPicker = require('../TimeOfDayPicker.cjs');
var CalendarBody = require('../TimeRangePicker/CalendarBody.cjs');
var utils = require('../utils.cjs');
var adjustDateForReactCalendar = require('../utils/adjustDateForReactCalendar.cjs');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
function _interopNamespaceCompat(e) {
if (e && typeof e === 'object' && 'default' in e) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespaceCompat(React);
var Calendar__default = /*#__PURE__*/_interopDefaultCompat(Calendar);
"use strict";
const DateTimePicker = ({
date,
maxDate,
minDate,
label,
onChange,
disabledHours,
disabledMinutes,
disabledSeconds,
timeZone,
showSeconds = true,
clearable = false
}) => {
const [isOpen, setOpen] = React.useState(false);
const ref = React.useRef(null);
const { overlayProps, underlayProps } = overlays.useOverlay(
{
onClose: () => setOpen(false),
isDismissable: true,
isOpen,
shouldCloseOnInteractOutside: (element) => !Portal.getPortalContainer().contains(element)
},
ref
);
const { dialogProps } = dialog.useDialog({}, ref);
const theme = ThemeContext.useTheme2();
const { modalBackdrop } = ThemeContext.useStyles2(getModalStyles.getModalStyles);
const isFullscreen = reactUse.useMedia(`(min-width: ${theme.breakpoints.values.lg}px)`);
const placement = "bottom-start";
const styles = ThemeContext.useStyles2(getStyles);
const middleware = floating.getPositioningMiddleware(placement);
const { refs, floatingStyles } = react.useFloating({
open: isOpen,
placement,
onOpenChange: setOpen,
middleware,
whileElementsMounted: react.autoUpdate,
strategy: "fixed"
});
const onApply = React.useCallback(
(date2) => {
setOpen(false);
onChange(date2);
},
[onChange]
);
const onOpen = React.useCallback(
(event) => {
event.preventDefault();
setOpen(true);
},
[setOpen]
);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": "date-time-picker", style: { position: "relative" }, children: [
/* @__PURE__ */ jsxRuntime.jsx(
DateTimeInput,
{
date,
onChange,
isFullscreen,
onOpen,
label,
ref: refs.setReference,
showSeconds,
clearable,
timeZone
}
),
isOpen ? isFullscreen ? /* @__PURE__ */ jsxRuntime.jsx(Portal.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(focus.FocusScope, { contain: true, autoFocus: true, restoreFocus: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, ...overlayProps, ...dialogProps, children: /* @__PURE__ */ jsxRuntime.jsx(
DateTimeCalendar,
{
date,
onChange: onApply,
isFullscreen: true,
onClose: () => setOpen(false),
maxDate,
minDate,
ref: refs.setFloating,
style: floatingStyles,
showSeconds,
disabledHours,
disabledMinutes,
disabledSeconds,
timeZone
}
) }) }) }) : /* @__PURE__ */ jsxRuntime.jsxs(Portal.Portal, { children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { className: modalBackdrop, ...underlayProps }),
/* @__PURE__ */ jsxRuntime.jsx(focus.FocusScope, { contain: true, autoFocus: true, restoreFocus: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, ...overlayProps, ...dialogProps, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.modal, children: /* @__PURE__ */ jsxRuntime.jsx(
DateTimeCalendar,
{
date,
maxDate,
minDate,
onChange: onApply,
isFullscreen: false,
onClose: () => setOpen(false),
showSeconds,
disabledHours,
disabledMinutes,
disabledSeconds,
timeZone
}
) }) }) })
] }) : null
] });
};
const DateTimeInput = React__namespace.forwardRef(
({ date, label, onChange, onOpen, timeZone, showSeconds = true, clearable = false }, ref) => {
const styles = ThemeContext.useStyles2(getStyles);
const format = showSeconds ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD HH:mm";
const [internalDate, setInternalDate] = React.useState(() => {
return {
value: date ? data.dateTimeFormat(date, { timeZone }) : !clearable ? data.dateTimeFormat(data.dateTime(), { timeZone }) : "",
invalid: false
};
});
React.useEffect(() => {
if (date) {
const formattedDate = data.dateTimeFormat(date, { format, timeZone });
setInternalDate({
invalid: !utils.isValid(formattedDate),
value: data.isDateTime(date) ? formattedDate : date
});
}
}, [date, format, timeZone]);
const onChangeDate = React.useCallback((event) => {
const isInvalid = !utils.isValid(event.currentTarget.value);
setInternalDate({
value: event.currentTarget.value,
invalid: isInvalid
});
}, []);
const onBlur = React.useCallback(() => {
if (!internalDate.invalid && internalDate.value) {
const date2 = data.dateTimeForTimeZone(data.getTimeZone({ timeZone }), internalDate.value);
onChange(date2);
}
}, [internalDate, onChange, timeZone]);
const clearInternalDate = React.useCallback(() => {
setInternalDate({ value: "", invalid: false });
onChange();
}, [onChange]);
const icon = /* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
"aria-label": i18n.t("grafana-ui.date-time-picker.calendar-icon-label", "Time picker"),
icon: "calendar-alt",
variant: "secondary",
onClick: onOpen
}
);
return /* @__PURE__ */ jsxRuntime.jsx(InlineField.InlineField, { label, invalid: !!(internalDate.value && internalDate.invalid), className: styles.field, children: /* @__PURE__ */ jsxRuntime.jsx(
Input.Input,
{
onChange: onChangeDate,
addonAfter: icon,
value: internalDate.value,
onBlur,
"data-testid": e2eSelectors.Components.DateTimePicker.input,
placeholder: i18n.t("grafana-ui.date-time-picker.select-placeholder", "Select date/time"),
ref,
suffix: clearable && internalDate.value && /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: "times", className: styles.clearIcon, onClick: clearInternalDate })
}
) });
}
);
DateTimeInput.displayName = "DateTimeInput";
const DateTimeCalendar = React__namespace.forwardRef(
({
date,
onClose,
onChange,
isFullscreen,
maxDate,
minDate,
style,
showSeconds = true,
disabledHours,
disabledMinutes,
disabledSeconds,
timeZone
}, ref) => {
const calendarStyles = ThemeContext.useStyles2(CalendarBody.getBodyStyles);
const styles = ThemeContext.useStyles2(getStyles);
const [timeOfDayDateTime, setTimeOfDayDateTime] = React.useState(() => {
if (date && date.isValid()) {
return data.dateTimeForTimeZone(data.getTimeZone({ timeZone }), date);
}
return data.dateTimeForTimeZone(data.getTimeZone({ timeZone }), /* @__PURE__ */ new Date());
});
const [reactCalendarDate, setReactCalendarDate] = React.useState(() => {
if (date && date.isValid()) {
return adjustDateForReactCalendar.adjustDateForReactCalendar(date.toDate(), data.getTimeZone({ timeZone }));
}
return adjustDateForReactCalendar.adjustDateForReactCalendar(/* @__PURE__ */ new Date(), data.getTimeZone({ timeZone }));
});
const onChangeDate = React.useCallback((date2) => {
if (date2 && !Array.isArray(date2)) {
setReactCalendarDate(date2);
}
}, []);
const onChangeTime = React.useCallback((date2) => {
setTimeOfDayDateTime(date2);
}, []);
const handleApply = () => {
const newDate = data.dateTime(timeOfDayDateTime);
newDate.set("date", reactCalendarDate.getDate());
newDate.set("month", reactCalendarDate.getMonth());
newDate.set("year", reactCalendarDate.getFullYear());
onChange(newDate);
};
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: css.cx(styles.container, { [styles.fullScreen]: isFullscreen }), style, ref, children: [
/* @__PURE__ */ jsxRuntime.jsx(
Calendar__default.default,
{
next2Label: null,
prev2Label: null,
value: reactCalendarDate,
nextLabel: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: "angle-right" }),
nextAriaLabel: i18n.t("grafana-ui.date-time-picker.next-label", "Next month"),
prevLabel: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: "angle-left" }),
prevAriaLabel: i18n.t("grafana-ui.date-time-picker.previous-label", "Previous month"),
onChange: onChangeDate,
locale: "en",
className: calendarStyles.body,
tileClassName: calendarStyles.title,
maxDate,
minDate
}
),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.time, children: /* @__PURE__ */ jsxRuntime.jsx(
TimeOfDayPicker.TimeOfDayPicker,
{
showSeconds,
onChange: onChangeTime,
value: timeOfDayDateTime,
disabledHours
}
) }),
/* @__PURE__ */ jsxRuntime.jsxs(Stack.Stack, { children: [
/* @__PURE__ */ jsxRuntime.jsx(Button.Button, { type: "button", onClick: handleApply, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.date-time-picker.apply", children: "Apply" }) }),
/* @__PURE__ */ jsxRuntime.jsx(Button.Button, { variant: "secondary", type: "button", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "grafana-ui.date-time-picker.cancel", children: "Cancel" }) })
] })
] });
}
);
DateTimeCalendar.displayName = "DateTimeCalendar";
const getStyles = (theme) => ({
container: css.css({
padding: theme.spacing(1),
border: `1px ${theme.colors.border.weak} solid`,
borderRadius: theme.shape.radius.default,
backgroundColor: theme.colors.background.primary,
zIndex: theme.zIndex.modal
}),
fullScreen: css.css({
position: "absolute"
}),
time: css.css({
marginBottom: theme.spacing(2)
}),
modal: css.css({
position: "fixed",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: theme.zIndex.modal,
maxWidth: "280px"
}),
clearIcon: css.css({
cursor: "pointer"
}),
field: css.css({
marginBottom: 0,
width: "100%"
})
});
exports.DateTimePicker = DateTimePicker;
//# sourceMappingURL=DateTimePicker.cjs.map