SearchField.tsx 2.6 KB

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