Commit 1d7d72b4 by Torkel Ödegaard

wip: react select css refactoring

parent d9985271
......@@ -8,15 +8,16 @@ interface ExtendedOptionProps extends OptionProps<any> {
}
export const Option = (props: ExtendedOptionProps) => {
const { children, isSelected, data, className } = props;
const { children, isSelected, data } = props;
return (
<components.Option {...props}>
<div className={`description-picker-option__button btn btn-link ${className}`}>
{isSelected && <i className="fa fa-check pull-right" aria-hidden="true" />}
<div className="gf-form">{children}</div>
<div className="gf-form">
<div className="muted width-17">{data.description}</div>
<div className="gf-form-select-box__desc-option">
<div className="gf-form-select-box__desc-option__body">
<div>{children}</div>
{data.description && <div className="gf-form-select-box__desc-option__desc">{data.description}</div>}
</div>
{isSelected && <i className="fa fa-check" aria-hidden="true" />}
</div>
</components.Option>
);
......
// Libraries
import React, { PureComponent } from 'react';
import classNames from 'classnames';
import _ from 'lodash';
import KeyboardNavigation, { KeyboardNavigationProps } from './KeyboardNavigation';
// Components
import ResetStyles from 'app/core/components/Picker/ResetStyles';
import PickerOption from 'app/core/components/Picker/PickerOption';
import IndicatorsContainer from 'app/core/components/Picker/IndicatorsContainer';
import Select from 'react-select';
// Types
import { DataSourceSelectItem } from 'app/types';
export interface Props {
......@@ -10,127 +17,50 @@ export interface Props {
current: DataSourceSelectItem;
}
interface State {
searchQuery: string;
isOpen: boolean;
}
export class DataSourcePicker extends PureComponent<Props, State> {
export class DataSourcePicker extends PureComponent<Props> {
searchInput: HTMLElement;
constructor(props) {
super(props);
this.state = {
searchQuery: '',
isOpen: false,
};
}
getDataSources() {
const { searchQuery } = this.state;
const regex = new RegExp(searchQuery, 'i');
const { datasources } = this.props;
const filtered = datasources.filter(item => {
return regex.test(item.name) || regex.test(item.meta.name);
});
return filtered;
}
get maxSelectedIndex() {
const filtered = this.getDataSources();
return filtered.length - 1;
}
renderDataSource = (ds: DataSourceSelectItem, index: number, keyNavProps: KeyboardNavigationProps) => {
const { onChangeDataSource } = this.props;
const { selected, onMouseEnter } = keyNavProps;
const onClick = () => onChangeDataSource(ds);
const isSelected = selected === index;
const cssClass = classNames({
'ds-picker-list__item': true,
'ds-picker-list__item--selected': isSelected,
});
return (
<div key={index} className={cssClass} title={ds.name} onClick={onClick} onMouseEnter={() => onMouseEnter(index)}>
<img className="ds-picker-list__img" src={ds.meta.info.logos.small} />
<div className="ds-picker-list__name">{ds.name}</div>
</div>
);
onChange = item => {
const ds = this.props.datasources.find(ds => ds.name === item.value);
this.props.onChangeDataSource(ds);
};
componentDidMount() {
setTimeout(() => {
this.searchInput.focus();
}, 300);
}
render() {
const { datasources, current, onChangeDatasource } = this.props;
onSearchQueryChange = evt => {
const value = evt.target.value;
this.setState(prevState => ({
...prevState,
searchQuery: value,
const options = datasources.map(ds => ({
value: ds.name,
label: ds.name,
avatarUrl: ds.meta.info.logos.small,
}));
};
renderFilters({ onKeyDown, selected }: KeyboardNavigationProps) {
const { searchQuery } = this.state;
const value = { label: current.name, label: current.name };
return (
<label className="gf-form--has-input-icon">
<input
type="text"
className="gf-form-input width-13"
placeholder=""
ref={elem => (this.searchInput = elem)}
onChange={this.onSearchQueryChange}
value={searchQuery}
onKeyDown={evt => {
onKeyDown(evt, this.maxSelectedIndex, () => {
const { onChangeDataSource } = this.props;
const ds = this.getDataSources()[selected];
onChangeDataSource(ds);
});
<div className="gf-form-inline">
<Select
classNamePrefix={`gf-form-select-box`}
isMulti={false}
menuShouldScrollIntoView={false}
isClearable={false}
className="gf-form-input gf-form-input--form-dropdown ds-picker"
onChange={item => this.onChange(item)}
options={options}
styles={ResetStyles}
maxMenuHeight={500}
placeholder="Select datasource"
loadingMessage={() => 'Loading datasources...'}
noOptionsMessage={() => 'No datasources found'}
value={value}
components={{
Option: PickerOption,
IndicatorsContainer,
}}
/>
<i className="gf-form-input-icon fa fa-search" />
</label>
);
}
onOpen = () => {
this.setState({ isOpen: true });
};
render() {
const { current } = this.props;
const { isOpen } = this.state;
return (
<div className="ds-picker">
{!isOpen && (
<div className="toolbar__main" onClick={this.onOpen}>
<img className="toolbar__main-image" src={current.meta.info.logos.small} />
<div className="toolbar__main-name">{current.name}</div>
<i className="fa fa-caret-down" />
</div>
)}
{isOpen && (
<KeyboardNavigation
render={(keyNavProps: KeyboardNavigationProps) => (
<div className="ds-picker-menu">
<div className="cta-form__bar">
{this.renderFilters(keyNavProps)}
<div className="gf-form--grow" />
</div>
<div className="ds-picker-list">
{this.getDataSources().map((ds, index) => this.renderDataSource(ds, index, keyNavProps))}
</div>
</div>
)}
/>
)}
</div>
);
}
......
......@@ -9,3 +9,27 @@
padding-left: 2px;
}
}
.gf-form-select-box__desc-option {
display: flex;
align-items: center;
justify-content: flex-start;
justify-items: center;
cursor: pointer;
padding: 7px 10px;
width: 100%;
}
.gf-form-select-box__desc-option__body {
display: flex;
flex-direction: column;
flex-grow: 1;
padding-right: 10px;
font-weight: 500;
}
.gf-form-select-box__desc-option__desc {
font-weight: normal;
font-size: $font-size-sm;
color: $text-muted;
}
......@@ -50,9 +50,10 @@ $select-input-bg-disabled: $input-bg-disabled;
}
.gf-form-select-box__menu {
background: $dropdownBackground;
background: $input-bg;
position: absolute;
z-index: 2;
min-width: 100%;
}
.gf-form-select-box__menu-list {
......@@ -64,12 +65,16 @@ $select-input-bg-disabled: $input-bg-disabled;
width: 100%;
}
/* .gf-form-select-box__single-value { */
/* } */
.gf-form-select-box__multi-value {
display: inline;
}
.gf-form-select-box__option {
border-left: 2px solid transparent;
white-space: nowrap;
&.gf-form-select-box__option--is-focused {
color: $dropdownLinkColorHover;
......@@ -88,6 +93,9 @@ $select-input-bg-disabled: $input-bg-disabled;
display: none;
}
.gf-form-select-box__option {
}
.gf-form-select-box__value-container {
display: table-cell;
padding: 8px 10px;
......@@ -119,10 +127,12 @@ $select-input-bg-disabled: $input-bg-disabled;
border-width: 0 5px 5px;
}
}
.gf-form-input--form-dropdown {
padding: 0;
border: 0;
overflow: visible;
position: relative;
}
.gf-form--has-input-icon {
......
......@@ -275,6 +275,7 @@
.ds-picker {
position: relative;
min-width: 200px;
}
.ds-picker-menu {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment