Select: fixes so component loses focus on selecting value or pressing outside of input. (#24008)
* changed the value container to a class component to get it to work with focus (maybe something with context?).
* added e2e tests to verify that the select focus is working as it should.
* fixed according to feedback.
* updated snapshot.
(cherry picked from commit be8c62033c)
This commit is contained in:
committed by
Arve Knudsen
parent
b09c75afab
commit
b4e2276d48
@@ -0,0 +1,40 @@
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
e2e.scenario({
|
||||
describeName: 'Select focus/unfocus tests',
|
||||
itName: 'Tests select focus/unfocus scenarios',
|
||||
addScenarioDataSource: false,
|
||||
addScenarioDashBoard: false,
|
||||
skipScenario: false,
|
||||
scenario: () => {
|
||||
e2e.flows.openDashboard('5SdHCadmz');
|
||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||
|
||||
e2e.components.FolderPicker.container()
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
|
||||
e2e.components.Select.option()
|
||||
.should('be.visible')
|
||||
.first()
|
||||
.click();
|
||||
|
||||
e2e.components.Select.input()
|
||||
.should('be.visible')
|
||||
.should('have.focus');
|
||||
});
|
||||
|
||||
e2e.pages.Dashboard.Settings.General.title().click();
|
||||
|
||||
e2e.components.FolderPicker.container()
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input()
|
||||
.should('be.visible')
|
||||
.should('not.have.focus');
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -98,6 +98,7 @@ export const Components = {
|
||||
},
|
||||
Select: {
|
||||
option: 'Select option',
|
||||
input: () => 'input[id*="react-select-"]',
|
||||
},
|
||||
FieldConfigEditor: {
|
||||
content: 'Field config editor content',
|
||||
@@ -105,4 +106,7 @@ export const Components = {
|
||||
OverridesConfigEditor: {
|
||||
content: 'Field overrides editor content',
|
||||
},
|
||||
FolderPicker: {
|
||||
container: 'Folder picker select container',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -49,6 +49,7 @@ export const Pages = {
|
||||
sectionItems: (item: string) => `Dashboard settings section item ${item}`,
|
||||
saveDashBoard: 'Dashboard settings aside actions Save button',
|
||||
saveAsDashBoard: 'Dashboard settings aside actions Save As button',
|
||||
title: 'Dashboard settings page title',
|
||||
},
|
||||
Variables: {
|
||||
List: {
|
||||
|
||||
@@ -231,22 +231,7 @@ export function SelectBase<T>({
|
||||
components={{
|
||||
MenuList: SelectMenu,
|
||||
Group: SelectOptionGroup,
|
||||
ValueContainer: (props: any) => {
|
||||
const { menuIsOpen } = props.selectProps;
|
||||
if (
|
||||
Array.isArray(props.children) &&
|
||||
Array.isArray(props.children[0]) &&
|
||||
maxVisibleValues !== undefined &&
|
||||
!(showAllSelectedWhenOpen && menuIsOpen)
|
||||
) {
|
||||
const [valueChildren, ...otherChildren] = props.children;
|
||||
const truncatedValues = valueChildren.slice(0, maxVisibleValues);
|
||||
|
||||
return <ValueContainer {...props} children={[truncatedValues, ...otherChildren]} />;
|
||||
}
|
||||
|
||||
return <ValueContainer {...props} />;
|
||||
},
|
||||
ValueContainer,
|
||||
Placeholder: (props: any) => (
|
||||
<div
|
||||
{...props.innerProps}
|
||||
|
||||
@@ -1,11 +1,36 @@
|
||||
import React from 'react';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { cx } from 'emotion';
|
||||
import { useTheme } from '../../themes/ThemeContext';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { withTheme } from '../../themes/ThemeContext';
|
||||
import { getSelectStyles } from './getSelectStyles';
|
||||
|
||||
export const ValueContainer = (props: any) => {
|
||||
const theme = useTheme();
|
||||
const styles = getSelectStyles(theme);
|
||||
const { children, isMulti } = props;
|
||||
return <div className={cx(styles.valueContainer, isMulti && styles.valueContainerMulti)}>{children}</div>;
|
||||
};
|
||||
class UnthemedValueContainer extends React.Component<any & { theme: GrafanaTheme }> {
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const { selectProps } = this.props;
|
||||
|
||||
if (
|
||||
selectProps &&
|
||||
Array.isArray(children) &&
|
||||
Array.isArray(children[0]) &&
|
||||
selectProps.maxVisibleValues !== undefined &&
|
||||
!(selectProps.showAllSelectedWhenOpen && selectProps.menuIsOpen)
|
||||
) {
|
||||
const [valueChildren, ...otherChildren] = children;
|
||||
const truncatedValues = valueChildren.slice(0, selectProps.maxVisibleValues);
|
||||
|
||||
return this.renderContainer([truncatedValues, ...otherChildren]);
|
||||
}
|
||||
|
||||
return this.renderContainer(children);
|
||||
}
|
||||
|
||||
renderContainer(children?: ReactNode) {
|
||||
const { isMulti, theme } = this.props;
|
||||
const styles = getSelectStyles(theme);
|
||||
const className = cx(styles.valueContainer, isMulti && styles.valueContainerMulti);
|
||||
return <div className={className}>{children}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export const ValueContainer = withTheme(UnthemedValueContainer);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { debounce } from 'lodash';
|
||||
import { AsyncSelect } from '@grafana/ui';
|
||||
import { AppEvents, SelectableValue } from '@grafana/data';
|
||||
import { debounce } from 'lodash';
|
||||
import appEvents from '../../app_events';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import appEvents from '../../app_events';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { DashboardSearchHit } from 'app/features/search/types';
|
||||
|
||||
@@ -148,7 +149,7 @@ export class FolderPicker extends PureComponent<Props, State> {
|
||||
const { enableCreateNew, useNewForms } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div aria-label={selectors.components.FolderPicker.container}>
|
||||
{useNewForms && (
|
||||
<AsyncSelect
|
||||
loadingMessage="Loading folders..."
|
||||
@@ -180,7 +181,7 @@ export class FolderPicker extends PureComponent<Props, State> {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FolderPicker should render 1`] = `
|
||||
<Fragment>
|
||||
<div
|
||||
aria-label="Folder picker select container"
|
||||
>
|
||||
<div
|
||||
className="gf-form-inline"
|
||||
>
|
||||
@@ -26,5 +28,5 @@ exports[`FolderPicker should render 1`] = `
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</aside>
|
||||
|
||||
<div class="dashboard-settings__content" ng-if="ctrl.viewId === 'settings'">
|
||||
<h3 class="dashboard-settings__header">
|
||||
<h3 class="dashboard-settings__header" aria-label="{{::ctrl.selectors.title}}">
|
||||
General
|
||||
</h3>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user