Guest User

Untitled

a guest
Dec 16th, 2017
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.04 KB | None | 0 0
  1. 'use strict';
  2.  
  3. import _ from 'lodash';
  4. import React from 'react';
  5. import { unstable_renderSubtreeIntoContainer, unmountComponentAtNode } from 'react-dom'; // eslint-disable-line camelcase
  6. import classNames from 'classnames';
  7. import TooltipJS from 'tooltip.js';
  8.  
  9. type Props = {
  10. className: string,
  11. element: string,
  12. label: React.ReactChild,
  13. placement?: 'top'|'right'|'bottom'|'left',
  14. };
  15.  
  16. export default class Tooltip extends React.Component<Props> {
  17. static defaultProps = {
  18. element: 'div',
  19. };
  20.  
  21. componentDidMount() {
  22. const { children, placement, className } = this.props;
  23. this.tooltipRoot = document.createElement('div');
  24. document.body.appendChild(this.tooltipRoot);
  25.  
  26. this.contentContainer = document.createElement('div');
  27. this._mountContent(children, { placement, className });
  28. }
  29.  
  30. componentWillUpdate(nextProps: Props) {
  31. if (nextProps.children !== this.props.children) {
  32. const { children, placement, className } = nextProps;
  33. this._mountContent(children, { placement, className });
  34. }
  35. }
  36.  
  37. componentWillUnmount() {
  38. if (this.contentContainer) {
  39. const parent = this.contentContainer.parentElement;
  40. parent && parent.removeChild(this.contentContainer);
  41. }
  42.  
  43. this.tooltipRoot.parant && this.tooltipRoot.parant.removeChild(this.tooltipRoot);
  44. this.tooltipRoot = null;
  45. this.contentContainer = null;
  46. this.tooltip.dispose();
  47. }
  48.  
  49. /** ReactでマウントされたDOM要素のルート */
  50. rootEl: HTMLDivElement;
  51. /** ツールチップのマウント先要素 */
  52. tooltipRoot: HTMLDivElement;
  53. /** ツールチップに表示するコンテンツのコンテナ */
  54. contentContainer: HTMLDivElement;
  55. tooltip: any;
  56.  
  57. _bindRoot = el => this.rootEl = el
  58.  
  59. _mountContent(content: React.ReactChild, { placement, className }: { placement: string }) {
  60. unmountComponentAtNode(this.contentContainer);
  61. this.tooltip && this.tooltip.show().dispose(); // HACK: 一瞬マウントしないとdisposeされない
  62. this.tooltip = null;
  63.  
  64. // HACK: ツールチップは document.body に追加した div要素(= this.tooltipRoot)へマウントさせる。
  65. // そうしないとツールチップのコンテナ以上の要素が`overflow`に`hidden`や`scroll`を設定していた時に、ツールチップが見切れてしまう
  66.  
  67. if (_.isObject(content)) { // maybe ReactComponent
  68. unstable_renderSubtreeIntoContainer(this, content, this.contentContainer);
  69. this.tooltip = new TooltipJS(this.rootEl, { title: this.contentContainer, html: true, placement, container: this.tooltipRoot });
  70. } else {
  71. this.tooltip = new TooltipJS(this.rootEl, { title: content, placement, container: this.tooltipRoot });
  72. }
  73.  
  74. this.tooltip.show().hide(); // HACK: .show()でpopperInstanceを生成させている
  75. const node: HTMLElement = this.tooltip.popperInstance.popper;
  76. node.className = classNames('tooltip', className);
  77. }
  78.  
  79. render() {
  80. const { label, element: Element } = this.props;
  81.  
  82. return (
  83. <Element ref={this._bindRoot}>
  84. {label}
  85. </Element>
  86. );
  87. }
  88. }
Add Comment
Please, Sign In to add comment