textarea.tsx 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import {forwardRef} from 'react';
  2. import TextareaAutosize from 'react-autosize-textarea';
  3. import isPropValid from '@emotion/is-prop-valid';
  4. import styled from '@emotion/styled';
  5. import {inputStyles} from 'sentry/styles/input';
  6. import space from 'sentry/styles/space';
  7. type InputProps = Omit<Parameters<typeof inputStyles>[0], 'theme'>;
  8. export interface TextAreaProps
  9. extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'css'>,
  10. InputProps {
  11. /**
  12. * Enable autosizing of the textarea.
  13. */
  14. autosize?: boolean;
  15. /**
  16. * Max number of rows to default to.
  17. */
  18. maxRows?: number;
  19. /**
  20. * Number of rows to default to.
  21. */
  22. rows?: number;
  23. }
  24. const TextAreaControl = forwardRef(function TextAreaControl(
  25. {autosize, rows, maxRows, ...p}: TextAreaProps,
  26. ref: React.Ref<HTMLTextAreaElement>
  27. ) {
  28. return autosize ? (
  29. <TextareaAutosize {...p} async ref={ref} rows={rows ? rows : 2} maxRows={maxRows} />
  30. ) : (
  31. <textarea ref={ref} {...p} />
  32. );
  33. });
  34. TextAreaControl.displayName = 'TextAreaControl';
  35. const propFilter = (p: string) =>
  36. ['autosize', 'rows', 'maxRows'].includes(p) || isPropValid(p);
  37. const TextArea = styled(TextAreaControl, {shouldForwardProp: propFilter})`
  38. ${inputStyles};
  39. min-height: 40px;
  40. padding: calc(${space(1)} - 1px) ${space(1)};
  41. line-height: 1.5em;
  42. ${p =>
  43. p.autosize &&
  44. `
  45. height: auto;
  46. padding: calc(${space(1)} - 2px) ${space(1)};
  47. line-height: 1.6em;
  48. `}
  49. `;
  50. export default TextArea;