diff --git a/src/components/form/range/__snapshots__/dual_range.test.js.snap b/src/components/form/range/__snapshots__/dual_range.test.js.snap
index d6cc79d08b0..d9bdf8df45b 100644
--- a/src/components/form/range/__snapshots__/dual_range.test.js.snap
+++ b/src/components/form/range/__snapshots__/dual_range.test.js.snap
@@ -10,6 +10,7 @@ exports[`EuiDualRange allows value prop to accept empty strings 1`] = `
{
+ // Firefox returns `relatedTarget` as `null` for security reasons, but provides a proprietary `explicitOriginalTarget`
+ const relatedTarget = e.relatedTarget || e.explicitOriginalTarget;
+ if (!relatedTarget || relatedTarget.id !== this.state.id) {
+ this.closePopover();
+ }
+ };
+
closePopover = () => {
this.setState({
isPopoverOpen: false,
@@ -243,7 +253,7 @@ export class EuiDualRange extends Component {
disabled,
fullWidth,
readOnly,
- id,
+ id: propsId,
max,
min,
name,
@@ -261,6 +271,8 @@ export class EuiDualRange extends Component {
...rest
} = this.props;
+ const { id } = this.state;
+
const digitTolerance = Math.max(String(min).length, String(max).length);
const showInputOnly = showInput === 'only';
const canShowDropdown = showInputOnly && !readOnly && !disabled;
@@ -281,6 +293,7 @@ export class EuiDualRange extends Component {
aria-describedby={this.props['aria-describedby']}
aria-label={this.props['aria-label']}
onFocus={canShowDropdown ? this.onInputFocus : undefined}
+ onBlur={canShowDropdown ? this.onInputBlur : undefined}
readOnly={readOnly}
autoSize={!showInputOnly}
fullWidth={!!showInputOnly && fullWidth}
@@ -306,6 +319,7 @@ export class EuiDualRange extends Component {
aria-describedby={this.props['aria-describedby']}
aria-label={this.props['aria-label']}
onFocus={canShowDropdown ? this.onInputFocus : undefined}
+ onBlur={canShowDropdown ? this.onInputBlur : undefined}
readOnly={readOnly}
autoSize={!showInputOnly}
fullWidth={!!showInputOnly && fullWidth}
@@ -424,7 +438,8 @@ export class EuiDualRange extends Component {
}
fullWidth={fullWidth}
isOpen={this.state.isPopoverOpen}
- closePopover={this.closePopover}>
+ closePopover={this.closePopover}
+ disableFocusTrap={true}>
{theRange}
) : (
diff --git a/src/components/form/range/dual_range.test.js b/src/components/form/range/dual_range.test.js
index 4b96afebd01..39c9a2cb947 100644
--- a/src/components/form/range/dual_range.test.js
+++ b/src/components/form/range/dual_range.test.js
@@ -4,6 +4,8 @@ import { requiredProps } from '../../../test/required_props';
import { EuiDualRange } from './dual_range';
+jest.mock('../form_row/make_id', () => () => 'generated-id');
+
describe('EuiDualRange', () => {
test('is rendered', () => {
const component = render(
diff --git a/src/components/form/range/range.js b/src/components/form/range/range.js
index b760ecefec1..7be1b7dcc57 100644
--- a/src/components/form/range/range.js
+++ b/src/components/form/range/range.js
@@ -4,6 +4,7 @@ import classNames from 'classnames';
import { isWithinRange } from '../../../services/number';
import { EuiInputPopover } from '../../popover';
+import makeId from '../form_row/make_id';
import { EuiRangeHighlight } from './range_highlight';
import { EuiRangeInput } from './range_input';
@@ -17,6 +18,7 @@ export class EuiRange extends Component {
constructor(props) {
super(props);
this.state = {
+ id: props.id || makeId(),
isPopoverOpen: false,
};
}
@@ -40,6 +42,14 @@ export class EuiRange extends Component {
});
};
+ onInputBlur = e => {
+ // Firefox returns `relatedTarget` as `null` for security reasons, but provides a proprietary `explicitOriginalTarget`
+ const relatedTarget = e.relatedTarget || e.explicitOriginalTarget;
+ if (!relatedTarget || relatedTarget.id !== this.state.id) {
+ this.closePopover();
+ }
+ };
+
closePopover = () => {
this.setState({
isPopoverOpen: false,
@@ -53,7 +63,7 @@ export class EuiRange extends Component {
disabled,
fullWidth,
readOnly,
- id,
+ id: propsId,
max,
min,
name,
@@ -75,6 +85,8 @@ export class EuiRange extends Component {
...rest
} = this.props;
+ const { id } = this.state;
+
const digitTolerance = Math.max(String(min).length, String(max).length);
const showInputOnly = showInput === 'only';
const canShowDropdown = showInputOnly && !readOnly && !disabled;
@@ -92,6 +104,7 @@ export class EuiRange extends Component {
onChange={this.handleOnChange}
name={name}
onFocus={canShowDropdown ? this.onInputFocus : undefined}
+ onBlur={canShowDropdown ? this.onInputBlur : undefined}
fullWidth={showInputOnly && fullWidth}
autoSize={!showInputOnly}
{...rest}
@@ -180,7 +193,8 @@ export class EuiRange extends Component {
input={theInput}
fullWidth={fullWidth}
isOpen={this.state.isPopoverOpen}
- closePopover={this.closePopover}>
+ closePopover={this.closePopover}
+ disableFocusTrap={true}>
{theRange}
) : (
diff --git a/src/components/form/range/range.test.js b/src/components/form/range/range.test.js
index b645f82bcbf..33495ea665d 100644
--- a/src/components/form/range/range.test.js
+++ b/src/components/form/range/range.test.js
@@ -4,6 +4,8 @@ import { requiredProps } from '../../../test/required_props';
import { EuiRange } from './range';
+jest.mock('../form_row/make_id', () => () => 'generated-id');
+
describe('EuiRange', () => {
test('is rendered', () => {
const component = render(
diff --git a/src/components/popover/input_popover.tsx b/src/components/popover/input_popover.tsx
index 6659708b0aa..8145f91dfb4 100644
--- a/src/components/popover/input_popover.tsx
+++ b/src/components/popover/input_popover.tsx
@@ -15,6 +15,7 @@ import { cascadingMenuKeyCodes } from '../../services';
interface EuiInputPopoverProps
extends Omit {
+ disableFocusTrap?: boolean;
fullWidth?: boolean;
input: EuiPopoverProps['button'];
inputRef?: EuiPopoverProps['buttonRef'];
@@ -27,6 +28,7 @@ type Props = CommonProps &
export const EuiInputPopover: FunctionComponent = ({
children,
className,
+ disableFocusTrap = false,
input,
fullWidth = false,
...props
@@ -68,8 +70,9 @@ export const EuiInputPopover: FunctionComponent = ({
);
});
if (
- tabbableItems.length &&
- tabbableItems[tabbableItems.length - 1] === document.activeElement
+ disableFocusTrap ||
+ (tabbableItems.length &&
+ tabbableItems[tabbableItems.length - 1] === document.activeElement)
) {
props.closePopover();
}
@@ -96,7 +99,7 @@ export const EuiInputPopover: FunctionComponent = ({
panelRef={panelRef}
className={classes}
{...props}>
-
+
{children}