diff --git a/dist/Portal.js b/dist/Portal.js new file mode 100644 index 0000000..776e0c7 --- /dev/null +++ b/dist/Portal.js @@ -0,0 +1,37 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = Portal; + +var _react = require('react'); + +var _reactDom = require('react-dom'); + +var _reactDom2 = _interopRequireDefault(_reactDom); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function Portal(_ref) { + var children = _ref.children; + + var elRef = (0, _react.useRef)(null); + if (!elRef.current) { + elRef.current = document.createElement('div'); + } + + (0, _react.useEffect)(function () { + var portalRoot = document.getElementById('portal-root'); + if (!portalRoot) { + return; + } + + portalRoot.appendChild(elRef.current); + return function () { + portalRoot.removeChild(elRef.current); + }; + }, []); + + return _reactDom2.default.createPortal(children, elRef.current); +} \ No newline at end of file diff --git a/dist/Tooltip.js b/dist/Tooltip.js new file mode 100644 index 0000000..184c0b8 --- /dev/null +++ b/dist/Tooltip.js @@ -0,0 +1,245 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _TooltipBubble = require('./TooltipBubble'); + +var _TooltipBubble2 = _interopRequireDefault(_TooltipBubble); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @class Tooltip + * @description The container of a lightweight and responsive tooltip. + */ + + +var Tooltip = function (_React$PureComponent) { + _inherits(Tooltip, _React$PureComponent); + + function Tooltip() { + _classCallCheck(this, Tooltip); + + var _this = _possibleConstructorReturn(this, (Tooltip.__proto__ || Object.getPrototypeOf(Tooltip)).call(this)); + + _this.target = null; + _this.tip = null; + + + _this.state = { + showTip: false, + hasHover: false + }; + + _this.target = _react2.default.createRef(); + _this.tip = _react2.default.createRef(); + + _this.showTip = _this.showTip.bind(_this); + _this.hideTip = _this.hideTip.bind(_this); + _this.checkHover = _this.checkHover.bind(_this); + _this.toggleTip = _this.toggleTip.bind(_this); + _this.startHover = _this.startHover.bind(_this); + _this.endHover = _this.endHover.bind(_this); + return _this; + } + + _createClass(Tooltip, [{ + key: 'componentDidMount', + value: function componentDidMount() { + // if the isOpen prop is passed on first render we need to immediately trigger a second render, + // because the tip ref is needed to calculate the position + if (this.props.isOpen) { + // eslint-disable-next-line react/no-did-mount-set-state + this.setState({ isOpen: true }); + } + } + }, { + key: 'toggleTip', + value: function toggleTip() { + this.setState({ showTip: !this.state.showTip }); + } + }, { + key: 'showTip', + value: function showTip() { + this.setState({ showTip: true }); + } + }, { + key: 'hideTip', + value: function hideTip() { + this.setState({ hasHover: false }); + this.setState({ showTip: false }); + } + }, { + key: 'startHover', + value: function startHover() { + this.setState({ hasHover: true }); + + setTimeout(this.checkHover, this.props.hoverDelay); + } + }, { + key: 'endHover', + value: function endHover() { + this.setState({ hasHover: false }); + + setTimeout(this.checkHover, this.props.hoverDelay); + } + }, { + key: 'checkHover', + value: function checkHover() { + this.setState({ showTip: this.state.hasHover }); + } + }, { + key: 'render', + value: function render() { + var _this2 = this; + + var _props = this.props, + direction = _props.direction, + className = _props.className, + padding = _props.padding, + children = _props.children, + content = _props.content, + eventOn = _props.eventOn, + eventOff = _props.eventOff, + eventToggle = _props.eventToggle, + useHover = _props.useHover, + background = _props.background, + color = _props.color, + useDefaultStyles = _props.useDefaultStyles, + isOpen = _props.isOpen, + tipContentHover = _props.tipContentHover, + arrow = _props.arrow, + arrowSize = _props.arrowSize, + distance = _props.distance, + others = _objectWithoutProperties(_props, ['direction', 'className', 'padding', 'children', 'content', 'eventOn', 'eventOff', 'eventToggle', 'useHover', 'background', 'color', 'useDefaultStyles', 'isOpen', 'tipContentHover', 'arrow', 'arrowSize', 'distance']); + + delete others.hoverDelay; + + var showTip = typeof isOpen === 'undefined' ? this.state.showTip : isOpen; + + var props = {}; + + // event handling + if (eventOff) { + props[eventOff] = this.hideTip; + } + + if (eventOn) { + props[eventOn] = this.showTip; + } + + if (eventToggle) { + props[eventToggle] = this.toggleTip; + + // only use hover if they don't have a toggle event + } else if (useHover) { + props.onMouseEnter = this.startHover; + props.onMouseLeave = tipContentHover ? this.endHover : this.hideTip; + props.onTouchStart = this.toggleTip; + } + + if (_react2.default.Children.count(children) !== 1) { + throw new Error('You must pass exactly one child element into Tooltip that it can attach to.'); + } + if (children.type.toString() === 'Symbol(react.fragment)') { + throw new Error('The one child element passed into Tooltip cannot be a React Fragment.'); + } + + // map other properties and most importantly, reference to the inner DOM component + var updatedChildren = _react2.default.Children.map(children, function (child) { + var additionalProps = _extends({}, props, others); + if (typeof child.type === 'function') { + // if the Tooltip is attaching to another React Component + // the inner React Component MUST handle the passing of the ref on its own (as well as spread other props (most importantly the events) + return _react2.default.cloneElement(child, _extends({ + innerRef: _this2.target + }, additionalProps)); + } + // or an HTML node + return _react2.default.cloneElement(child, _extends({ + ref: _this2.target + }, additionalProps)); + }); + return _react2.default.createElement( + _react2.default.Fragment, + null, + updatedChildren, + showTip && _react2.default.createElement(_TooltipBubble2.default, { + direction: direction, + className: className, + content: content, + background: background, + color: color, + padding: padding, + eventToggle: eventToggle, + useHover: useHover, + useDefaultStyles: useDefaultStyles, + tipContentHover: tipContentHover, + arrow: arrow, + arrowSize: arrowSize, + distance: distance, + target: this.target.current, + startHover: this.startHover, + endHover: this.endHover + }) + ); + } + }]); + + return Tooltip; +}(_react2.default.PureComponent); + +Tooltip.propTypes = { + direction: _propTypes2.default.string, + className: _propTypes2.default.string, + content: _propTypes2.default.node.isRequired, + background: _propTypes2.default.string, + color: _propTypes2.default.string, + padding: _propTypes2.default.string, + eventOn: _propTypes2.default.string, + eventOff: _propTypes2.default.string, + eventToggle: _propTypes2.default.string, + useHover: _propTypes2.default.bool, + useDefaultStyles: _propTypes2.default.bool, + isOpen: _propTypes2.default.bool, + hoverDelay: _propTypes2.default.number, + tipContentHover: _propTypes2.default.bool, + arrow: _propTypes2.default.bool, + arrowSize: _propTypes2.default.number, + distance: _propTypes2.default.number +}; +Tooltip.defaultProps = { + direction: 'up', + className: '', + background: '', + color: '', + padding: '10px', + useHover: true, + useDefaultStyles: false, + hoverDelay: 0, + tipContentHover: false, + arrow: true, + arrowSize: 10, + distance: undefined +}; +exports.default = Tooltip; \ No newline at end of file diff --git a/dist/TooltipBubble.js b/dist/TooltipBubble.js new file mode 100644 index 0000000..76a4a48 --- /dev/null +++ b/dist/TooltipBubble.js @@ -0,0 +1,176 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _Portal = require('./Portal'); + +var _Portal2 = _interopRequireDefault(_Portal); + +var _position = require('./position'); + +var _position2 = _interopRequireDefault(_position); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @class TooltipBubble + * @description A lightweight and responsive tooltip. + */ + + +// default colors +var defaultColor = '#fff'; +var defaultBg = '#333'; + +var stopProp = function stopProp(e) { + return e.stopPropagation(); +}; + +var TooltipBubble = function (_React$PureComponent) { + _inherits(TooltipBubble, _React$PureComponent); + + function TooltipBubble() { + _classCallCheck(this, TooltipBubble); + + var _this = _possibleConstructorReturn(this, (TooltipBubble.__proto__ || Object.getPrototypeOf(TooltipBubble)).call(this)); + + _this.tip = null; + + _this.tip = _react2.default.createRef(); + return _this; + } + + _createClass(TooltipBubble, [{ + key: 'componentDidMount', + value: function componentDidMount() { + // This is necessary because positions relies on the tooltip existing to determine the optimal location + this.forceUpdate(); + } + }, { + key: 'render', + value: function render() { + var _props = this.props, + direction = _props.direction, + className = _props.className, + padding = _props.padding, + content = _props.content, + eventToggle = _props.eventToggle, + useHover = _props.useHover, + background = _props.background, + color = _props.color, + useDefaultStyles = _props.useDefaultStyles, + tipContentHover = _props.tipContentHover, + arrow = _props.arrow, + arrowSize = _props.arrowSize, + distance = _props.distance, + target = _props.target, + startHover = _props.startHover, + endHover = _props.endHover; + + + var currentPositions = (0, _position2.default)(direction, this.tip.current, target, { + background: useDefaultStyles ? defaultBg : background, + arrow: arrow, + arrowSize: arrowSize, + distance: distance + }); + + var tipStyles = _extends({}, currentPositions.tip, { + background: useDefaultStyles ? defaultBg : background, + color: useDefaultStyles ? defaultColor : color, + padding: padding, + boxSizing: 'border-box', + zIndex: 1000, + position: 'absolute', + display: 'inline-block' + }); + + var portalProps = { + // keep clicks on the tip from closing click controlled tips + onClick: stopProp + }; + + if (!eventToggle && useHover && tipContentHover) { + portalProps.onMouseEnter = startHover; + portalProps.onMouseLeave = endHover; + portalProps.onTouchStart = stopProp; + } + + return _react2.default.createElement( + _Portal2.default, + null, + _react2.default.createElement( + 'div', + _extends({}, portalProps, { className: className }), + _react2.default.createElement( + 'span', + { className: 'react-tooltip-lite', style: tipStyles, ref: this.tip }, + content + ), + currentPositions.arrow && _react2.default.createElement('span', { + className: 'react-tooltip-lite-arrow react-tooltip-lite-' + currentPositions.realDirection + '-arrow', + style: _extends({}, currentPositions.arrow, { + position: 'absolute', + width: 0, + height: 0, + zIndex: 1001 + }) + }) + ) + ); + } + }]); + + return TooltipBubble; +}(_react2.default.PureComponent); + +TooltipBubble.propTypes = { + direction: _propTypes2.default.string, + className: _propTypes2.default.string, + content: _propTypes2.default.node.isRequired, + background: _propTypes2.default.string, + color: _propTypes2.default.string, + padding: _propTypes2.default.string, + eventToggle: _propTypes2.default.string, + useHover: _propTypes2.default.bool, + useDefaultStyles: _propTypes2.default.bool, + tipContentHover: _propTypes2.default.bool, + arrow: _propTypes2.default.bool, + arrowSize: _propTypes2.default.number, + distance: _propTypes2.default.number, + target: _propTypes2.default.object, + startHover: _propTypes2.default.func, + endHover: _propTypes2.default.func +}; +TooltipBubble.defaultProps = { + direction: 'up', + className: '', + background: '', + color: '', + padding: '10px', + useHover: true, + useDefaultStyles: false, + tipContentHover: false, + arrow: true, + arrowSize: 10, + distance: undefined +}; +exports.default = TooltipBubble; \ No newline at end of file diff --git a/dist/getDirection.js b/dist/getDirection.js new file mode 100644 index 0000000..85623fe --- /dev/null +++ b/dist/getDirection.js @@ -0,0 +1,114 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = getDirection; + +var _position = require('./position'); + +function checkLeftRightWidthSufficient(tip, target, distance, bodyPadding) { + var targetRect = target.getBoundingClientRect(); + var deadSpace = Math.min(targetRect.left, document.documentElement.clientWidth - targetRect.right); + + return tip.offsetWidth + target.offsetWidth + distance + bodyPadding + deadSpace < document.documentElement.clientWidth; +} /** + * Checks the intended tip direction and falls back if not enough space + */ + + +function checkTargetFullyVisible(target) { + var bottomOverhang = target.getBoundingClientRect().bottom > window.innerHeight; + var topOverhang = target.getBoundingClientRect().top < 0; + + return !bottomOverhang && !topOverhang; +} + +function checkForArrowOverhang(props, arrowStyles, bodyPadding) { + var scrollLeft = (0, _position.getScrollLeft)(); + var hasLeftClearance = arrowStyles.left - scrollLeft > bodyPadding; + var hasRightClearance = arrowStyles.left + props.arrowSize * 2 < scrollLeft + document.documentElement.clientWidth - bodyPadding; + + return !hasLeftClearance || !hasRightClearance; +} + +function getDirection(currentDirection, tip, target, props, bodyPadding, arrowStyles, recursive) { + // can't switch until target is rendered + if (!target) { + return currentDirection; + } + + var targetRect = target.getBoundingClientRect(); + var arrowSpacing = (0, _position.getArrowSpacing)(props); + + // this is how much space is needed to display the tip above or below the target + var heightOfTipWithArrow = tip.offsetHeight + arrowSpacing + bodyPadding; + + var spaceBelowTarget = window.innerHeight - targetRect.bottom; + var spaceAboveTarget = targetRect.top; + + var hasSpaceBelow = spaceBelowTarget >= heightOfTipWithArrow; + var hasSpaceAbove = spaceAboveTarget >= heightOfTipWithArrow; + + switch (currentDirection) { + case 'right': + // if the window is not wide enough try top (which falls back to down) + if (!checkLeftRightWidthSufficient(tip, target, arrowSpacing, bodyPadding) || !checkTargetFullyVisible(target)) { + return getDirection('up', tip, target, arrowSpacing, bodyPadding, arrowStyles, true); + } + + if (document.documentElement.clientWidth - targetRect.right < tip.offsetWidth + arrowSpacing + bodyPadding) { + return 'left'; + } + + return 'right'; + + case 'left': + // if the window is not wide enough try top (which falls back to down) + if (!checkLeftRightWidthSufficient(tip, target, arrowSpacing, bodyPadding) || !checkTargetFullyVisible(target)) { + return getDirection('up', tip, target, arrowSpacing, bodyPadding, arrowStyles, true); + } + + if (targetRect.left < tip.offsetWidth + arrowSpacing + bodyPadding) { + return 'right'; + } + + return 'left'; + + case 'up': + if (!recursive && arrowStyles && checkForArrowOverhang(props, arrowStyles, bodyPadding)) { + return getDirection('left', tip, target, arrowSpacing, bodyPadding, arrowStyles, true); + } + + if (!hasSpaceAbove) { + if (hasSpaceBelow) { + return 'down'; + } else if (checkLeftRightWidthSufficient(tip, target, arrowSpacing, bodyPadding)) { + return getDirection('right', tip, target, arrowSpacing, bodyPadding, arrowStyles, true); + } + } + + return 'up'; + + case 'down': + default: + if (!recursive && arrowStyles && checkForArrowOverhang(props, arrowStyles, bodyPadding)) { + return getDirection('right', tip, target, arrowSpacing, bodyPadding, arrowStyles, true); + } + + if (!hasSpaceBelow) { + // if there's no space below, but space above, switch to that direction + if (hasSpaceAbove) { + return 'up'; + + // if there's no space above or below, check if there would be space left or right + } else if (checkLeftRightWidthSufficient(tip, target, arrowSpacing, bodyPadding)) { + return getDirection('right', tip, target, arrowSpacing, bodyPadding, arrowStyles, true); + } + + // if there's no space in any direction, default to the original direction + } + + return 'down'; + } +} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..b7e5a97 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,25 @@ +import type { PureComponent, ReactNode } from 'react'; + +export interface TooltipProps { + direction?: string; + className?: string; + content: ReactNode; + children?: ReactNode; + background?: string; + color?: string; + padding?: string; + distance?: number; + eventOff?: string; + eventOn?: string; + eventToggle?: string; + useHover?: boolean; + useDefaultStyles?: boolean; + isOpen?: boolean; + hoverDelay?: number; + tipContentHover?: boolean; + arrow?: boolean; + arrowSize?: number; +} + +export default class Tooltip extends PureComponent { +} diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..b6d6701 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,13 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _Tooltip = require('./Tooltip'); + +var _Tooltip2 = _interopRequireDefault(_Tooltip); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = _Tooltip2.default; \ No newline at end of file diff --git a/dist/position.js b/dist/position.js new file mode 100644 index 0000000..e519d28 --- /dev/null +++ b/dist/position.js @@ -0,0 +1,288 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** + * @file positions.js + * @description some functions for position calculation + */ + +exports.getScrollLeft = getScrollLeft; +exports.getArrowSpacing = getArrowSpacing; +exports.default = positions; + +var _getDirection = require('./getDirection'); + +var _getDirection2 = _interopRequireDefault(_getDirection); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var bodyPadding = 10; +var minArrowPadding = 5; +var noArrowDistance = 3; + +/** + * cross browser scroll positions + */ +function getScrollTop() { + return window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0; +} + +function getScrollLeft() { + return window.scrollX || document.documentElement.scrollLeft || document.body.scrollLeft || 0; +} + +/** + * Sets tip max width safely for mobile + */ +function getTipMaxWidth() { + return typeof document !== 'undefined' ? document.documentElement.clientWidth - bodyPadding * 2 : 1000; +} + +/** + * Parses align mode from direction if specified with hyphen, defaulting to middle if not - + * e.g. 'left-start' is mode 'start' and 'left' would be the default of 'middle' + */ +function parseAlignMode(direction) { + var directionArray = direction.split('-'); + if (directionArray.length > 1) { + return directionArray[1]; + } + return 'middle'; +} + +function getArrowSpacing(props) { + var defaultArrowSpacing = props.arrow ? props.arrowSize : noArrowDistance; + return typeof props.distance === 'number' ? props.distance : defaultArrowSpacing; +} + +/** + * Gets wrapper's left position for top/bottom tooltips as well as needed width restriction + */ +function getUpDownPosition(tip, target, direction, alignMode, props) { + var left = -10000000; + var top = void 0; + + var arrowSpacing = getArrowSpacing(props); + + if (tip) { + + // get wrapper left position + var scrollLeft = getScrollLeft(); + var targetRect = target.getBoundingClientRect(); + var targetLeft = targetRect.left + scrollLeft; + + var halfTargetWidth = Math.round(target.offsetWidth / 2); + var tipWidth = Math.min(getTipMaxWidth(), tip.offsetWidth); + var arrowCenter = targetLeft + halfTargetWidth; + var arrowLeft = arrowCenter - props.arrowSize; + var arrowRight = arrowCenter + props.arrowSize; + + if (alignMode === 'start') { + left = props.arrow ? Math.min(arrowLeft, targetLeft) : targetLeft; + } else if (alignMode === 'end') { + var rightWithArrow = Math.max(arrowRight, targetLeft + target.offsetWidth); + var rightEdge = props.arrow ? rightWithArrow : targetLeft + target.offsetWidth; + left = Math.max(rightEdge - tipWidth, bodyPadding + scrollLeft); + } else { + var centeredLeft = targetLeft + halfTargetWidth - Math.round(tipWidth / 2); + var availableSpaceOnLeft = bodyPadding + scrollLeft; + + left = Math.max(centeredLeft, availableSpaceOnLeft); + } + + // check for right overhang + var rightOfTip = left + tipWidth; + var rightOfScreen = scrollLeft + document.documentElement.clientWidth - bodyPadding; + var rightOverhang = rightOfTip - rightOfScreen; + if (rightOverhang > 0) { + left -= rightOverhang; + } + + if (direction === 'up') { + top = targetRect.top + getScrollTop() - (tip.offsetHeight + arrowSpacing); + } else { + top = targetRect.bottom + getScrollTop() + arrowSpacing; + } + } + + return { + left: left, + top: top + }; +} + +/** + * gets top position for left/right arrows + */ +function getLeftRightPosition(tip, target, direction, alignMode, props) { + var left = -10000000; + var top = 0; + + var arrowSpacing = getArrowSpacing(props); + var arrowPadding = props.arrow ? minArrowPadding : 0; + + if (tip) { + var scrollTop = getScrollTop(); + var scrollLeft = getScrollLeft(); + var targetRect = target.getBoundingClientRect(); + var targetTop = targetRect.top + scrollTop; + var halfTargetHeight = Math.round(target.offsetHeight / 2); + var arrowTop = targetTop + halfTargetHeight - props.arrowSize; + var arrowBottom = targetRect.top + scrollTop + halfTargetHeight + props.arrowSize; + + // TODO: handle close to edges better + if (alignMode === 'start') { + top = props.arrow ? Math.min(targetTop, arrowTop) : targetTop; + } else if (alignMode === 'end') { + var topForBottomAlign = targetRect.bottom + scrollTop - tip.offsetHeight; + top = props.arrow ? Math.max(topForBottomAlign, arrowBottom - tip.offsetHeight) : topForBottomAlign; + } else { + // default to middle, but don't go below body + var centeredTop = Math.max(targetTop + halfTargetHeight - Math.round(tip.offsetHeight / 2), bodyPadding + scrollTop); + + // make sure it doesn't go below the arrow + top = Math.min(centeredTop, arrowTop - arrowPadding); + } + + // check for bottom overhang + var bottomOverhang = top - scrollTop + tip.offsetHeight + bodyPadding - window.innerHeight; + if (bottomOverhang > 0) { + // try to add the body padding below the tip, but don't offset too far from the arrow + top = Math.max(top - bottomOverhang, arrowBottom + arrowPadding - tip.offsetHeight); + } + + if (direction === 'right') { + left = targetRect.right + arrowSpacing + scrollLeft; + } else { + left = targetRect.left - arrowSpacing - tip.offsetWidth + scrollLeft; + } + } + + return { + left: left, + top: top + }; +} + +/** + * sets the Arrow styles based on direction + */ +function getArrowStyles(target, direction, props) { + if (!target) { + return null; + } + + var targetRect = target.getBoundingClientRect(); + var halfTargetHeight = Math.round(target.offsetHeight / 2); + var halfTargetWidth = Math.round(target.offsetWidth / 2); + var scrollTop = getScrollTop(); + var scrollLeft = getScrollLeft(); + var arrowSpacing = getArrowSpacing(props); + var borderStyles = {}; + + switch (direction) { + case 'right': + borderStyles.borderTop = props.arrowSize + 'px solid transparent'; + borderStyles.borderBottom = props.arrowSize + 'px solid transparent'; + + if (props.background) { + borderStyles.borderRight = props.arrowSize + 'px solid ' + props.background; + } else { + borderStyles.borderRightWidth = props.arrowSize + 'px'; + borderStyles.borderRightStyle = 'solid'; + } + + return _extends({}, borderStyles, { + top: targetRect.top + scrollTop + halfTargetHeight - props.arrowSize, + left: targetRect.right + scrollLeft + arrowSpacing - props.arrowSize + }); + + case 'left': + borderStyles.borderTop = props.arrowSize + 'px solid transparent'; + borderStyles.borderBottom = props.arrowSize + 'px solid transparent'; + + if (props.background) { + borderStyles.borderLeft = props.arrowSize + 'px solid ' + props.background; + } else { + borderStyles.borderLeftWidth = props.arrowSize + 'px'; + borderStyles.borderLeftStyle = 'solid'; + } + + return _extends({}, borderStyles, { + top: targetRect.top + scrollTop + halfTargetHeight - props.arrowSize, + left: targetRect.left + scrollLeft - arrowSpacing - 1 + }); + + case 'up': + borderStyles.borderLeft = props.arrowSize + 'px solid transparent'; + borderStyles.borderRight = props.arrowSize + 'px solid transparent'; + + // if color is styled with css, we need everything except border-color, if styled with props, we add entire border rule + if (props.background) { + borderStyles.borderTop = props.arrowSize + 'px solid ' + props.background; + } else { + borderStyles.borderTopWidth = props.arrowSize + 'px'; + borderStyles.borderTopStyle = 'solid'; + } + + return _extends({}, borderStyles, { + left: Math.min(getScrollLeft() + getTipMaxWidth() - bodyPadding, targetRect.left + scrollLeft + halfTargetWidth - props.arrowSize), + top: targetRect.top + scrollTop - arrowSpacing + }); + + case 'down': + default: + borderStyles.borderLeft = props.arrowSize + 'px solid transparent'; + borderStyles.borderRight = props.arrowSize + 'px solid transparent'; + + if (props.background) { + borderStyles.borderBottom = '10px solid ' + props.background; + } else { + borderStyles.borderBottomWidth = props.arrowSize + 'px'; + borderStyles.borderBottomStyle = 'solid'; + } + + return _extends({}, borderStyles, { + left: Math.min(getScrollLeft() + getTipMaxWidth() - bodyPadding, targetRect.left + scrollLeft + halfTargetWidth - props.arrowSize), + top: targetRect.bottom + scrollTop + arrowSpacing - props.arrowSize + }); + } +} + +/** + * Returns the positions style rules + */ +function positions(direction, tip, target, props) { + var alignMode = parseAlignMode(direction); + var trimmedDirection = direction.split('-')[0]; + + var realDirection = trimmedDirection; + if (tip) { + var testArrowStyles = props.arrow && getArrowStyles(target, trimmedDirection, props); + realDirection = (0, _getDirection2.default)(trimmedDirection, tip, target, props, bodyPadding, testArrowStyles); + } + + var maxWidth = getTipMaxWidth(); + + // force the tip to display the width we measured everything at when visible, when scrolled + var width = void 0; + if (tip && getScrollLeft() > 0) { + // adding the exact width on the first render forces a bogus line break, so add 1px the first time + var spacer = tip.style.width ? 0 : 1; + width = Math.min(tip.offsetWidth, maxWidth) + spacer; + } + + var tipPosition = realDirection === 'up' || realDirection === 'down' ? getUpDownPosition(tip, target, realDirection, alignMode, props) : getLeftRightPosition(tip, target, realDirection, alignMode, props); + + return { + tip: _extends({}, tipPosition, { + maxWidth: maxWidth, + width: width + }), + arrow: tip && props.arrow ? getArrowStyles(target, realDirection, props) : null, + realDirection: realDirection + }; +} \ No newline at end of file diff --git a/dist/react-tooltip-lite.min.js b/dist/react-tooltip-lite.min.js new file mode 100644 index 0000000..17f86fd --- /dev/null +++ b/dist/react-tooltip-lite.min.js @@ -0,0 +1,6 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("React"),require("ReactDOM")):"function"==typeof define&&define.amd?define(["React","ReactDOM"],t):"object"==typeof exports?exports.ReactToolTipLite=t(require("React"),require("ReactDOM")):e.ReactToolTipLite=t(e.React,e.ReactDOM)}(this,function(e,t){return function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){e.exports=r(10)},function(e,t){function r(){throw new Error("setTimeout has not been defined")}function n(){throw new Error("clearTimeout has not been defined")}function o(e){if(f===setTimeout)return setTimeout(e,0);if((f===r||!f)&&setTimeout)return f=setTimeout,setTimeout(e,0);try{return f(e,0)}catch(t){try{return f.call(null,e,0)}catch(t){return f.call(this,e,0)}}}function i(e){if(s===clearTimeout)return clearTimeout(e);if((s===n||!s)&&clearTimeout)return s=clearTimeout,clearTimeout(e);try{return s(e)}catch(t){try{return s.call(null,e)}catch(t){return s.call(this,e)}}}function a(){v&&p&&(v=!1,p.length?h=p.concat(h):y=-1,h.length&&u())}function u(){if(!v){var e=o(a);v=!0;for(var t=h.length;t;){for(p=h,h=[];++y1)for(var r=1;r1?t[1]:"middle"}function c(e){var t=e.arrow?e.arrowSize:b;return"number"==typeof e.distance?e.distance:t}function l(e,t,r,n,u){var l=-1e7,f=void 0,s=c(u);if(e){var d=i(),p=t.getBoundingClientRect(),h=p.left+d,v=Math.round(t.offsetWidth/2),g=Math.min(a(),e.offsetWidth),b=h+v,m=b-u.arrowSize,w=b+u.arrowSize;if("start"===n)l=u.arrow?Math.min(m,h):h;else if("end"===n){var O=Math.max(w,h+t.offsetWidth),T=u.arrow?O:h+t.offsetWidth;l=Math.max(T-g,y+d)}else{var S=h+v-Math.round(g/2),x=y+d;l=Math.max(S,x)}var E=l+g,j=d+document.documentElement.clientWidth-y,k=E-j;k>0&&(l-=k),f="up"===r?p.top+o()-(e.offsetHeight+s):p.bottom+o()+s}return{left:l,top:f}}function f(e,t,r,n,a){var u=-1e7,l=0,f=c(a),s=a.arrow?g:0;if(e){var d=o(),p=i(),h=t.getBoundingClientRect(),v=h.top+d,b=Math.round(t.offsetHeight/2),m=v+b-a.arrowSize,w=h.top+d+b+a.arrowSize;if("start"===n)l=a.arrow?Math.min(v,m):v;else if("end"===n){var O=h.bottom+d-e.offsetHeight;l=a.arrow?Math.max(O,w-e.offsetHeight):O}else{var T=Math.max(v+b-Math.round(e.offsetHeight/2),y+d);l=Math.min(T,m-s)}var S=l-d+e.offsetHeight+y-window.innerHeight;S>0&&(l=Math.max(l-S,w+s-e.offsetHeight)),u="right"===r?h.right+f+p:h.left-f-e.offsetWidth+p}return{left:u,top:l}}function s(e,t,r){if(!e)return null;var n=e.getBoundingClientRect(),u=Math.round(e.offsetHeight/2),l=Math.round(e.offsetWidth/2),f=o(),s=i(),d=c(r),h={};switch(t){case"right":return h.borderTop=r.arrowSize+"px solid transparent",h.borderBottom=r.arrowSize+"px solid transparent",r.background?h.borderRight=r.arrowSize+"px solid "+r.background:(h.borderRightWidth=r.arrowSize+"px",h.borderRightStyle="solid"),p({},h,{top:n.top+f+u-r.arrowSize,left:n.right+s+d-r.arrowSize});case"left":return h.borderTop=r.arrowSize+"px solid transparent",h.borderBottom=r.arrowSize+"px solid transparent",r.background?h.borderLeft=r.arrowSize+"px solid "+r.background:(h.borderLeftWidth=r.arrowSize+"px",h.borderLeftStyle="solid"),p({},h,{top:n.top+f+u-r.arrowSize,left:n.left+s-d-1});case"up":return h.borderLeft=r.arrowSize+"px solid transparent",h.borderRight=r.arrowSize+"px solid transparent",r.background?h.borderTop=r.arrowSize+"px solid "+r.background:(h.borderTopWidth=r.arrowSize+"px",h.borderTopStyle="solid"),p({},h,{left:Math.min(i()+a()-y,n.left+s+l-r.arrowSize),top:n.top+f-d});case"down":default:return h.borderLeft=r.arrowSize+"px solid transparent",h.borderRight=r.arrowSize+"px solid transparent",r.background?h.borderBottom="10px solid "+r.background:(h.borderBottomWidth=r.arrowSize+"px",h.borderBottomStyle="solid"),p({},h,{left:Math.min(i()+a()-y,n.left+s+l-r.arrowSize),top:n.bottom+f+d-r.arrowSize})}}function d(e,t,r,n){var o=u(e),c=e.split("-")[0],d=c;if(t){var h=n.arrow&&s(r,c,n);d=(0,v.default)(c,t,r,n,y,h)}var g=a(),b=void 0;if(t&&i()>0){var m=t.style.width?0:1;b=Math.min(t.offsetWidth,g)+m}var w="up"===d||"down"===d?l(t,r,d,o,n):f(t,r,d,o,n);return{tip:p({},w,{maxWidth:g,width:b}),arrow:t&&n.arrow?s(r,d,n):null,realDirection:d}}Object.defineProperty(t,"__esModule",{value:!0});var p=Object.assign||function(e){for(var t=1;t=0||Object.prototype.hasOwnProperty.call(e,n)&&(r[n]=e[n]);return r}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function u(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var c=Object.assign||function(e){for(var t=1;twindow.innerHeight,r=e.getBoundingClientRect().top<0;return!t&&!r}function i(e,t,r){var n=(0,u.getScrollLeft)(),o=t.left-n>r,i=t.left+2*e.arrowSize=h,b=y>=h;switch(e){case"right":return n(t,r,p,l)&&o(r)?document.documentElement.clientWidth-d.right= 0.8" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1608,33 +1622,6 @@ "node": ">=0.10.0" } }, - "node_modules/cheerio": { - "version": "0.22.0", - "resolved": "http://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", - "dev": true, - "dependencies": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -1958,26 +1945,12 @@ "node": "*" } }, - "node_modules/css-select": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "dev": true, - "dependencies": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "node_modules/css-what": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.2.tgz", - "integrity": "sha512-wan8dMWQ0GUeF7DGEPVjhHemVW/vy6xUYmFzRY8RYqgA0JtXC9rJmbScBjqSu6dg9q0lwPQy6ZAmJVr3PPTvqQ==", + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "dev": true, - "engines": { - "node": "*" - } + "license": "MIT" }, "node_modules/d": { "version": "1.0.0", @@ -2162,22 +2135,6 @@ "node": ">=0.10.0" } }, - "node_modules/dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", - "dev": true, - "dependencies": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" - } - }, - "node_modules/dom-serializer/node_modules/domelementtype": { - "version": "1.1.3", - "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - }, "node_modules/domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -2188,31 +2145,6 @@ "npm": ">=1.2" } }, - "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "node_modules/domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dev": true, - "dependencies": { - "domelementtype": "1" - } - }, - "node_modules/domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "dev": true, - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2257,33 +2189,6 @@ "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", "dev": true }, - "node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "node_modules/enzyme": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-2.9.1.tgz", - "integrity": "sha1-B9XOaRJBJA+4F78sSxjW5TAkDfY=", - "dev": true, - "dependencies": { - "cheerio": "^0.22.0", - "function.prototype.name": "^1.0.0", - "is-subset": "^0.1.1", - "lodash": "^4.17.4", - "object-is": "^1.0.1", - "object.assign": "^4.0.4", - "object.entries": "^1.0.4", - "object.values": "^1.0.4", - "prop-types": "^15.5.10", - "uuid": "^3.0.1" - }, - "peerDependencies": { - "react": "0.13.x || 0.14.x || ^15.0.0-0 || 15.x" - } - }, "node_modules/errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", @@ -3814,20 +3719,6 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "node_modules/function.prototype.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.0.tgz", - "integrity": "sha512-Bs0VRrTz4ghD8pTmbJQD1mZ8A/mN0ur/jGz+A6FBxPDUPkm1tNfF6bhTYPA7i7aF4lZJVr+OXTNNrnnIl58Wfg==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "is-callable": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", @@ -4048,34 +3939,6 @@ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, - "node_modules/htmlparser2": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.0.tgz", - "integrity": "sha512-J1nEUGv+MkXS0weHNWVKJJ+UrLfePxRWpN3C9bEi9fLxL2+ggW94DQvgYVXsaT30PGwYRIZKNZXuyMhp3Di4bQ==", - "dev": true, - "dependencies": { - "domelementtype": "^1.3.0", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.0.6" - } - }, - "node_modules/htmlparser2/node_modules/readable-stream": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", - "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/http-errors": { "version": "1.6.3", "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -4590,12 +4453,6 @@ "node": ">= 0.4" } }, - "node_modules/is-subset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", - "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", - "dev": true - }, "node_modules/is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -4842,84 +4699,12 @@ "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", "dev": true }, - "node_modules/lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=", - "dev": true - }, - "node_modules/lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=", - "dev": true - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", - "dev": true - }, - "node_modules/lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=", - "dev": true - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", - "dev": true - }, - "node_modules/lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=", - "dev": true - }, - "node_modules/lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", - "dev": true - }, - "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", - "dev": true - }, "node_modules/lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", "dev": true }, - "node_modules/lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=", - "dev": true - }, - "node_modules/lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=", - "dev": true - }, - "node_modules/lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", - "dev": true - }, "node_modules/longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -5365,15 +5150,6 @@ "node": ">=0.10.0" } }, - "node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "dependencies": { - "boolbase": "~1.0.0" - } - }, "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -5423,15 +5199,6 @@ "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", "dev": true }, - "node_modules/object-is": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", - "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/object-keys": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", @@ -5526,21 +5293,6 @@ "node": ">=0.10.0" } }, - "node_modules/object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -6049,72 +5801,26 @@ } }, "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", "dev": true, "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/react-addons-test-utils": { - "version": "15.6.2", - "resolved": "https://registry.npmjs.org/react-addons-test-utils/-/react-addons-test-utils-15.6.2.tgz", - "integrity": "sha1-wStu/cIkfBDae4dw0YUICnsEcVY=", - "dev": true, - "peerDependencies": { - "react-dom": "^15.4.2" - } - }, "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", "dev": true, "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.26.0" }, "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-hot-api": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/react-hot-api/-/react-hot-api-0.4.7.tgz", - "integrity": "sha1-p+IqVtJS4Rq9k2a2EmTPRJLFgXE=", - "dev": true, - "peerDependencies": { - "react": ">=0.11.0 || ^0.14.0-rc" - } - }, - "node_modules/react-hot-loader": { - "version": "1.3.1", - "resolved": "http://registry.npmjs.org/react-hot-loader/-/react-hot-loader-1.3.1.tgz", - "integrity": "sha1-yVZHrni3Pfzv9uxx/8sEGC/22vk=", - "dev": true, - "dependencies": { - "react-hot-api": "^0.4.5", - "source-map": "^0.4.4" - } - }, - "node_modules/react-hot-loader/node_modules/source-map": { - "version": "0.4.4", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" + "react": "^19.1.1" } }, "node_modules/read-pkg": { @@ -6801,15 +6507,11 @@ "dev": true }, "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } + "license": "MIT" }, "node_modules/semver": { "version": "5.6.0", diff --git a/package.json b/package.json index 0fcbe83..8d96622 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@wowanalyzer/react-tooltip-lite", - "version": "3.2.0", + "version": "4.0.0", "description": "React tooltip, focused on simplicity and performance", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -32,9 +32,12 @@ "prop-types": "^15.5.8" }, "peerDependencies": { - "react": "^17.0.2" + "react": "^19.1.0", + "react-dom": "^19.1.0" }, "devDependencies": { + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", "babel-cli": "^6.10.1", "babel-core": "^6.18.2", "babel-eslint": "^6.0.4", @@ -42,7 +45,6 @@ "babel-preset-es2015": "^6.18.0", "babel-preset-react": "^6.16.0", "babel-preset-stage-0": "^6.16.0", - "enzyme": "^2.4.1", "eslint": "^3.11.1", "eslint-config-airbnb": "^13.0.0", "eslint-plugin-import": "^2.2.0", @@ -51,11 +53,9 @@ "eslint-plugin-react": "^6.7.1", "expect": "^1.20.2", "mocha": "^2.5.3", - "react": "^17.0.2", - "react-addons-test-utils": "^15.2.1", - "react-dom": "^17.0.2", - "react-hot-loader": "^1.3.1", + "react": "^19.1.0", + "react-dom": "^19.1.0", "webpack": "^1.13.3", "webpack-dev-server": "^1.16.2" } -} \ No newline at end of file +} diff --git a/src/index.d.ts b/src/index.d.ts index f2ebbb6..b7e5a97 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,11 +1,10 @@ -declare module '@wowanalyzer/react-tooltip-lite' { +import type { PureComponent, ReactNode } from 'react'; - import * as React from 'react'; - - export interface TooltipProps { +export interface TooltipProps { direction?: string; className?: string; - content: React.ReactNode; + content: ReactNode; + children?: ReactNode; background?: string; color?: string; padding?: string; @@ -20,9 +19,7 @@ declare module '@wowanalyzer/react-tooltip-lite' { tipContentHover?: boolean; arrow?: boolean; arrowSize?: number; - } - - export default class Tooltip extends React.PureComponent { - } +} +export default class Tooltip extends PureComponent { }