mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Accessibility: Fix text selection when using FocusScope (#44770)
* Add tabIndex={-1} to places using focusScope to allow for text highlighting
* use useDialog
* don't need explicit tabIndex anymore
* remove duplicate spreading of props
This commit is contained in:
@@ -248,6 +248,7 @@
|
|||||||
"@opentelemetry/semantic-conventions": "1.0.1",
|
"@opentelemetry/semantic-conventions": "1.0.1",
|
||||||
"@popperjs/core": "2.11.2",
|
"@popperjs/core": "2.11.2",
|
||||||
"@react-aria/button": "3.3.4",
|
"@react-aria/button": "3.3.4",
|
||||||
|
"@react-aria/dialog": "3.1.4",
|
||||||
"@react-aria/focus": "3.5.0",
|
"@react-aria/focus": "3.5.0",
|
||||||
"@react-aria/interactions": "3.7.0",
|
"@react-aria/interactions": "3.7.0",
|
||||||
"@react-aria/menu": "3.3.0",
|
"@react-aria/menu": "3.3.0",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
"@monaco-editor/react": "4.3.1",
|
"@monaco-editor/react": "4.3.1",
|
||||||
"@popperjs/core": "2.11.2",
|
"@popperjs/core": "2.11.2",
|
||||||
"@react-aria/button": "3.3.4",
|
"@react-aria/button": "3.3.4",
|
||||||
|
"@react-aria/dialog": "3.1.4",
|
||||||
"@react-aria/focus": "3.5.0",
|
"@react-aria/focus": "3.5.0",
|
||||||
"@react-aria/menu": "3.3.0",
|
"@react-aria/menu": "3.3.0",
|
||||||
"@react-aria/overlays": "3.7.3",
|
"@react-aria/overlays": "3.7.3",
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ class UnThemedColorPickerPopover<T extends CustomPickersDescriptor> extends Reac
|
|||||||
<>
|
<>
|
||||||
{Object.keys(customPickers).map((key) => {
|
{Object.keys(customPickers).map((key) => {
|
||||||
return (
|
return (
|
||||||
<div className={this.getTabClassName(key)} onClick={this.onTabChange(key)} key={key}>
|
<button className={this.getTabClassName(key)} onClick={this.onTabChange(key)} key={key}>
|
||||||
{customPickers[key].name}
|
{customPickers[key].name}
|
||||||
</div>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
@@ -118,7 +118,11 @@ class UnThemedColorPickerPopover<T extends CustomPickersDescriptor> extends Reac
|
|||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
return (
|
return (
|
||||||
<FocusScope contain restoreFocus autoFocus>
|
<FocusScope contain restoreFocus autoFocus>
|
||||||
<div className={styles.colorPickerPopover}>
|
{/*
|
||||||
|
tabIndex=-1 is needed here to support highlighting text within the picker when using FocusScope
|
||||||
|
see https://github.com/adobe/react-spectrum/issues/1604#issuecomment-781574668
|
||||||
|
*/}
|
||||||
|
<div tabIndex={-1} className={styles.colorPickerPopover}>
|
||||||
<div className={styles.colorPickerPopoverTabs}>
|
<div className={styles.colorPickerPopoverTabs}>
|
||||||
<button className={this.getTabClassName('palette')} onClick={this.onTabChange('palette')}>
|
<button className={this.getTabClassName('palette')} onClick={this.onTabChange('palette')}>
|
||||||
Colors
|
Colors
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { Themeable } from '../../types';
|
|||||||
import { quickOptions } from './options';
|
import { quickOptions } from './options';
|
||||||
import { ButtonGroup, ToolbarButton } from '../Button';
|
import { ButtonGroup, ToolbarButton } from '../Button';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { useOverlay } from '@react-aria/overlays';
|
import { useOverlay } from '@react-aria/overlays';
|
||||||
import { FocusScope } from '@react-aria/focus';
|
import { FocusScope } from '@react-aria/focus';
|
||||||
|
|
||||||
@@ -86,6 +87,7 @@ export function UnthemedTimeRangePicker(props: TimeRangePickerProps): ReactEleme
|
|||||||
|
|
||||||
const ref = createRef<HTMLElement>();
|
const ref = createRef<HTMLElement>();
|
||||||
const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen }, ref);
|
const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen }, ref);
|
||||||
|
const { dialogProps } = useDialog({}, ref);
|
||||||
|
|
||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
const hasAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to);
|
const hasAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to);
|
||||||
@@ -118,7 +120,7 @@ export function UnthemedTimeRangePicker(props: TimeRangePickerProps): ReactEleme
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<FocusScope contain autoFocus restoreFocus>
|
<FocusScope contain autoFocus restoreFocus>
|
||||||
<section ref={ref} {...overlayProps}>
|
<section ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
<TimePickerContent
|
<TimePickerContent
|
||||||
timeZone={timeZone}
|
timeZone={timeZone}
|
||||||
fiscalYearStartMonth={fiscalYearStartMonth}
|
fiscalYearStartMonth={fiscalYearStartMonth}
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ export const getBodyStyles = (theme: GrafanaTheme2) => {
|
|||||||
background-color: ${theme.colors.background.primary};
|
background-color: ${theme.colors.background.primary};
|
||||||
width: 268px;
|
width: 268px;
|
||||||
|
|
||||||
|
.react-calendar__navigation {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.react-calendar__navigation__label,
|
.react-calendar__navigation__label,
|
||||||
.react-calendar__navigation__arrow,
|
.react-calendar__navigation__arrow,
|
||||||
.react-calendar__navigation {
|
.react-calendar__navigation {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { DateTime, GrafanaTheme2, TimeZone } from '@grafana/data';
|
|||||||
import { useTheme2 } from '../../../themes';
|
import { useTheme2 } from '../../../themes';
|
||||||
import { Header } from './CalendarHeader';
|
import { Header } from './CalendarHeader';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { FocusScope } from '@react-aria/focus';
|
import { FocusScope } from '@react-aria/focus';
|
||||||
import { OverlayContainer, useOverlay } from '@react-aria/overlays';
|
import { OverlayContainer, useOverlay } from '@react-aria/overlays';
|
||||||
import { Body } from './CalendarBody';
|
import { Body } from './CalendarBody';
|
||||||
@@ -77,6 +78,12 @@ function TimePickerCalendar(props: TimePickerCalendarProps) {
|
|||||||
const styles = getStyles(theme, props.isReversed);
|
const styles = getStyles(theme, props.isReversed);
|
||||||
const { isOpen, isFullscreen, onClose } = props;
|
const { isOpen, isFullscreen, onClose } = props;
|
||||||
const ref = React.createRef<HTMLElement>();
|
const ref = React.createRef<HTMLElement>();
|
||||||
|
const { dialogProps } = useDialog(
|
||||||
|
{
|
||||||
|
'aria-label': selectors.components.TimePicker.calendar.label,
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
);
|
||||||
const { overlayProps } = useOverlay(
|
const { overlayProps } = useOverlay(
|
||||||
{
|
{
|
||||||
isDismissable: true,
|
isDismissable: true,
|
||||||
@@ -93,13 +100,7 @@ function TimePickerCalendar(props: TimePickerCalendarProps) {
|
|||||||
if (isFullscreen) {
|
if (isFullscreen) {
|
||||||
return (
|
return (
|
||||||
<FocusScope contain restoreFocus autoFocus>
|
<FocusScope contain restoreFocus autoFocus>
|
||||||
<section
|
<section className={styles.container} onClick={stopPropagation} ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
className={styles.container}
|
|
||||||
onClick={stopPropagation}
|
|
||||||
aria-label={selectors.components.TimePicker.calendar.label}
|
|
||||||
ref={ref}
|
|
||||||
{...overlayProps}
|
|
||||||
>
|
|
||||||
<Header {...props} />
|
<Header {...props} />
|
||||||
<Body {...props} />
|
<Body {...props} />
|
||||||
</section>
|
</section>
|
||||||
@@ -110,7 +111,7 @@ function TimePickerCalendar(props: TimePickerCalendarProps) {
|
|||||||
return (
|
return (
|
||||||
<OverlayContainer>
|
<OverlayContainer>
|
||||||
<FocusScope contain autoFocus restoreFocus>
|
<FocusScope contain autoFocus restoreFocus>
|
||||||
<section className={styles.modal} onClick={stopPropagation} ref={ref} {...overlayProps}>
|
<section className={styles.modal} onClick={stopPropagation} ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
<div className={styles.content} aria-label={selectors.components.TimePicker.calendar.label}>
|
<div className={styles.content} aria-label={selectors.components.TimePicker.calendar.label}>
|
||||||
<Header {...props} />
|
<Header {...props} />
|
||||||
<Body {...props} />
|
<Body {...props} />
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
|
|||||||
import { IconButton } from '../IconButton/IconButton';
|
import { IconButton } from '../IconButton/IconButton';
|
||||||
import { stylesFactory, useTheme2 } from '../../themes';
|
import { stylesFactory, useTheme2 } from '../../themes';
|
||||||
import { FocusScope } from '@react-aria/focus';
|
import { FocusScope } from '@react-aria/focus';
|
||||||
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { useOverlay } from '@react-aria/overlays';
|
import { useOverlay } from '@react-aria/overlays';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
@@ -34,6 +35,11 @@ export interface Props {
|
|||||||
|
|
||||||
const getStyles = stylesFactory((theme: GrafanaTheme2, scrollableContent: boolean) => {
|
const getStyles = stylesFactory((theme: GrafanaTheme2, scrollableContent: boolean) => {
|
||||||
return {
|
return {
|
||||||
|
container: css`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
`,
|
||||||
drawer: css`
|
drawer: css`
|
||||||
.drawer-content {
|
.drawer-content {
|
||||||
background-color: ${theme.colors.background.primary};
|
background-color: ${theme.colors.background.primary};
|
||||||
@@ -76,10 +82,9 @@ const getStyles = stylesFactory((theme: GrafanaTheme2, scrollableContent: boolea
|
|||||||
`,
|
`,
|
||||||
content: css`
|
content: css`
|
||||||
padding: ${theme.spacing(2)};
|
padding: ${theme.spacing(2)};
|
||||||
flex-grow: 1;
|
flex: 1;
|
||||||
overflow: ${!scrollableContent ? 'hidden' : 'auto'};
|
overflow: ${!scrollableContent ? 'hidden' : 'auto'};
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
height: 100%;
|
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -101,6 +106,7 @@ export const Drawer: FC<Props> = ({
|
|||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const currentWidth = isExpanded ? '100%' : width;
|
const currentWidth = isExpanded ? '100%' : width;
|
||||||
const overlayRef = React.useRef(null);
|
const overlayRef = React.useRef(null);
|
||||||
|
const { dialogProps, titleProps } = useDialog({}, overlayRef);
|
||||||
const { overlayProps } = useOverlay(
|
const { overlayProps } = useOverlay(
|
||||||
{
|
{
|
||||||
isDismissable: true,
|
isDismissable: true,
|
||||||
@@ -132,45 +138,47 @@ export const Drawer: FC<Props> = ({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FocusScope restoreFocus contain autoFocus>
|
<FocusScope restoreFocus contain autoFocus>
|
||||||
{typeof title === 'string' && (
|
<div className={drawerStyles.container} {...overlayProps} {...dialogProps} ref={overlayRef}>
|
||||||
<div className={drawerStyles.header} {...overlayProps} ref={overlayRef}>
|
{typeof title === 'string' && (
|
||||||
<div className={drawerStyles.actions}>
|
<div className={drawerStyles.header}>
|
||||||
{expandable && !isExpanded && (
|
<div className={drawerStyles.actions}>
|
||||||
|
{expandable && !isExpanded && (
|
||||||
|
<IconButton
|
||||||
|
name="angle-left"
|
||||||
|
size="xl"
|
||||||
|
onClick={() => setIsExpanded(true)}
|
||||||
|
surface="header"
|
||||||
|
aria-label={selectors.components.Drawer.General.expand}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{expandable && isExpanded && (
|
||||||
|
<IconButton
|
||||||
|
name="angle-right"
|
||||||
|
size="xl"
|
||||||
|
onClick={() => setIsExpanded(false)}
|
||||||
|
surface="header"
|
||||||
|
aria-label={selectors.components.Drawer.General.contract}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<IconButton
|
<IconButton
|
||||||
name="angle-left"
|
name="times"
|
||||||
size="xl"
|
size="xl"
|
||||||
onClick={() => setIsExpanded(true)}
|
onClick={onClose}
|
||||||
surface="header"
|
surface="header"
|
||||||
aria-label={selectors.components.Drawer.General.expand}
|
aria-label={selectors.components.Drawer.General.close}
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
{expandable && isExpanded && (
|
<div className={drawerStyles.titleWrapper}>
|
||||||
<IconButton
|
<h3 {...titleProps}>{title}</h3>
|
||||||
name="angle-right"
|
{typeof subtitle === 'string' && <div className="muted">{subtitle}</div>}
|
||||||
size="xl"
|
{typeof subtitle !== 'string' && subtitle}
|
||||||
onClick={() => setIsExpanded(false)}
|
</div>
|
||||||
surface="header"
|
|
||||||
aria-label={selectors.components.Drawer.General.contract}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<IconButton
|
|
||||||
name="times"
|
|
||||||
size="xl"
|
|
||||||
onClick={onClose}
|
|
||||||
surface="header"
|
|
||||||
aria-label={selectors.components.Drawer.General.close}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={drawerStyles.titleWrapper}>
|
|
||||||
<h3>{title}</h3>
|
|
||||||
{typeof subtitle === 'string' && <div className="muted">{subtitle}</div>}
|
|
||||||
{typeof subtitle !== 'string' && subtitle}
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{typeof title !== 'string' && title}
|
||||||
|
<div className={drawerStyles.content}>
|
||||||
|
{!scrollableContent ? children : <CustomScrollbar>{children}</CustomScrollbar>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
{typeof title !== 'string' && title}
|
|
||||||
<div className={drawerStyles.content} {...overlayProps} ref={overlayRef}>
|
|
||||||
{!scrollableContent ? children : <CustomScrollbar>{children}</CustomScrollbar>}
|
|
||||||
</div>
|
</div>
|
||||||
</FocusScope>
|
</FocusScope>
|
||||||
</RcDrawer>
|
</RcDrawer>
|
||||||
|
|||||||
@@ -57,7 +57,11 @@ const ButtonSelectComponent = <T,>(props: Props<T>) => {
|
|||||||
<div className={styles.menuWrapper}>
|
<div className={styles.menuWrapper}>
|
||||||
<ClickOutsideWrapper onClick={state.close} parent={document} includeButtonPress={false}>
|
<ClickOutsideWrapper onClick={state.close} parent={document} includeButtonPress={false}>
|
||||||
<FocusScope contain autoFocus restoreFocus>
|
<FocusScope contain autoFocus restoreFocus>
|
||||||
<Menu onClose={state.close} {...menuProps}>
|
{/*
|
||||||
|
tabIndex=-1 is needed here to support highlighting text within the menu when using FocusScope
|
||||||
|
see https://github.com/adobe/react-spectrum/issues/1604#issuecomment-781574668
|
||||||
|
*/}
|
||||||
|
<Menu tabIndex={-1} onClose={state.close} {...menuProps}>
|
||||||
{options.map((item) => (
|
{options.map((item) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={`${item.value}`}
|
key={`${item.value}`}
|
||||||
|
|||||||
@@ -80,7 +80,11 @@ export function Modal(props: PropsWithChildren<Props>) {
|
|||||||
onClick={onClickBackdrop || (closeOnBackdropClick ? onDismiss : undefined)}
|
onClick={onClickBackdrop || (closeOnBackdropClick ? onDismiss : undefined)}
|
||||||
/>
|
/>
|
||||||
<FocusScope contain={trapFocus} autoFocus restoreFocus>
|
<FocusScope contain={trapFocus} autoFocus restoreFocus>
|
||||||
<div className={cx(styles.modal, className)}>
|
{/*
|
||||||
|
tabIndex=-1 is needed here to support highlighting text within the modal when using FocusScope
|
||||||
|
see https://github.com/adobe/react-spectrum/issues/1604#issuecomment-781574668
|
||||||
|
*/}
|
||||||
|
<div tabIndex={-1} className={cx(styles.modal, className)}>
|
||||||
<div className={headerClass}>
|
<div className={headerClass}>
|
||||||
{typeof title === 'string' && <DefaultModalHeader {...props} title={title} />}
|
{typeof title === 'string' && <DefaultModalHeader {...props} title={title} />}
|
||||||
{typeof title !== 'string' && title}
|
{typeof title !== 'string' && title}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { useMenuTriggerState } from '@react-stately/menu';
|
|||||||
import { useMenuTrigger } from '@react-aria/menu';
|
import { useMenuTrigger } from '@react-aria/menu';
|
||||||
import { useFocusWithin, useHover, useKeyboard } from '@react-aria/interactions';
|
import { useFocusWithin, useHover, useKeyboard } from '@react-aria/interactions';
|
||||||
import { useButton } from '@react-aria/button';
|
import { useButton } from '@react-aria/button';
|
||||||
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { DismissButton, useOverlay } from '@react-aria/overlays';
|
import { DismissButton, useOverlay } from '@react-aria/overlays';
|
||||||
import { FocusScope } from '@react-aria/focus';
|
import { FocusScope } from '@react-aria/focus';
|
||||||
|
|
||||||
@@ -130,6 +131,7 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
|||||||
}
|
}
|
||||||
|
|
||||||
const overlayRef = React.useRef(null);
|
const overlayRef = React.useRef(null);
|
||||||
|
const { dialogProps } = useDialog({}, overlayRef);
|
||||||
const { overlayProps } = useOverlay(
|
const { overlayProps } = useOverlay(
|
||||||
{
|
{
|
||||||
onClose: () => state.close(),
|
onClose: () => state.close(),
|
||||||
@@ -155,7 +157,7 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FocusScope restoreFocus>
|
<FocusScope restoreFocus>
|
||||||
<div {...overlayProps} ref={overlayRef}>
|
<div {...overlayProps} {...dialogProps} ref={overlayRef}>
|
||||||
<DismissButton onDismiss={() => state.close()} />
|
<DismissButton onDismiss={() => state.close()} />
|
||||||
{menu}
|
{menu}
|
||||||
<DismissButton onDismiss={() => state.close()} />
|
<DismissButton onDismiss={() => state.close()} />
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useRef } from 'react';
|
|||||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||||
import { CustomScrollbar, Icon, IconButton, IconName, useTheme2 } from '@grafana/ui';
|
import { CustomScrollbar, Icon, IconButton, IconName, useTheme2 } from '@grafana/ui';
|
||||||
import { FocusScope } from '@react-aria/focus';
|
import { FocusScope } from '@react-aria/focus';
|
||||||
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { useOverlay } from '@react-aria/overlays';
|
import { useOverlay } from '@react-aria/overlays';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { NavBarMenuItem } from './NavBarMenuItem';
|
import { NavBarMenuItem } from './NavBarMenuItem';
|
||||||
@@ -16,6 +17,7 @@ export function NavBarMenu({ activeItem, navItems, onClose }: Props) {
|
|||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
|
const { dialogProps } = useDialog({}, ref);
|
||||||
const { overlayProps } = useOverlay(
|
const { overlayProps } = useOverlay(
|
||||||
{
|
{
|
||||||
isDismissable: true,
|
isDismissable: true,
|
||||||
@@ -27,7 +29,7 @@ export function NavBarMenu({ activeItem, navItems, onClose }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusScope contain restoreFocus autoFocus>
|
<FocusScope contain restoreFocus autoFocus>
|
||||||
<div data-testid="navbarmenu" className={styles.container} ref={ref} {...overlayProps}>
|
<div data-testid="navbarmenu" className={styles.container} ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<Icon name="bars" size="xl" />
|
<Icon name="bars" size="xl" />
|
||||||
<IconButton aria-label="Close navigation menu" name="times" onClick={onClose} size="xl" variant="secondary" />
|
<IconButton aria-label="Close navigation menu" name="times" onClick={onClose} size="xl" variant="secondary" />
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { css } from '@emotion/css';
|
|||||||
import { Button, ButtonGroup, useStyles2 } from '@grafana/ui';
|
import { Button, ButtonGroup, useStyles2 } from '@grafana/ui';
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { FocusScope } from '@react-aria/focus';
|
import { FocusScope } from '@react-aria/focus';
|
||||||
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { useOverlay } from '@react-aria/overlays';
|
import { useOverlay } from '@react-aria/overlays';
|
||||||
|
|
||||||
import { MediaType, PickerTabType, ResourceFolderName } from '../types';
|
import { MediaType, PickerTabType, ResourceFolderName } from '../types';
|
||||||
@@ -25,6 +26,7 @@ export const ResourcePickerPopover = (props: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ref = createRef<HTMLElement>();
|
const ref = createRef<HTMLElement>();
|
||||||
|
const { dialogProps } = useDialog({}, ref);
|
||||||
const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen: true }, ref);
|
const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen: true }, ref);
|
||||||
|
|
||||||
const [newValue, setNewValue] = useState<string>(value ?? '');
|
const [newValue, setNewValue] = useState<string>(value ?? '');
|
||||||
@@ -59,7 +61,7 @@ export const ResourcePickerPopover = (props: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusScope contain autoFocus restoreFocus>
|
<FocusScope contain autoFocus restoreFocus>
|
||||||
<section ref={ref} {...overlayProps}>
|
<section ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
<div className={styles.resourcePickerPopover}>
|
<div className={styles.resourcePickerPopover}>
|
||||||
<div className={styles.resourcePickerPopoverTabs}>
|
<div className={styles.resourcePickerPopoverTabs}>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { createRef } from 'react';
|
import React, { createRef } from 'react';
|
||||||
import { VizTooltipContainer } from '@grafana/ui';
|
import { VizTooltipContainer } from '@grafana/ui';
|
||||||
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { useOverlay } from '@react-aria/overlays';
|
import { useOverlay } from '@react-aria/overlays';
|
||||||
|
|
||||||
import { ComplexDataHoverView } from './components/ComplexDataHoverView';
|
import { ComplexDataHoverView } from './components/ComplexDataHoverView';
|
||||||
@@ -14,12 +15,13 @@ interface Props {
|
|||||||
export const GeomapTooltip = ({ ttip, onClose, isOpen }: Props) => {
|
export const GeomapTooltip = ({ ttip, onClose, isOpen }: Props) => {
|
||||||
const ref = createRef<HTMLElement>();
|
const ref = createRef<HTMLElement>();
|
||||||
const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen }, ref);
|
const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen }, ref);
|
||||||
|
const { dialogProps } = useDialog({}, ref);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ttip && ttip.layers && (
|
{ttip && ttip.layers && (
|
||||||
<VizTooltipContainer position={{ x: ttip.pageX, y: ttip.pageY }} offset={{ x: 10, y: 10 }} allowPointerEvents>
|
<VizTooltipContainer position={{ x: ttip.pageX, y: ttip.pageY }} offset={{ x: 10, y: 10 }} allowPointerEvents>
|
||||||
<section ref={ref} {...overlayProps}>
|
<section ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
<ComplexDataHoverView {...ttip} isOpen={isOpen} onClose={onClose} />
|
<ComplexDataHoverView {...ttip} isOpen={isOpen} onClose={onClose} />
|
||||||
</section>
|
</section>
|
||||||
</VizTooltipContainer>
|
</VizTooltipContainer>
|
||||||
|
|||||||
31
yarn.lock
31
yarn.lock
@@ -4042,6 +4042,7 @@ __metadata:
|
|||||||
"@monaco-editor/react": 4.3.1
|
"@monaco-editor/react": 4.3.1
|
||||||
"@popperjs/core": 2.11.2
|
"@popperjs/core": 2.11.2
|
||||||
"@react-aria/button": 3.3.4
|
"@react-aria/button": 3.3.4
|
||||||
|
"@react-aria/dialog": 3.1.4
|
||||||
"@react-aria/focus": 3.5.0
|
"@react-aria/focus": 3.5.0
|
||||||
"@react-aria/menu": 3.3.0
|
"@react-aria/menu": 3.3.0
|
||||||
"@react-aria/overlays": 3.7.3
|
"@react-aria/overlays": 3.7.3
|
||||||
@@ -6520,7 +6521,22 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@react-aria/focus@npm:3.5.0, @react-aria/focus@npm:^3.5.0":
|
"@react-aria/dialog@npm:3.1.4":
|
||||||
|
version: 3.1.4
|
||||||
|
resolution: "@react-aria/dialog@npm:3.1.4"
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime": ^7.6.2
|
||||||
|
"@react-aria/focus": ^3.4.1
|
||||||
|
"@react-aria/utils": ^3.8.2
|
||||||
|
"@react-stately/overlays": ^3.1.3
|
||||||
|
"@react-types/dialog": ^3.3.1
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0-rc.1
|
||||||
|
checksum: 968328a9b22e545ea79084cca2714f3bc7954c02eb0dc7cab78a1094d4c5dbd19520a0cc28e3dcbb7cb8dd7c505d6b9cb77fbb0fb4735fdf2e99908d481af3ab
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@react-aria/focus@npm:3.5.0, @react-aria/focus@npm:^3.4.1, @react-aria/focus@npm:^3.5.0":
|
||||||
version: 3.5.0
|
version: 3.5.0
|
||||||
resolution: "@react-aria/focus@npm:3.5.0"
|
resolution: "@react-aria/focus@npm:3.5.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6835,6 +6851,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@react-types/dialog@npm:^3.3.1":
|
||||||
|
version: 3.3.1
|
||||||
|
resolution: "@react-types/dialog@npm:3.3.1"
|
||||||
|
dependencies:
|
||||||
|
"@react-types/overlays": ^3.5.1
|
||||||
|
"@react-types/shared": ^3.8.0
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0-rc.1
|
||||||
|
checksum: 6b0260e7018f26387c1d16585a048af5617f8b146d42d28439f0d4fd0fb041b1f004ca1a0a021a4e07a200a0045e34da8b2e0a3ff235272426b6815994e1c291
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@react-types/menu@npm:3.4.1, @react-types/menu@npm:^3.3.0":
|
"@react-types/menu@npm:3.4.1, @react-types/menu@npm:^3.3.0":
|
||||||
version: 3.4.1
|
version: 3.4.1
|
||||||
resolution: "@react-types/menu@npm:3.4.1"
|
resolution: "@react-types/menu@npm:3.4.1"
|
||||||
@@ -19664,6 +19692,7 @@ __metadata:
|
|||||||
"@pmmmwh/react-refresh-webpack-plugin": 0.5.4
|
"@pmmmwh/react-refresh-webpack-plugin": 0.5.4
|
||||||
"@popperjs/core": 2.11.2
|
"@popperjs/core": 2.11.2
|
||||||
"@react-aria/button": 3.3.4
|
"@react-aria/button": 3.3.4
|
||||||
|
"@react-aria/dialog": 3.1.4
|
||||||
"@react-aria/focus": 3.5.0
|
"@react-aria/focus": 3.5.0
|
||||||
"@react-aria/interactions": 3.7.0
|
"@react-aria/interactions": 3.7.0
|
||||||
"@react-aria/menu": 3.3.0
|
"@react-aria/menu": 3.3.0
|
||||||
|
|||||||
Reference in New Issue
Block a user