Skip to content

Commit

Permalink
[v9.3.x] TimePicker: Prevent TimePicker overflowing viewport on small…
Browse files Browse the repository at this point in the history
… screens (grafana#60100)

TimePicker: Prevent TimePicker overflowing viewport on small screens (grafana#59808)

* render timepicker in a modal style on small screens

* remove top: -1

* apply styles

* prevent bug where selecting a relative range wouldn't apply if the absolute ranges were expanded

* Revert "prevent bug where selecting a relative range wouldn't apply if the absolute ranges were expanded"

This reverts commit 7090443.

(cherry picked from commit 1497ad4)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
  • Loading branch information
2 people authored and GuaYounesPW committed Feb 8, 2023
1 parent 2068d29 commit 5585be1
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 42 deletions.
Expand Up @@ -7,9 +7,9 @@ import { dateTimeFormat, DateTime, dateTime, GrafanaTheme2, isDateTime } from '@

import { Button, ClickOutsideWrapper, HorizontalGroup, Icon, InlineField, Input, Portal } from '../..';
import { useStyles2, useTheme2 } from '../../../themes';
import { getModalStyles } from '../../Modal/getModalStyles';
import { TimeOfDayPicker } from '../TimeOfDayPicker';
import { getBodyStyles } from '../TimeRangePicker/CalendarBody';
import { getStyles as getCalendarStyles } from '../TimeRangePicker/TimePickerCalendar';
import { isValid } from '../utils';

export interface Props {
Expand All @@ -29,8 +29,8 @@ export const DateTimePicker: FC<Props> = ({ date, maxDate, label, onChange }) =>
const [isOpen, setOpen] = useState(false);

const theme = useTheme2();
const { modalBackdrop } = getModalStyles(theme);
const isFullscreen = useMedia(`(min-width: ${theme.breakpoints.values.lg}px)`);
const containerStyles = useStyles2(getCalendarStyles);
const styles = useStyles2(getStyles);

const onApply = useCallback(
Expand Down Expand Up @@ -69,7 +69,7 @@ export const DateTimePicker: FC<Props> = ({ date, maxDate, label, onChange }) =>
<div className={styles.modal} onClick={stopPropagation}>
<DateTimeCalendar date={date} onChange={onApply} isFullscreen={false} onClose={() => setOpen(false)} />
</div>
<div className={containerStyles.backdrop} onClick={stopPropagation} />
<div className={modalBackdrop} onClick={stopPropagation} />
</ClickOutsideWrapper>
</Portal>
)
Expand Down
@@ -1,4 +1,4 @@
import { css } from '@emotion/css';
import { css, cx } from '@emotion/css';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
Expand All @@ -16,9 +16,10 @@ import {
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';

import { useStyles2 } from '../../themes/ThemeContext';
import { useStyles2, useTheme2 } from '../../themes/ThemeContext';
import { t, Trans } from '../../utils/i18n';
import { ButtonGroup } from '../Button';
import { getModalStyles } from '../Modal/getModalStyles';
import { ToolbarButton } from '../ToolbarButton';
import { Tooltip } from '../Tooltip/Tooltip';

Expand Down Expand Up @@ -85,10 +86,12 @@ export function TimeRangePicker(props: TimeRangePickerProps) {
};

const ref = createRef<HTMLElement>();
const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen }, ref);
const { overlayProps, underlayProps } = useOverlay({ onClose, isDismissable: true, isOpen }, ref);
const { dialogProps } = useDialog({}, ref);

const theme = useTheme2();
const styles = useStyles2(getStyles);
const { modalBackdrop } = getModalStyles(theme);
const hasAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to);
const variant = isSynced ? 'active' : isOnCanvas ? 'canvas' : 'default';

Expand Down Expand Up @@ -122,23 +125,26 @@ export function TimeRangePicker(props: TimeRangePickerProps) {
</ToolbarButton>
</Tooltip>
{isOpen && (
<section ref={ref} {...overlayProps} {...dialogProps}>
<FocusScope contain autoFocus>
<TimePickerContent
timeZone={timeZone}
fiscalYearStartMonth={fiscalYearStartMonth}
value={value}
onChange={onChange}
quickOptions={quickOptions}
history={history}
showHistory
widthOverride={widthOverride}
onChangeTimeZone={onChangeTimeZone}
onChangeFiscalYearStartMonth={onChangeFiscalYearStartMonth}
hideQuickRanges={hideQuickRanges}
/>
</FocusScope>
</section>
<>
<div role="presentation" className={cx(modalBackdrop, styles.backdrop)} {...underlayProps} />
<section className={styles.content} ref={ref} {...overlayProps} {...dialogProps}>
<FocusScope contain autoFocus>
<TimePickerContent
timeZone={timeZone}
fiscalYearStartMonth={fiscalYearStartMonth}
value={value}
onChange={onChange}
quickOptions={quickOptions}
history={history}
showHistory
widthOverride={widthOverride}
onChangeTimeZone={onChangeTimeZone}
onChangeFiscalYearStartMonth={onChangeFiscalYearStartMonth}
hideQuickRanges={hideQuickRanges}
/>
</FocusScope>
</section>
</>
)}

{timeSyncButton}
Expand Down Expand Up @@ -219,13 +225,33 @@ const formattedRange = (value: TimeRange, timeZone?: TimeZone) => {
return rangeUtil.describeTimeRange(adjustedTimeRange, timeZone);
};

const getStyles = () => {
const getStyles = (theme: GrafanaTheme2) => {
return {
container: css`
position: relative;
display: flex;
vertical-align: middle;
`,
backdrop: css({
display: 'none',
[theme.breakpoints.down('sm')]: {
display: 'block',
},
}),
content: css({
position: 'absolute',
right: 0,
top: '116%',
zIndex: theme.zIndex.dropdown,

[theme.breakpoints.down('sm')]: {
position: 'fixed',
right: '50%',
top: '50%',
transform: 'translate(50%, -50%)',
zIndex: theme.zIndex.modal,
},
}),
};
};

Expand Down
Expand Up @@ -8,6 +8,7 @@ import { DateTime, GrafanaTheme2, TimeZone } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';

import { useTheme2 } from '../../../themes';
import { getModalStyles } from '../../Modal/getModalStyles';

import { Body } from './CalendarBody';
import { Footer } from './CalendarFooter';
Expand All @@ -16,7 +17,7 @@ import { Header } from './CalendarHeader';
export const getStyles = (theme: GrafanaTheme2, isReversed = false) => {
return {
container: css`
top: -1px;
top: 0px;
position: absolute;
${isReversed ? 'left' : 'right'}: 544px;
box-shadow: ${theme.shadows.z3};
Expand All @@ -38,26 +39,17 @@ export const getStyles = (theme: GrafanaTheme2, isReversed = false) => {
}
`,
modal: css`
box-shadow: ${theme.shadows.z3};
left: 50%;
position: fixed;
top: 20%;
width: 100%;
top: 50%;
transform: translate(-50%, -50%);
z-index: ${theme.zIndex.modal};
`,
content: css`
margin: 0 auto;
width: 268px;
`,
backdrop: css`
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #202226;
opacity: 0.7;
z-index: ${theme.zIndex.modalBackdrop};
text-align: center;
`,
};
};

Expand All @@ -77,6 +69,7 @@ const stopPropagation = (event: React.MouseEvent<HTMLDivElement>) => event.stopP

function TimePickerCalendar(props: TimePickerCalendarProps) {
const theme = useTheme2();
const { modalBackdrop } = getModalStyles(theme);
const styles = getStyles(theme, props.isReversed);
const { isOpen, isFullscreen, onClose } = props;
const ref = React.createRef<HTMLElement>();
Expand Down Expand Up @@ -112,6 +105,7 @@ function TimePickerCalendar(props: TimePickerCalendarProps) {

return (
<OverlayContainer>
<div className={modalBackdrop} onClick={stopPropagation} />
<FocusScope contain autoFocus restoreFocus>
<section className={styles.modal} onClick={stopPropagation} ref={ref} {...overlayProps} {...dialogProps}>
<div className={styles.content} aria-label={selectors.components.TimePicker.calendar.label}>
Expand All @@ -121,7 +115,6 @@ function TimePickerCalendar(props: TimePickerCalendarProps) {
</div>
</section>
</FocusScope>
<div className={styles.backdrop} onClick={stopPropagation} />
</OverlayContainer>
);
}
Expand Down
Expand Up @@ -267,10 +267,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme2, isReversed, hideQuickRang
container: css`
background: ${theme.colors.background.primary};
box-shadow: ${theme.shadows.z3};
position: absolute;
z-index: ${theme.zIndex.dropdown};
width: ${isFullscreen ? '546px' : '262px'};
top: 116%;
border-radius: 2px;
border: 1px solid ${theme.colors.border.weak};
${isReversed ? 'left' : 'right'}: 0;
Expand Down

0 comments on commit 5585be1

Please sign in to comment.