UNPKG

@grafana/ui

Version:
259 lines (254 loc) • 10 kB
'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 i18n = require('@grafana/i18n'); var ThemeContext = require('../../../themes/ThemeContext.cjs'); var floating = require('../../../utils/floating.cjs'); var Button = require('../../Button/Button.cjs'); var Field = require('../../Forms/Field.cjs'); var Icon = require('../../Icon/Icon.cjs'); var Input = require('../../Input/Input.cjs'); var ScrollContainer = require('../../ScrollContainer/ScrollContainer.cjs'); var TimePickerTitle = require('../TimeRangePicker/TimePickerTitle.cjs'); var TimeRangeList = require('../TimeRangePicker/TimeRangeList.cjs'); var options = require('../options.cjs'); var utils = require('./utils.cjs'); "use strict"; function RelativeTimeRangePicker(props) { const { timeRange, onChange } = props; const [isOpen, setIsOpen] = React.useState(false); const onClose = React.useCallback(() => setIsOpen(false), []); const timeOption = utils.mapRelativeTimeRangeToOption(timeRange); const [from, setFrom] = React.useState({ value: timeOption.from, validation: utils.isRangeValid(timeOption.from) }); const [to, setTo] = React.useState({ value: timeOption.to, validation: utils.isRangeValid(timeOption.to) }); const ref = React.useRef(null); const { overlayProps, underlayProps } = overlays.useOverlay( { onClose: () => setIsOpen(false), isDismissable: true, isOpen }, ref ); const { dialogProps } = dialog.useDialog({}, ref); const validOptions = options.getQuickOptions().filter((o) => utils.isRelativeFormat(o.from)); const placement = "bottom-start"; const middleware = floating.getPositioningMiddleware(placement); const { context, refs, floatingStyles } = react.useFloating({ open: isOpen, placement, onOpenChange: setIsOpen, middleware, whileElementsMounted: react.autoUpdate, strategy: "fixed" }); const click = react.useClick(context); const dismiss = react.useDismiss(context); const { getReferenceProps, getFloatingProps } = react.useInteractions([dismiss, click]); const styles = ThemeContext.useStyles2(getStyles(from.validation.errorMessage, to.validation.errorMessage)); const onChangeTimeOption = (option) => { const relativeTimeRange = utils.mapOptionToRelativeTimeRange(option); if (!relativeTimeRange) { return; } onClose(); setFrom({ ...from, value: option.from }); setTo({ ...to, value: option.to }); onChange(relativeTimeRange); }; const onOpen = React.useCallback( (event) => { event.stopPropagation(); event.preventDefault(); setIsOpen(!isOpen); }, [isOpen] ); const onApply = (event) => { event.preventDefault(); if (!to.validation.isValid || !from.validation.isValid) { return; } const timeRange2 = utils.mapOptionToRelativeTimeRange({ from: from.value, to: to.value, display: "" }); if (!timeRange2) { return; } onChange(timeRange2); setIsOpen(false); }; const { from: timeOptionFrom, to: timeOptionTo } = timeOption; return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.container, children: [ /* @__PURE__ */ jsxRuntime.jsxs( "button", { ref: refs.setReference, className: styles.pickerInput, type: "button", onClick: onOpen, ...getReferenceProps(), children: [ /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.clockIcon, children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: "clock-nine" }) }), /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsxs(i18n.Trans, { i18nKey: "time-picker.time-range.from-to", children: [ { timeOptionFrom }, " to ", { timeOptionTo } ] }) }), /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.caretIcon, children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: isOpen ? "angle-up" : "angle-down", size: "lg" }) }) ] } ), isOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "presentation", className: styles.backdrop, ...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.content, ref: refs.setFloating, style: floatingStyles, ...getFloatingProps(), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.body, children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.leftSide, children: /* @__PURE__ */ jsxRuntime.jsx(ScrollContainer.ScrollContainer, { showScrollIndicators: true, children: /* @__PURE__ */ jsxRuntime.jsx( TimeRangeList.TimeRangeList, { title: i18n.t("time-picker.time-range.example-title", "Example time ranges"), options: validOptions, onChange: onChangeTimeOption, value: timeOption } ) }) }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.rightSide, children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.title, children: /* @__PURE__ */ jsxRuntime.jsx(TimePickerTitle.TimePickerTitle, { children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "time-picker.time-range.specify", children: "Specify time range" }) }) }), /* @__PURE__ */ jsxRuntime.jsx( Field.Field, { label: i18n.t("time-picker.time-range.from-label", "From"), invalid: !from.validation.isValid, error: from.validation.errorMessage, children: /* @__PURE__ */ jsxRuntime.jsx( Input.Input, { onClick: (event) => event.stopPropagation(), onBlur: () => setFrom({ ...from, validation: utils.isRangeValid(from.value) }), onChange: (event) => setFrom({ ...from, value: event.currentTarget.value }), value: from.value } ) } ), /* @__PURE__ */ jsxRuntime.jsx( Field.Field, { label: i18n.t("time-picker.time-range.to-label", "To"), invalid: !to.validation.isValid, error: to.validation.errorMessage, children: /* @__PURE__ */ jsxRuntime.jsx( Input.Input, { onClick: (event) => event.stopPropagation(), onBlur: () => setTo({ ...to, validation: utils.isRangeValid(to.value) }), onChange: (event) => setTo({ ...to, value: event.currentTarget.value }), value: to.value } ) } ), /* @__PURE__ */ jsxRuntime.jsx( Button.Button, { "aria-label": i18n.t("time-picker.time-range.submit-button-label", "TimePicker submit button"), onClick: onApply, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "time-picker.time-range.apply", children: "Apply time range" }) } ) ] }) ] }) }) }) }) ] }) ] }); } const getStyles = (fromError, toError) => (theme) => { const inputStyles = Input.getInputStyles({ theme, invalid: false }); const bodyMinimumHeight = 250; const bodyHeight = bodyMinimumHeight + calculateErrorHeight(theme, fromError) + calculateErrorHeight(theme, toError); return { backdrop: css.css({ position: "fixed", zIndex: theme.zIndex.modalBackdrop, top: 0, right: 0, bottom: 0, left: 0 }), container: css.css({ display: "flex", position: "relative" }), pickerInput: css.cx( inputStyles.input, inputStyles.wrapper, css.css({ display: "flex", alignItems: "center", justifyContent: "space-between", cursor: "pointer", paddingRight: 0, paddingLeft: 0, lineHeight: `${theme.spacing.gridSize * theme.components.height.md - 2}px` }) ), caretIcon: css.cx( inputStyles.suffix, css.css({ position: "relative", marginLeft: theme.spacing(0.5) }) ), clockIcon: css.cx( inputStyles.prefix, css.css({ position: "relative", marginRight: theme.spacing(0.5) }) ), content: css.css({ background: theme.colors.background.primary, boxShadow: theme.shadows.z3, position: "absolute", zIndex: theme.zIndex.modal, width: "500px", top: "100%", borderRadius: theme.shape.radius.default, border: `1px solid ${theme.colors.border.weak}`, left: 0, whiteSpace: "normal" }), body: css.css({ display: "flex", height: `${bodyHeight}px` }), description: css.css({ color: theme.colors.text.secondary, fontSize: theme.typography.size.sm }), leftSide: css.css({ width: "50% !important", borderRight: `1px solid ${theme.colors.border.medium}` }), rightSide: css.css({ width: "50%", padding: theme.spacing(1) }), title: css.css({ marginBottom: theme.spacing(1) }) }; }; function calculateErrorHeight(theme, errorMessage) { if (!errorMessage) { return 0; } if (errorMessage.length > 34) { return theme.spacing.gridSize * 6.5; } return theme.spacing.gridSize * 4; } exports.RelativeTimeRangePicker = RelativeTimeRangePicker; //# sourceMappingURL=RelativeTimeRangePicker.cjs.map