From 0034456e003a641661bb133ad643313daa24067b Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 13 Jun 2025 21:51:09 +0100 Subject: [PATCH] TimeRangePicker: Highlight range on hover (#106616) * WIP for improved hover state for calendar range * TimeRangePicker: Add hover state when selecting a date range * reorder styles to reduce duplication * oops that wasn't supposed to go in * ignore border radius false positive --- .../TimeRangePicker/CalendarBody.tsx | 63 +++++++++++-------- public/app/core/services/keybindingSrv.ts | 1 + 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarBody.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarBody.tsx index 5279342e6d6..e134e941b77 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarBody.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarBody.tsx @@ -92,6 +92,7 @@ export const getBodyStyles = (theme: GrafanaTheme2) => { // If a time range is part of only 1 day but does not encompass the whole day, // the class that react-calendar uses is '--hasActive' by itself (without being part of a '--range') const hasActiveSelector = `.react-calendar__tile--hasActive:not(.react-calendar__tile--range)`; + return { title: css({ color: theme.colors.text.primary, @@ -154,43 +155,51 @@ export const getBodyStyles = (theme: GrafanaTheme2) => { outline: 0, }, - [`${hasActiveSelector}, .react-calendar__tile--active`]: { - color: theme.colors.primary.contrastText, - fontWeight: theme.typography.fontWeightMedium, - background: theme.colors.primary.main, - border: '0px', + // 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:hover:not(.react-calendar__tile--active):not(.react-calendar__tile--rangeEnd):not(.react-calendar__tile--rangeStart)': + '.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, - }, - - '.react-calendar__tile--rangeEnd, .react-calendar__tile--rangeStart': { - padding: 0, - border: '0px', - color: theme.colors.primary.contrastText, - fontWeight: theme.typography.fontWeightMedium, - background: theme.colors.primary.main, - - abbr: { - backgroundColor: theme.colors.primary.main, borderRadius: theme.shape.radius.pill, - display: 'block', - paddingTop: '2px', - height: '26px', }, + + // 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--rangeStart`]: { - borderTopLeftRadius: '20px', - borderBottomLeftRadius: '20px', + [`${hasActiveSelector}, .react-calendar__tile--rangeEnd:not(.react-calendar__tile--hover)`]: { + borderTopRightRadius: theme.shape.radius.pill, + borderBottomRightRadius: theme.shape.radius.pill, }, - [`${hasActiveSelector}, .react-calendar__tile--rangeEnd`]: { - borderTopRightRadius: '20px', - borderBottomRightRadius: '20px', - }, + [`${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', + }, }), }; }; diff --git a/public/app/core/services/keybindingSrv.ts b/public/app/core/services/keybindingSrv.ts index 3ff866f92c9..37f70eb6b9a 100644 --- a/public/app/core/services/keybindingSrv.ts +++ b/public/app/core/services/keybindingSrv.ts @@ -45,6 +45,7 @@ export class KeybindingSrv { // Chromeless pages like login and signup page don't get any global bindings if (!route.chromeless) { this.bind('?', this.showHelpModal); + this.bind('g h', this.goToHome); this.bind('g d', this.goToDashboards); this.bind('g e', this.goToExplore);