autoSelectText.tsx 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import React, {CSSProperties} from 'react';
  2. import classNames from 'classnames';
  3. import {isRenderFunc} from 'app/utils/isRenderFunc';
  4. import {selectText} from 'app/utils/selectText';
  5. type ChildRenderProps = {
  6. doSelect: () => void;
  7. doMount: (el: HTMLElement) => void;
  8. };
  9. type ChildFunction = (props: ChildRenderProps) => React.ReactNode;
  10. type Props = {
  11. /**
  12. * Can be a `node` for a simple auto select div container.
  13. * When children is a render function, it is passed 2 functions:
  14. * - `doMount` - should be applied on parent element's `ref` whose
  15. * children is the text to be copied
  16. * - `doSelect` - selects text
  17. */
  18. children: React.ReactNode | ChildFunction;
  19. className?: string;
  20. style?: CSSProperties;
  21. };
  22. class AutoSelectText extends React.Component<Props> {
  23. private el: HTMLElement | undefined;
  24. selectText = () => {
  25. if (!this.el) {
  26. return;
  27. }
  28. selectText(this.el);
  29. };
  30. handleMount = (el: HTMLElement) => {
  31. this.el = el;
  32. };
  33. render() {
  34. const {children, className, ...props} = this.props;
  35. if (isRenderFunc<ChildFunction>(children)) {
  36. return children({
  37. doMount: this.handleMount,
  38. doSelect: this.selectText,
  39. });
  40. }
  41. // use an inner span here for the selection as otherwise the selectText
  42. // function will create a range that includes the entire part of the
  43. // div (including the div itself) which causes newlines to be selected
  44. // in chrome.
  45. return (
  46. <div
  47. {...props}
  48. onClick={this.selectText}
  49. className={classNames('auto-select-text', className)}
  50. >
  51. <span ref={this.handleMount}>{children}</span>
  52. </div>
  53. );
  54. }
  55. }
  56. export default AutoSelectText;