SearchField.tsx 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import React, { useContext } from 'react';
  2. import tinycolor from 'tinycolor2';
  3. import { SearchQuery } from './search';
  4. import { css, cx } from 'emotion';
  5. import { ThemeContext, GrafanaTheme, selectThemeVariant } from '@grafana/ui';
  6. type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
  7. interface SearchFieldProps extends Omit<React.HTMLAttributes<HTMLInputElement>, 'onChange'> {
  8. query: SearchQuery;
  9. onChange: (query: string) => void;
  10. onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
  11. }
  12. const getSearchFieldStyles = (theme: GrafanaTheme) => ({
  13. wrapper: css`
  14. width: 100%;
  15. height: 55px; /* this variable is not part of GrafanaTheme yet*/
  16. display: flex;
  17. background-color: ${selectThemeVariant(
  18. {
  19. light: theme.colors.white,
  20. dark: theme.colors.dark4,
  21. },
  22. theme.type
  23. )};
  24. position: relative;
  25. `,
  26. input: css`
  27. max-width: 653px;
  28. padding: ${theme.spacing.md} ${theme.spacing.md} ${theme.spacing.sm} ${theme.spacing.md};
  29. height: 51px;
  30. box-sizing: border-box;
  31. outline: none;
  32. background: ${selectThemeVariant(
  33. {
  34. light: theme.colors.dark1,
  35. dark: theme.colors.black,
  36. },
  37. theme.type
  38. )};
  39. background-color: ${selectThemeVariant(
  40. {
  41. light: tinycolor(theme.colors.white)
  42. .lighten(4)
  43. .toString(),
  44. dark: theme.colors.dark4,
  45. },
  46. theme.type
  47. )};
  48. flex-grow: 10;
  49. `,
  50. spacer: css`
  51. flex-grow: 1;
  52. `,
  53. icon: cx(
  54. css`
  55. font-size: ${theme.typography.size.lg};
  56. padding: ${theme.spacing.md} ${theme.spacing.md} ${theme.spacing.sm} ${theme.spacing.md};
  57. `,
  58. 'pointer'
  59. ),
  60. });
  61. export const SearchField: React.FunctionComponent<SearchFieldProps> = ({ query, onChange, ...inputProps }) => {
  62. const theme = useContext(ThemeContext);
  63. const styles = getSearchFieldStyles(theme);
  64. return (
  65. <>
  66. {/* search-field-wrapper class name left on purpose until we migrate entire search to React */}
  67. {/* based on it GrafanaCtrl (L256) decides whether or not hide search */}
  68. <div className={`${styles.wrapper} search-field-wrapper`}>
  69. <div className={styles.icon}>
  70. <i className="fa fa-search" />
  71. </div>
  72. <input
  73. type="text"
  74. placeholder="Find dashboards by name"
  75. value={query.query}
  76. onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
  77. onChange(event.currentTarget.value);
  78. }}
  79. tabIndex={1}
  80. spellCheck={false}
  81. {...inputProps}
  82. className={styles.input}
  83. />
  84. <div className={styles.spacer} />
  85. </div>
  86. </>
  87. );
  88. };