Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-stickynode

Package Overview
Dependencies
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-stickynode - npm Package Compare versions

Comparing version 1.0.2 to 1.0.3

.eslintcache

523

dist/Sticky.js

@@ -9,2 +9,10 @@ /**

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 _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
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; }
var React = require('react');

@@ -49,29 +57,12 @@

var Sticky = React.createClass({
displayName: 'Sticky',
var Sticky = (function (_React$Component) {
_inherits(Sticky, _React$Component);
autobind: false,
/**
* @param {Bool} enabled A switch to enable or disable Sticky.
* @param {String/Number} top A top offset px for Sticky. Could be a selector representing a node
* whose height should serve as the top offset.
* @param {String/Number} bottomBoundary A bottom boundary px on document where Sticky will stop.
* Could be a selector representing a node whose bottom should serve as the bottom boudary.
*/
propTpes: {
enabled: propTypes.bool,
top: propTypes.oneOfType([propTypes.string, propTypes.number]),
bottomBoundary: propTypes.oneOfType([propTypes.object, // TODO, may remove
propTypes.string, propTypes.number])
},
function Sticky(props, context) {
_classCallCheck(this, Sticky);
getDefaultProps: function getDefaultProps() {
return {
enabled: true,
top: 0,
bottomBoundary: 0
};
},
getInitialState: function getInitialState() {
_get(Object.getPrototypeOf(Sticky.prototype), 'constructor', this).call(this, props, context);
this.handleResize = this.handleResize.bind(this);
this.handleScroll = this.handleScroll.bind(this);
this.handleScrollStart = this.handleScrollStart.bind(this);
this.delta = 0;

@@ -85,3 +76,3 @@ this.stickyTop = 0;

return {
this.state = {
top: 0, // A top offset px from screen top for Sticky when scrolling down

@@ -98,253 +89,295 @@ bottom: 0, // A bottom offset px from screen top for Sticky when scrolling up *1*

};
// *1* When Sticky is higher then screen, it will be screen bottom.
// When Sticky is shorter, it will be the difference of Sticky bottom and screen top.
},
}
getTargetHeight: function getTargetHeight(target) {
return target && target.offsetHeight || 0;
},
getTopPosition: function getTopPosition() {
var self = this;
// TODO, topTarget is for current layout, may remove
var top = self.props.top || self.props.topTarget || 0;
if (typeof top === 'string') {
if (!self.topTarget) {
self.topTarget = doc.querySelector(top);
_createClass(Sticky, [{
key: 'getTargetHeight',
value: function getTargetHeight(target) {
return target && target.offsetHeight || 0;
}
}, {
key: 'getTopPosition',
value: function getTopPosition() {
var self = this;
// TODO, topTarget is for current layout, may remove
var top = self.props.top || self.props.topTarget || 0;
if (typeof top === 'string') {
if (!self.topTarget) {
self.topTarget = doc.querySelector(top);
}
top = self.getTargetHeight(self.topTarget);
}
top = self.getTargetHeight(self.topTarget);
return top;
}
return top;
},
getTargetBottom: function getTargetBottom(target) {
if (!target) {
return -1;
}, {
key: 'getTargetBottom',
value: function getTargetBottom(target) {
if (!target) {
return -1;
}
var rect = target.getBoundingClientRect();
return scrollTop + rect.bottom;
}
var rect = target.getBoundingClientRect();
return scrollTop + rect.bottom;
},
}, {
key: 'getBottomBoundary',
value: function getBottomBoundary() {
var self = this;
getBottomBoundary: function getBottomBoundary() {
var self = this;
var boundary = self.props.bottomBoundary;
var boundary = self.props.bottomBoundary;
// TODO, bottomBoundary was an object, depricate it later.
if (typeof boundary === 'object') {
boundary = boundary.value || boundary.target || 0;
}
// TODO, bottomBoundary was an object, depricate it later.
if (typeof boundary === 'object') {
boundary = boundary.value || boundary.target || 0;
}
if (typeof boundary === 'string') {
if (!self.bottomBoundaryTarget) {
self.bottomBoundaryTarget = doc.querySelector(boundary);
if (typeof boundary === 'string') {
if (!self.bottomBoundaryTarget) {
self.bottomBoundaryTarget = doc.querySelector(boundary);
}
boundary = self.getTargetBottom(self.bottomBoundaryTarget);
}
boundary = self.getTargetBottom(self.bottomBoundaryTarget);
return boundary && boundary > 0 ? boundary : Infinity;
}
return boundary && boundary > 0 ? boundary : Infinity;
},
}, {
key: 'reset',
value: function reset() {
this.setState({
status: STATUS_ORIGINAL,
pos: 0
});
}
}, {
key: 'release',
value: function release(pos) {
this.setState({
status: STATUS_RELEASED,
pos: pos - this.state.y
});
}
}, {
key: 'fix',
value: function fix(pos) {
this.setState({
status: STATUS_FIXED,
pos: pos
});
}
reset: function reset() {
this.setState({
status: STATUS_ORIGINAL,
pos: 0
});
},
/**
* Update the initial position, width, and height. It should update whenever children change.
*/
}, {
key: 'updateInitialDimension',
value: function updateInitialDimension() {
var self = this;
release: function release(pos) {
this.setState({
status: STATUS_RELEASED,
pos: pos - this.state.y
});
},
self.timer = +new Date();
var outer = self.refs.outer;
var inner = self.refs.inner;
var outerRect = outer.getBoundingClientRect();
fix: function fix(pos) {
this.setState({
status: STATUS_FIXED,
pos: pos
});
},
var width = outer.offsetWidth;
var height = inner.offsetHeight;
var outerY = outerRect.top + scrollTop;
/**
* Update the initial position, width, and height. It should update whenever children change.
*/
updateInitialDimension: function updateInitialDimension() {
var self = this;
self.setState({
top: self.getTopPosition(),
bottom: Math.min(self.state.top + height, winHeight),
width: width,
height: height,
x: outerRect.left,
y: outerY,
bottomBoundary: self.getBottomBoundary(),
topBoundary: outerY
});
}
}, {
key: 'handleResize',
value: function handleResize(e, ae) {
winHeight = ae.resize.height;
this.updateInitialDimension();
this.update();
}
}, {
key: 'handleScrollStart',
value: function handleScrollStart(e, ae) {
scrollTop = ae.scroll.top;
this.updateInitialDimension();
}
}, {
key: 'handleScroll',
value: function handleScroll(e, ae) {
scrollDelta = ae.scroll.delta;
scrollTop = ae.scroll.top;
this.update();
}
self.timer = +new Date();
var outer = self.refs.outer;
var inner = self.refs.inner;
var outerRect = outer.getBoundingClientRect();
/**
* Update Sticky position.
* In this function, all coordinates of Sticky and scren are projected to document, so the local variables
* "top"/"bottom" mean the expected top/bottom of Sticky on document. They will move when scrolling.
*
* There are 2 principles to make sure Sticky won't get wrong so much:
* 1. Reset Sticky to the original postion when "top" <= topBoundary
* 2. Release Sticky to the bottom boundary when "bottom" >= bottomBoundary
*
* If "top" and "bottom" are between the boundaries, Sticky will always fix to the top of screen
* when it is shorter then screen. If Sticky is taller then screen, then it will
* 1. Fix to the bottom of screen when scrolling down and "bottom" > Sticky current bottom
* 2. Fix to the top of screen when scrolling up and "top" < Sticky current top
* (The above 2 points act kind of "bottom" dragging Sticky down or "top" dragging it up.)
* 3. Release Sticky when "top" and "bottom" are between Sticky current top and bottom.
*/
}, {
key: 'update',
value: function update() {
var self = this;
var width = outer.offsetWidth;
var height = inner.offsetHeight;
var outerY = outerRect.top + scrollTop;
if (self.state.bottomBoundary - self.state.topBoundary <= self.state.height || !self.props.enabled) {
if (self.state.status !== STATUS_ORIGINAL) {
self.reset();
}
return;
}
self.setState({
top: self.getTopPosition(),
bottom: Math.min(self.state.top + height, winHeight),
width: width,
height: height,
x: outerRect.left,
y: outerY,
bottomBoundary: self.getBottomBoundary(),
topBoundary: outerY
});
},
var delta = scrollDelta;
var top = scrollTop + self.state.top;
var bottom = scrollTop + self.state.bottom;
handleResize: function handleResize(e, ae) {
winHeight = ae.resize.height;
this.updateInitialDimension();
this.update();
},
handleScrollStart: function handleScrollStart(e, ae) {
scrollTop = ae.scroll.top;
this.updateInitialDimension();
},
handleScroll: function handleScroll(e, ae) {
scrollDelta = ae.scroll.delta;
scrollTop = ae.scroll.top;
this.update();
},
/**
* Update Sticky position.
* In this function, all coordinates of Sticky and scren are projected to document, so the local variables
* "top"/"bottom" mean the expected top/bottom of Sticky on document. They will move when scrolling.
*
* There are 2 principles to make sure Sticky won't get wrong so much:
* 1. Reset Sticky to the original postion when "top" <= topBoundary
* 2. Release Sticky to the bottom boundary when "bottom" >= bottomBoundary
*
* If "top" and "bottom" are between the boundaries, Sticky will always fix to the top of screen
* when it is shorter then screen. If Sticky is taller then screen, then it will
* 1. Fix to the bottom of screen when scrolling down and "bottom" > Sticky current bottom
* 2. Fix to the top of screen when scrolling up and "top" < Sticky current top
* (The above 2 points act kind of "bottom" dragging Sticky down or "top" dragging it up.)
* 3. Release Sticky when "top" and "bottom" are between Sticky current top and bottom.
*/
update: function update() {
var self = this;
if (self.state.bottomBoundary - self.state.topBoundary <= self.state.height || !self.props.enabled) {
if (self.state.status !== STATUS_ORIGINAL) {
if (top <= self.state.topBoundary) {
self.reset();
}
return;
}
var delta = scrollDelta;
var top = scrollTop + self.state.top;
var bottom = scrollTop + self.state.bottom;
if (top <= self.state.topBoundary) {
self.reset();
} else if (bottom >= self.state.bottomBoundary) {
self.stickyBottom = self.state.bottomBoundary;
self.stickyTop = self.stickyBottom - self.state.height;
self.release(self.stickyTop);
} else {
if (self.state.height > winHeight) {
// In this case, Sticky is larger then screen
switch (self.state.status) {
case STATUS_ORIGINAL:
self.release(self.state.y);
self.stickyTop = self.state.y;
self.stickyBottom = self.stickyTop + self.state.height;
break;
case STATUS_RELEASED:
if (delta > 0 && bottom > self.stickyBottom) {
// scroll down
self.fix(self.state.bottom - self.state.height);
} else if (delta < 0 && top < self.stickyTop) {
// scroll up
this.fix(self.state.top);
}
break;
case STATUS_FIXED:
var isChanged = true;
if (delta > 0 && self.state.pos === self.state.top) {
// scroll down
self.stickyTop = top - delta;
} else if (bottom >= self.state.bottomBoundary) {
self.stickyBottom = self.state.bottomBoundary;
self.stickyTop = self.stickyBottom - self.state.height;
self.release(self.stickyTop);
} else {
if (self.state.height > winHeight) {
// In this case, Sticky is larger then screen
switch (self.state.status) {
case STATUS_ORIGINAL:
self.release(self.state.y);
self.stickyTop = self.state.y;
self.stickyBottom = self.stickyTop + self.state.height;
} else if (delta < 0 && self.state.pos === self.state.bottom - self.state.height) {
// up
self.stickyBottom = bottom - delta;
self.stickyTop = self.stickyBottom - self.state.height;
} else {
isChanged = false;
}
break;
case STATUS_RELEASED:
if (delta > 0 && bottom > self.stickyBottom) {
// scroll down
self.fix(self.state.bottom - self.state.height);
} else if (delta < 0 && top < self.stickyTop) {
// scroll up
this.fix(self.state.top);
}
break;
case STATUS_FIXED:
var isChanged = true;
if (delta > 0 && self.state.pos === self.state.top) {
// scroll down
self.stickyTop = top - delta;
self.stickyBottom = self.stickyTop + self.state.height;
} else if (delta < 0 && self.state.pos === self.state.bottom - self.state.height) {
// up
self.stickyBottom = bottom - delta;
self.stickyTop = self.stickyBottom - self.state.height;
} else {
isChanged = false;
}
if (isChanged) {
self.release(self.stickyTop);
}
break;
if (isChanged) {
self.release(self.stickyTop);
}
break;
}
} else {
self.fix(self.state.top);
}
}
self.delta = delta;
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps() {
this.forceUpdate();
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
var subscribers = this.subscribers || [];
for (var i = subscribers.length - 1; i >= 0; i--) {
this.subscribers[i].unsubscribe();
}
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
var self = this;
if (self.props.enabled) {
self.updateInitialDimension();
self.subscribers = [subscribe('scrollStart', self.handleScrollStart.bind(self), { useRAF: true }), subscribe('scroll', self.handleScroll.bind(self), { useRAF: true, enableScrollInfo: true }), subscribe('resize', self.handleResize.bind(self), { enableResizeInfo: true })];
}
}
}, {
key: 'translate',
value: function translate(style, pos) {
if (enableTransforms) {
style[TRANSFORM_PROP] = 'translate3d(0,' + pos + 'px,0)';
} else {
self.fix(self.state.top);
style.top = pos;
}
}
self.delta = delta;
},
componentWillReceiveProps: function componentWillReceiveProps() {
this.forceUpdate();
},
componentWillUnmount: function componentWillUnmount() {
var subscribers = this.subscribers || [];
for (var i = subscribers.length - 1; i >= 0; i--) {
this.subscribers[i].unsubscribe();
}, {
key: 'shouldComponentUpdate',
value: function shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
},
}, {
key: 'render',
value: function render() {
var self = this;
// TODO, "overflow: auto" prevents collapse, need a good way to get children height
var style = {
overflow: 'hidden',
position: self.state.status === STATUS_FIXED ? 'fixed' : 'relative',
top: self.state.status === STATUS_FIXED ? '0' : ''
};
componentDidMount: function componentDidMount() {
var self = this;
if (self.props.enabled) {
self.updateInitialDimension();
self.subscribers = [subscribe('scrollStart', self.handleScrollStart.bind(self), { useRAF: true }), subscribe('scroll', self.handleScroll.bind(self), { useRAF: true, enableScrollInfo: true }), subscribe('resize', self.handleResize.bind(self), { enableResizeInfo: true })];
}
},
// always use translate3d to enhance the performance
self.translate(style, self.state.pos);
if (self.state.status !== STATUS_ORIGINAL) {
style.width = self.state.width;
}
translate: function translate(style, pos) {
if (enableTransforms) {
style[TRANSFORM_PROP] = 'translate3d(0,' + pos + 'px,0)';
} else {
style.top = pos;
return React.createElement(
'div',
{ ref: 'outer', className: classNames('sticky-outer-wrapper', self.props.className) },
React.createElement(
'div',
{ ref: 'inner', className: 'sticky-inner-wrapper', style: style },
self.props.children
)
);
}
},
}]);
shouldComponentUpdate: function shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
},
return Sticky;
})(React.Component);
render: function render() {
var self = this;
// TODO, "overflow: auto" prevents collapse, need a good way to get children height
var style = {
overflow: 'hidden',
position: self.state.status === STATUS_FIXED ? 'fixed' : 'relative',
top: self.state.status === STATUS_FIXED ? '0' : ''
};
Sticky.defaultProps = {
enabled: true,
top: 0,
bottomBoundary: 0
};
// always use translate3d to enhance the performance
self.translate(style, self.state.pos);
if (self.state.status !== STATUS_ORIGINAL) {
style.width = self.state.width;
}
/**
* @param {Bool} enabled A switch to enable or disable Sticky.
* @param {String/Number} top A top offset px for Sticky. Could be a selector representing a node
* whose height should serve as the top offset.
* @param {String/Number} bottomBoundary A bottom boundary px on document where Sticky will stop.
* Could be a selector representing a node whose bottom should serve as the bottom boudary.
*/
Sticky.propTypes = {
enabled: propTypes.bool,
top: propTypes.oneOfType([propTypes.string, propTypes.number]),
bottomBoundary: propTypes.oneOfType([propTypes.object, // TODO, may remove
propTypes.string, propTypes.number])
};
return React.createElement(
'div',
{ ref: 'outer', className: classNames('sticky-outer-wrapper', self.props.className) },
React.createElement(
'div',
{ ref: 'inner', className: 'sticky-inner-wrapper', style: style },
self.props.children
)
);
}
});
module.exports = Sticky;

@@ -9,3 +9,2 @@ // jscs:disable maximumLineLength

module.exports = function (grunt) {
// autoload installed tasks

@@ -147,6 +146,9 @@ [

},
command: 'node node_modules/istanbul/lib/cli.js cover --dir <%= project.coverage_dir %> -- ./node_modules/mocha/bin/_mocha <%= project.tmp %>/<%= project.unit %> --recursive --reporter xunit-file'
command: 'node node_modules/istanbul/lib/cli.js cover --dir <%= project.coverage_dir %> ' +
'-- ./node_modules/mocha/bin/_mocha <%= project.tmp %>/<%= project.unit %> ' +
'--recursive --reporter xunit-file'
},
mocha: {
command: './node_modules/mocha/bin/mocha <%= project.tmp %>/<%= project.unit %> --recursive --reporter spec'
command: './node_modules/mocha/bin/mocha <%= project.tmp %>/<%= project.unit %> ' +
'--recursive --reporter spec'
}

@@ -153,0 +155,0 @@ },

{
"name": "react-stickynode",
"version": "1.0.2",
"version": "1.0.3",
"description": "A performant and comprehensive React sticky",

@@ -10,3 +10,3 @@ "main": "index.js",

"func": "./tests/functional/saucelabs.sh",
"lint": "jshint",
"lint": "eslint --cache --ext .js,.jsx . --fix",
"test": "grunt cover"

@@ -41,2 +41,4 @@ },

"es5-shim": "^4.0.0",
"eslint-plugin-react": "^3.4.2",
"eslint": "^1.5.1",
"expect.js": "^0.3.1",

@@ -46,3 +48,3 @@ "grunt-atomizer": "^3.0.0",

"grunt-cli": "^0.1.13",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-clean": "^0.7.0",
"grunt-contrib-connect": "^0.11.2",

@@ -57,3 +59,2 @@ "grunt-contrib-jshint": "^0.11.2",

"jsdom": "^7.0.2",
"jshint": "^2.5.1",
"jsx-loader": "^0.13.2",

@@ -67,4 +68,50 @@ "jsx-test": "^0.8.0",

"react": "^0.14.2",
"xunit-file": "^0.0.8"
"xunit-file": "~0.0.9"
},
"eslintConfig": {
"rules": {
"space-before-function-paren": 2,
"valid-jsdoc": [
2,
{
"requireReturn": false,
"requireReturnDescription": false
}
],
"no-else-return": 2,
"no-extra-bind": 2,
"no-multi-spaces": 2,
"no-useless-call": 2,
"radix": 2,
"handle-callback-err": [
2,
"^(err|error)$"
],
"array-bracket-spacing": 2,
"block-spacing": 2,
"comma-spacing": 2,
"jsx-quotes": [
2,
"prefer-single"
],
"no-multiple-empty-lines": 2,
"no-trailing-spaces": 2,
"sort-vars": 2,
"space-after-keywords": 2,
"space-before-blocks": 2,
"space-infix-ops": 2,
"space-return-throw-case": 2,
"wrap-regex": 2,
"new-cap": 0
},
"plugins": [
"react"
],
"ecmaFeatures": {
"jsx": true
},
"env": {
"es6": true
}
},
"peerDependencies": {

@@ -71,0 +118,0 @@ "react": "^0.14.2",

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc