Skip to content

Commit

Permalink
Bump 0.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
kuy committed Jan 15, 2016
1 parent 07c1ed8 commit c716d71
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 10 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ npm run test:feature:ci
### TODO

+ Options to change offsets
+ Supports auto placement
+ Supports custom themes
+ Introduce ESLint
+ API documentation using ESDoc
Expand Down
1 change: 1 addition & 0 deletions lib/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var initial = {
show: false,
place: 'top',
el: null,
auto: true,
content: null,
timeout: null
};
Expand Down
17 changes: 11 additions & 6 deletions lib/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ var Tooltip = function (_Component) {
return {
// Props from state tree
show: _react.PropTypes.bool.isRequired,
place: _react.PropTypes.string.isRequired,
place: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.array]).isRequired,
el: _react.PropTypes.object,
content: _react.PropTypes.string,
auto: _react.PropTypes.bool.isRequired,
within: _react.PropTypes.func,

// Props from wrapper props
name: _react.PropTypes.string,
Expand All @@ -63,7 +65,8 @@ var Tooltip = function (_Component) {
get: function get() {
return {
show: false,
place: 'top'
place: 'top',
auto: true
};
}
}]);
Expand Down Expand Up @@ -99,21 +102,23 @@ var Tooltip = function (_Component) {
}, {
key: 'updatePosition',
value: function updatePosition(props) {
var offset = (0, _utils.placement)(props.place, this.refs.tooltip, props.el);
this.setState(offset);
var state = (0, _utils.adjust)(this.refs.tooltip, props);
this.setState(state);
}
}, {
key: 'render',
value: function render() {
var _props = this.props;
var content = _props.content;
var place = _props.place;
var onHover = _props.onHover;
var onLeave = _props.onLeave;
var _state = this.state;
var place = _state.place;
var offset = _state.offset;

var visibility = this.props.el && this.props.show ? 'visible' : 'hidden';
var style = {
base: _extends({}, styles.base, themes.simple.base, { visibility: visibility }, this.state),
base: _extends({}, styles.base, themes.simple.base, { visibility: visibility }, offset),
content: _extends({}, styles.content, themes.simple.content),
arrow: _extends({}, styles.arrow),
border: _extends({}, styles.border.base, styles.border[place], themes.simple.border)
Expand Down
185 changes: 183 additions & 2 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
'use strict';

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 _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.position = position;
exports.placement = placement;
exports.opposite = opposite;
exports.intersection = intersection;
exports.strip = strip;
exports.amend = amend;
exports.overDirs = overDirs;
exports.adjust = adjust;
exports.resolve = resolve;

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

/**
* Returns a position of given DOM element.
*
Expand Down Expand Up @@ -42,14 +55,14 @@ function position(el) {
* @param {string} place - 'top', 'right', 'bottom', or 'left'.
* @param {Object} tooltip - DOM element.
* @param {Object} origin - DOM element.
* @return {Object} contains 'top' and 'left' keys.
* @return {Object} contains 'top', 'left', and extra keys.
*/
function placement(place, tooltip, origin) {
var gap = 12;
var tip = position(tooltip);
var pos = position(origin);

var offset = {};
var offset = { width: tip.width, height: tip.height };

switch (place) {
case 'top':case 'bottom':
Expand Down Expand Up @@ -78,6 +91,174 @@ function placement(place, tooltip, origin) {
return offset;
}

/**
* Returns an opposite direction based on the given.
*
* @param {string|Array} dir - 'top', 'right', 'bottom', or 'left'.
* @return {string} an opposite direction.
* @throw
*/
function opposite(dir) {
var place = dir;

// Alrays use first direction if Array is passed
if ((typeof place === 'undefined' ? 'undefined' : _typeof(place)) === 'object' && typeof place.length === 'number' && 0 < place.length) {
place = place[0];
}

switch (place) {
case 'top':
return 'bottom';
case 'bottom':
return 'top';
case 'right':
return 'left';
case 'left':
return 'right';
}

throw new Error('Unknown direction: "' + dir + '"');
}

/**
* Calculates an intersection of two areas.
*
* @param {Object} area1
* @param {Object} area2
* @return {Object} an intersection.
*/
function intersection(area1, area2) {
var area = {};
area.top = Math.max(area1.top, area2.top);
area.right = Math.min(area1.left + area1.width, area2.left + area2.width);
area.bottom = Math.min(area1.top + area1.height, area2.top + area2.height);
area.left = Math.max(area1.left, area2.left);
area.height = area.bottom - area.top;
area.width = area.right - area.left;
return area;
}

function scrollOffset() {
var list = [document.documentElement, document.body.parentNode, document.body];
return {
top: list.map(function (el) {
return el.scrollTop;
}).reduce(function (p, v) {
return p || v;
}),
left: list.map(function (el) {
return el.scrollLeft;
}).reduce(function (p, v) {
return p || v;
})
};
}

// Returns current content area
function contentArea() {
return _extends({}, scrollOffset(), {
height: window.innerHeight,
width: window.innerWidth
});
}

// Strip unit string from property values and convert to float
var STRIP_FOR = ['top', 'left', 'right', 'bottom', 'width', 'height'];
function strip(obj) {
var data = _extends({}, obj);
STRIP_FOR.forEach(function (prop) {
if (typeof data[prop] === 'string') {
data[prop] = parseFloat(data[prop].replace('px', ''));
}
});
return data;
}

// Make full area data from minimum data
function amend(area) {
var data = strip(area);
if (typeof data.top !== 'number') {
data.top = 0;
}
if (typeof data.left !== 'number') {
data.left = 0;
}
if (typeof data.right !== 'number' && typeof data.width === 'number') {
data.right = data.left + data.width;
}
if (typeof data.bottom !== 'number' && typeof data.height === 'number') {
data.bottom = data.top + data.height;
}
return data;
}

// Returns directions which are not in target rectangle
function overDirs(tip, el) {
tip = amend(tip);
var area = amend(contentArea());
if (el && (typeof el === 'undefined' ? 'undefined' : _typeof(el)) === 'object') {
area = intersection(area, position(el));
}

var dirs = [];
if (tip.top < area.top) {
dirs.push('top');
}
if (area.right < tip.right) {
dirs.push('right');
}
if (area.bottom < tip.bottom) {
dirs.push('bottom');
}
if (tip.left < area.left) {
dirs.push('left');
}

return dirs;
}

/**
* Places and adjusts a tooltip.
*
* @param {Object} tooltip - DOM element.
* @param {string|Array} place
* @param {Object} origin - DOM element.
* @return {Object} 'offset': style data to locate, 'place': final direction of the tooltip
*/
function adjust(tooltip, props) {
var origin = props.el;
var auto = props.auto;
var within = props.within;
var place = props.place;

if (auto && typeof place === 'string') {
place = place.split(',').map(function (p) {
return p.trim();
});
}
if (place.length === 1) {
place.push(opposite(place));
}

var pos = undefined,
dirs = undefined,
current = undefined,
first = undefined;
var tries = [].concat(_toConsumableArray(place));
while (0 < tries.length) {
current = tries.shift();
pos = placement(current, tooltip, origin);
if (typeof first === 'undefined') {
first = { offset: pos, place: current };
}
dirs = overDirs(pos, within && within());
if (dirs.length === 0) {
return { offset: pos, place: current };
}
}
return first;
}

/**
* Resolves names of target tooltip from action or props.
*
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "redux-tooltip",
"version": "0.3.1",
"version": "0.4.0",
"description": "A tooltip React component for Redux",
"main": "./lib/index.js",
"repository": {
Expand Down

0 comments on commit c716d71

Please sign in to comment.