ResourcePicker.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import { css } from '@emotion/css';
  2. import React, { createRef } from 'react';
  3. import SVG from 'react-inlinesvg';
  4. import { GrafanaTheme2 } from '@grafana/data';
  5. import {
  6. Button,
  7. InlineField,
  8. InlineFieldRow,
  9. Input,
  10. LinkButton,
  11. Popover,
  12. PopoverController,
  13. useStyles2,
  14. useTheme2,
  15. } from '@grafana/ui';
  16. import { closePopover } from '@grafana/ui/src/utils/closePopover';
  17. import { getPublicOrAbsoluteUrl } from '../resource';
  18. import { MediaType, ResourceFolderName, ResourcePickerSize } from '../types';
  19. import { ResourcePickerPopover } from './ResourcePickerPopover';
  20. interface Props {
  21. onChange: (value?: string) => void;
  22. mediaType: MediaType;
  23. folderName: ResourceFolderName;
  24. size: ResourcePickerSize;
  25. onClear?: (event: React.MouseEvent) => void;
  26. value?: string; //img/icons/unicons/0-plus.svg
  27. src?: string;
  28. name?: string;
  29. placeholder?: string;
  30. color?: string;
  31. }
  32. export const ResourcePicker = (props: Props) => {
  33. const { value, src, name, placeholder, onChange, onClear, mediaType, folderName, size, color } = props;
  34. const styles = useStyles2(getStyles);
  35. const theme = useTheme2();
  36. const pickerTriggerRef = createRef<any>();
  37. const popoverElement = (
  38. <ResourcePickerPopover onChange={onChange} value={value} mediaType={mediaType} folderName={folderName} />
  39. );
  40. let sanitizedSrc = src;
  41. if (!sanitizedSrc && value) {
  42. sanitizedSrc = getPublicOrAbsoluteUrl(value);
  43. }
  44. const colorStyle = color && {
  45. fill: theme.visualization.getColorByName(color),
  46. };
  47. const renderSmallResourcePicker = () => {
  48. if (value && sanitizedSrc) {
  49. return <SVG src={sanitizedSrc} className={styles.icon} style={{ ...colorStyle }} />;
  50. } else {
  51. return (
  52. <LinkButton variant="primary" fill="text" size="sm">
  53. Set icon
  54. </LinkButton>
  55. );
  56. }
  57. };
  58. const renderNormalResourcePicker = () => (
  59. <InlineFieldRow>
  60. <InlineField label={null} grow>
  61. <Input
  62. value={name}
  63. placeholder={placeholder}
  64. readOnly={true}
  65. prefix={sanitizedSrc && <SVG src={sanitizedSrc} className={styles.icon} style={{ ...colorStyle }} />}
  66. suffix={<Button icon="times" variant="secondary" fill="text" size="sm" onClick={onClear} />}
  67. />
  68. </InlineField>
  69. </InlineFieldRow>
  70. );
  71. return (
  72. <PopoverController content={popoverElement}>
  73. {(showPopper, hidePopper, popperProps) => {
  74. return (
  75. <>
  76. {pickerTriggerRef.current && (
  77. <Popover
  78. {...popperProps}
  79. referenceElement={pickerTriggerRef.current}
  80. onMouseEnter={showPopper}
  81. onKeyDown={(event: any) => {
  82. closePopover(event, hidePopper);
  83. }}
  84. />
  85. )}
  86. <div ref={pickerTriggerRef} onClick={showPopper} className={styles.pointer}>
  87. {size === ResourcePickerSize.SMALL && renderSmallResourcePicker()}
  88. {size === ResourcePickerSize.NORMAL && renderNormalResourcePicker()}
  89. </div>
  90. </>
  91. );
  92. }}
  93. </PopoverController>
  94. );
  95. };
  96. const getStyles = (theme: GrafanaTheme2) => ({
  97. pointer: css`
  98. cursor: pointer;
  99. input[readonly] {
  100. cursor: pointer;
  101. }
  102. `,
  103. icon: css`
  104. vertical-align: middle;
  105. display: inline-block;
  106. fill: currentColor;
  107. width: 25px;
  108. `,
  109. });