浏览代码

wip: react select css refactoring

Torkel Ödegaard 7 年之前
父节点
当前提交
1d7d72b49d

+ 7 - 6
public/app/core/components/Picker/DescriptionOption.tsx

@@ -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>
   );

+ 39 - 109
public/app/features/dashboard/dashgrid/DataSourcePicker.tsx

@@ -1,7 +1,14 @@
+// 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>
     );
   }

+ 24 - 0
public/sass/components/_description-picker.scss

@@ -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;
+}

+ 11 - 1
public/sass/components/_form_select_box.scss

@@ -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 {

+ 1 - 0
public/sass/components/_panel_editor.scss

@@ -275,6 +275,7 @@
 
 .ds-picker {
   position: relative;
+  min-width: 200px;
 }
 
 .ds-picker-menu {