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

react-stickynode

Package Overview
Dependencies
Maintainers
5
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 3.0.2 to 3.0.3

babel.config.json

893

dist/Sticky.js

@@ -5,44 +5,79 @@ /**

*/
/* global window, document */
'use strict';
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; }; })();
require("core-js/modules/es.symbol");
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); } } };
require("core-js/modules/es.symbol.description");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
require("core-js/modules/es.symbol.iterator");
require("core-js/modules/es.array.iterator");
require("core-js/modules/es.array.join");
require("core-js/modules/es.object.get-prototype-of");
require("core-js/modules/es.object.set-prototype-of");
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.reflect.construct");
require("core-js/modules/es.regexp.to-string");
require("core-js/modules/es.string.iterator");
require("core-js/modules/web.dom-collections.iterator");
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _subscribeUiEvent = require("subscribe-ui-event");
var _classnames = _interopRequireDefault(require("classnames"));
var _shallowequal = _interopRequireDefault(require("shallowequal"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
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; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var _react = require('react');
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); } }
var _react2 = _interopRequireDefault(_react);
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var _propTypes = require('prop-types');
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
var _propTypes2 = _interopRequireDefault(_propTypes);
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
var _subscribeUiEvent = require('subscribe-ui-event');
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
var _classnames = require('classnames');
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
var _classnames2 = _interopRequireDefault(_classnames);
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
var _shallowequal = require('shallowequal');
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
var _shallowequal2 = _interopRequireDefault(_shallowequal);
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
// constants
var STATUS_ORIGINAL = 0; // The default status, locating at the original position.
var STATUS_RELEASED = 1; // The released status, locating at somewhere on document but not default one.
var STATUS_FIXED = 2; // The sticky status, locating fixed to the top or the bottom of screen.
var TRANSFORM_PROP = 'transform';
var TRANSFORM_PROP = 'transform'; // global variable for all instances
// global variable for all instances
var doc;

@@ -52,2 +87,3 @@ var docBody;

var canEnableTransforms = true; // Use transform by default, so no Sticky on lower-end browser when no Modernizr
var M;

@@ -58,417 +94,463 @@ var scrollDelta = 0;

var Sticky = (function (_Component) {
_inherits(Sticky, _Component);
var Sticky = /*#__PURE__*/function (_Component) {
_inherits(Sticky, _Component);
function Sticky(props, context) {
_classCallCheck(this, Sticky);
var _super = _createSuper(Sticky);
_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;
this.stickyTop = 0;
this.stickyBottom = 0;
this.frozen = false;
this.skipNextScrollEvent = false;
this.scrollTop = -1;
function Sticky(props, context) {
var _this;
this.bottomBoundaryTarget;
this.topTarget;
this.subscribers;
_classCallCheck(this, Sticky);
this.state = {
top: 0, // A top offset from viewport top where Sticky sticks to when scrolling up
bottom: 0, // A bottom offset from viewport top where Sticky sticks to when scrolling down
width: 0, // Sticky width
height: 0, // Sticky height
x: 0, // The original x of Sticky
y: 0, // The original y of Sticky
topBoundary: 0, // The top boundary on document
bottomBoundary: Infinity, // The bottom boundary on document
status: STATUS_ORIGINAL, // The Sticky status
pos: 0, // Real y-axis offset for rendering position-fixed and position-relative
activated: false // once browser info is available after mounted, it becomes true to avoid checksum error
};
_this = _super.call(this, props, context);
_this.handleResize = _this.handleResize.bind(_assertThisInitialized(_this));
_this.handleScroll = _this.handleScroll.bind(_assertThisInitialized(_this));
_this.handleScrollStart = _this.handleScrollStart.bind(_assertThisInitialized(_this));
_this.delta = 0;
_this.stickyTop = 0;
_this.stickyBottom = 0;
_this.frozen = false;
_this.skipNextScrollEvent = false;
_this.scrollTop = -1;
_this.bottomBoundaryTarget;
_this.topTarget;
_this.subscribers;
_this.state = {
top: 0,
// A top offset from viewport top where Sticky sticks to when scrolling up
bottom: 0,
// A bottom offset from viewport top where Sticky sticks to when scrolling down
width: 0,
// Sticky width
height: 0,
// Sticky height
x: 0,
// The original x of Sticky
y: 0,
// The original y of Sticky
topBoundary: 0,
// The top boundary on document
bottomBoundary: Infinity,
// The bottom boundary on document
status: STATUS_ORIGINAL,
// The Sticky status
pos: 0,
// Real y-axis offset for rendering position-fixed and position-relative
activated: false // once browser info is available after mounted, it becomes true to avoid checksum error
};
return _this;
}
_createClass(Sticky, [{
key: "getTargetHeight",
value: function getTargetHeight(target) {
return target && target.offsetHeight || 0;
}
}, {
key: "getTopPosition",
value: function getTopPosition(top) {
// a top argument can be provided to override reading from the props
top = top || this.props.top || 0;
_createClass(Sticky, [{
key: 'getTargetHeight',
value: function getTargetHeight(target) {
return target && target.offsetHeight || 0;
if (typeof top === 'string') {
if (!this.topTarget) {
this.topTarget = doc.querySelector(top);
}
}, {
key: 'getTopPosition',
value: function getTopPosition(top) {
// a top argument can be provided to override reading from the props
top = top || this.props.top || 0;
if (typeof top === 'string') {
if (!this.topTarget) {
this.topTarget = doc.querySelector(top);
}
top = this.getTargetHeight(this.topTarget);
}
return top;
}
}, {
key: 'getTargetBottom',
value: function getTargetBottom(target) {
if (!target) {
return -1;
}
var rect = target.getBoundingClientRect();
return this.scrollTop + rect.bottom;
}
}, {
key: 'getBottomBoundary',
value: function getBottomBoundary(bottomBoundary) {
// a bottomBoundary can be provided to avoid reading from the props
var boundary = bottomBoundary || this.props.bottomBoundary;
// TODO, bottomBoundary was an object, depricate it later.
if (typeof boundary === 'object') {
boundary = boundary.value || boundary.target || 0;
}
top = this.getTargetHeight(this.topTarget);
}
if (typeof boundary === 'string') {
if (!this.bottomBoundaryTarget) {
this.bottomBoundaryTarget = doc.querySelector(boundary);
}
boundary = this.getTargetBottom(this.bottomBoundaryTarget);
}
return boundary && boundary > 0 ? boundary : Infinity;
return top;
}
}, {
key: "getTargetBottom",
value: function getTargetBottom(target) {
if (!target) {
return -1;
}
var rect = target.getBoundingClientRect();
return this.scrollTop + rect.bottom;
}
}, {
key: "getBottomBoundary",
value: function getBottomBoundary(bottomBoundary) {
// a bottomBoundary can be provided to avoid reading from the props
var boundary = bottomBoundary || this.props.bottomBoundary; // TODO, bottomBoundary was an object, depricate it later.
if (_typeof(boundary) === 'object') {
boundary = boundary.value || boundary.target || 0;
}
if (typeof boundary === 'string') {
if (!this.bottomBoundaryTarget) {
this.bottomBoundaryTarget = doc.querySelector(boundary);
}
}, {
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
});
}
/**
* Update the initial position, width, and height. It should update whenever children change.
* @param {Object} options optional top and bottomBoundary new values
*/
}, {
key: 'updateInitialDimension',
value: function updateInitialDimension(options) {
options = options || {};
boundary = this.getTargetBottom(this.bottomBoundaryTarget);
}
var outerRect = this.outerElement.getBoundingClientRect();
var innerRect = this.innerElement.getBoundingClientRect();
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
});
}
/**
* Update the initial position, width, and height. It should update whenever children change.
* @param {Object} options optional top and bottomBoundary new values
*/
var width = outerRect.width || outerRect.right - outerRect.left;
var height = innerRect.height || innerRect.bottom - innerRect.top;;
var outerY = outerRect.top + this.scrollTop;
}, {
key: "updateInitialDimension",
value: function updateInitialDimension(options) {
options = options || {};
this.setState({
top: this.getTopPosition(options.top),
bottom: Math.min(this.state.top + height, winHeight),
width: width,
height: height,
x: outerRect.left,
y: outerY,
bottomBoundary: this.getBottomBoundary(options.bottomBoundary),
topBoundary: outerY
});
}
}, {
key: 'handleResize',
value: function handleResize(e, ae) {
if (this.props.shouldFreeze()) {
return;
}
if (!this.outerElement || !this.innerElement) {
return;
}
winHeight = ae.resize.height;
this.updateInitialDimension();
this.update();
}
}, {
key: 'handleScrollStart',
value: function handleScrollStart(e, ae) {
this.frozen = this.props.shouldFreeze();
var outerRect = this.outerElement.getBoundingClientRect();
var innerRect = this.innerElement.getBoundingClientRect();
var width = outerRect.width || outerRect.right - outerRect.left;
var height = innerRect.height || innerRect.bottom - innerRect.top;
;
var outerY = outerRect.top + this.scrollTop;
this.setState({
top: this.getTopPosition(options.top),
bottom: Math.min(this.state.top + height, winHeight),
width: width,
height: height,
x: outerRect.left,
y: outerY,
bottomBoundary: this.getBottomBoundary(options.bottomBoundary),
topBoundary: outerY
});
}
}, {
key: "handleResize",
value: function handleResize(e, ae) {
if (this.props.shouldFreeze()) {
return;
}
if (this.frozen) {
return;
}
winHeight = ae.resize.height;
this.updateInitialDimension();
this.update();
}
}, {
key: "handleScrollStart",
value: function handleScrollStart(e, ae) {
this.frozen = this.props.shouldFreeze();
if (this.scrollTop === ae.scroll.top) {
// Scroll position hasn't changed,
// do nothing
this.skipNextScrollEvent = true;
} else {
this.scrollTop = ae.scroll.top;
this.updateInitialDimension();
}
}
}, {
key: 'handleScroll',
value: function handleScroll(e, ae) {
// Scroll doesn't need to be handled
if (this.skipNextScrollEvent) {
this.skipNextScrollEvent = false;
return;
}
if (this.frozen) {
return;
}
scrollDelta = ae.scroll.delta;
this.scrollTop = ae.scroll.top;
this.update();
if (this.scrollTop === ae.scroll.top) {
// Scroll position hasn't changed,
// do nothing
this.skipNextScrollEvent = true;
} else {
this.scrollTop = ae.scroll.top;
this.updateInitialDimension();
}
}
}, {
key: "handleScroll",
value: function handleScroll(e, ae) {
// Scroll doesn't need to be handled
if (this.skipNextScrollEvent) {
this.skipNextScrollEvent = false;
return;
}
scrollDelta = ae.scroll.delta;
this.scrollTop = ae.scroll.top;
this.update();
}
/**
* Update Sticky position.
*/
}, {
key: "update",
value: function update() {
var disabled = !this.props.enabled || this.state.bottomBoundary - this.state.topBoundary <= this.state.height || this.state.width === 0 && this.state.height === 0;
if (disabled) {
if (this.state.status !== STATUS_ORIGINAL) {
this.reset();
}
/**
* Update Sticky position.
*/
}, {
key: 'update',
value: function update() {
var disabled = !this.props.enabled || this.state.bottomBoundary - this.state.topBoundary <= this.state.height || this.state.width === 0 && this.state.height === 0;
return;
}
if (disabled) {
if (this.state.status !== STATUS_ORIGINAL) {
this.reset();
}
return;
}
var delta = scrollDelta; // "top" and "bottom" are the positions that this.state.top and this.state.bottom project
// on document from viewport.
var delta = scrollDelta;
// "top" and "bottom" are the positions that this.state.top and this.state.bottom project
// on document from viewport.
var top = this.scrollTop + this.state.top;
var bottom = this.scrollTop + this.state.bottom;
var top = this.scrollTop + this.state.top;
var bottom = this.scrollTop + this.state.bottom; // 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
// 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 <= this.state.topBoundary) {
// #1
this.reset();
} else if (bottom >= this.state.bottomBoundary) {
// #2
this.stickyBottom = this.state.bottomBoundary;
this.stickyTop = this.stickyBottom - this.state.height;
if (top <= this.state.topBoundary) {
// #1
this.reset();
} else if (bottom >= this.state.bottomBoundary) {
// #2
this.stickyBottom = this.state.bottomBoundary;
this.stickyTop = this.stickyBottom - this.state.height;
this.release(this.stickyTop);
} else {
if (this.state.height > winHeight - this.state.top) {
// In this case, Sticky is higher then viewport minus top offset
switch (this.state.status) {
case STATUS_ORIGINAL:
this.release(this.state.y);
this.stickyTop = this.state.y;
this.stickyBottom = this.stickyTop + this.state.height;
// Commentting out "break" is on purpose, because there is a chance to transit to FIXED
// from ORIGINAL when calling window.scrollTo().
// break;
case STATUS_RELEASED:
// If "top" and "bottom" are inbetween stickyTop and stickyBottom, then Sticky is in
// RELEASE status. Otherwise, it changes to FIXED status, and its bottom sticks to
// viewport bottom when scrolling down, or its top sticks to viewport top when scrolling up.
this.stickyBottom = this.stickyTop + this.state.height;
if (delta > 0 && bottom > this.stickyBottom) {
this.fix(this.state.bottom - this.state.height);
} else if (delta < 0 && top < this.stickyTop) {
this.fix(this.state.top);
}
break;
case STATUS_FIXED:
var toRelease = true;
var pos = this.state.pos;
var height = this.state.height; // In regular cases, when Sticky is in FIXED status,
// 1. it's top will stick to the screen top,
// 2. it's bottom will stick to the screen bottom,
// 3. if not the cases above, then it's height gets changed
if (delta > 0 && pos === this.state.top) {
// case 1, and scrolling down
this.stickyTop = top - delta;
this.stickyBottom = this.stickyTop + height;
} else if (delta < 0 && pos === this.state.bottom - height) {
// case 2, and scrolling up
this.stickyBottom = bottom - delta;
this.stickyTop = this.stickyBottom - height;
} else if (pos !== this.state.bottom - height && pos !== this.state.top) {
// case 3
// This case only happens when Sticky's bottom sticks to the screen bottom and
// its height gets changed. Sticky should be in RELEASE status and update its
// sticky bottom by calculating how much height it changed.
var deltaHeight = pos + height - this.state.bottom;
this.stickyBottom = bottom - delta + deltaHeight;
this.stickyTop = this.stickyBottom - height;
} else {
toRelease = false;
}
if (toRelease) {
this.release(this.stickyTop);
} else {
if (this.state.height > winHeight - this.state.top) {
// In this case, Sticky is higher then viewport minus top offset
switch (this.state.status) {
case STATUS_ORIGINAL:
this.release(this.state.y);
this.stickyTop = this.state.y;
this.stickyBottom = this.stickyTop + this.state.height;
// Commentting out "break" is on purpose, because there is a chance to transit to FIXED
// from ORIGINAL when calling window.scrollTo().
// break;
case STATUS_RELEASED:
// If "top" and "bottom" are inbetween stickyTop and stickyBottom, then Sticky is in
// RELEASE status. Otherwise, it changes to FIXED status, and its bottom sticks to
// viewport bottom when scrolling down, or its top sticks to viewport top when scrolling up.
this.stickyBottom = this.stickyTop + this.state.height;
if (delta > 0 && bottom > this.stickyBottom) {
this.fix(this.state.bottom - this.state.height);
} else if (delta < 0 && top < this.stickyTop) {
this.fix(this.state.top);
}
break;
case STATUS_FIXED:
var toRelease = true;
var pos = this.state.pos;
var height = this.state.height;
// In regular cases, when Sticky is in FIXED status,
// 1. it's top will stick to the screen top,
// 2. it's bottom will stick to the screen bottom,
// 3. if not the cases above, then it's height gets changed
if (delta > 0 && pos === this.state.top) {
// case 1, and scrolling down
this.stickyTop = top - delta;
this.stickyBottom = this.stickyTop + height;
} else if (delta < 0 && pos === this.state.bottom - height) {
// case 2, and scrolling up
this.stickyBottom = bottom - delta;
this.stickyTop = this.stickyBottom - height;
} else if (pos !== this.state.bottom - height && pos !== this.state.top) {
// case 3
// This case only happens when Sticky's bottom sticks to the screen bottom and
// its height gets changed. Sticky should be in RELEASE status and update its
// sticky bottom by calculating how much height it changed.
var deltaHeight = pos + height - this.state.bottom;
this.stickyBottom = bottom - delta + deltaHeight;
this.stickyTop = this.stickyBottom - height;
} else {
toRelease = false;
}
}
if (toRelease) {
this.release(this.stickyTop);
}
break;
}
} else {
// In this case, Sticky is shorter then viewport minus top offset
// and will always fix to the top offset of viewport
this.fix(this.state.top);
}
}
this.delta = delta;
break;
}
} else {
// In this case, Sticky is shorter then viewport minus top offset
// and will always fix to the top offset of viewport
this.fix(this.state.top);
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate(prevProps, prevState) {
var _this = this;
}
if (prevState.status !== this.state.status && this.props.onStateChange) {
this.props.onStateChange({ status: this.state.status });
}
var arePropsChanged = !(0, _shallowequal2['default'])(this.props, prevProps);
if (arePropsChanged) {
// if the props for enabling are toggled, then trigger the update or reset depending on the current props
if (prevProps.enabled !== this.props.enabled) {
if (this.props.enabled) {
this.setState({ activated: true }, function () {
_this.updateInitialDimension();
_this.update();
});
} else {
this.setState({ activated: false }, function () {
_this.reset();
});
}
}
// if the top or bottomBoundary props were changed, then trigger the update
else if (prevProps.top !== this.props.top || prevProps.bottomBoundary !== this.props.bottomBoundary) {
this.updateInitialDimension();
this.update();
}
}
}
}, {
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() {
// Only initialize the globals if this is the first
// time this component type has been mounted
if (!win) {
win = window;
doc = document;
docEl = doc.documentElement;
docBody = doc.body;
winHeight = win.innerHeight || docEl.clientHeight;
M = window.Modernizr;
// No Sticky on lower-end browser when no Modernizr
if (M && M.prefixed) {
canEnableTransforms = M.csstransforms3d;
TRANSFORM_PROP = M.prefixed('transform');
}
}
this.delta = delta;
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps, prevState) {
var _this2 = this;
// when mount, the scrollTop is not necessary on the top
this.scrollTop = docBody.scrollTop + docEl.scrollTop;
if (prevState.status !== this.state.status && this.props.onStateChange) {
this.props.onStateChange({
status: this.state.status
});
}
if (this.props.enabled) {
this.setState({ activated: true });
this.updateInitialDimension();
this.update();
}
// bind the listeners regardless if initially enabled - allows the component to toggle sticky functionality
this.subscribers = [(0, _subscribeUiEvent.subscribe)('scrollStart', this.handleScrollStart.bind(this), { useRAF: true }), (0, _subscribeUiEvent.subscribe)('scroll', this.handleScroll.bind(this), { useRAF: true, enableScrollInfo: true }), (0, _subscribeUiEvent.subscribe)('resize', this.handleResize.bind(this), { enableResizeInfo: true })];
var arePropsChanged = !(0, _shallowequal.default)(this.props, prevProps);
if (arePropsChanged) {
// if the props for enabling are toggled, then trigger the update or reset depending on the current props
if (prevProps.enabled !== this.props.enabled) {
if (this.props.enabled) {
this.setState({
activated: true
}, function () {
_this2.updateInitialDimension();
_this2.update();
});
} else {
this.setState({
activated: false
}, function () {
_this2.reset();
});
}
} // if the top or bottomBoundary props were changed, then trigger the update
else if (prevProps.top !== this.props.top || prevProps.bottomBoundary !== this.props.bottomBoundary) {
this.updateInitialDimension();
this.update();
}
}
}
}, {
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() {
// Only initialize the globals if this is the first
// time this component type has been mounted
if (!win) {
win = window;
doc = document;
docEl = doc.documentElement;
docBody = doc.body;
winHeight = win.innerHeight || docEl.clientHeight;
M = window.Modernizr; // No Sticky on lower-end browser when no Modernizr
if (M && M.prefixed) {
canEnableTransforms = M.csstransforms3d;
TRANSFORM_PROP = M.prefixed('transform');
}
}, {
key: 'translate',
value: function translate(style, pos) {
var enableTransforms = canEnableTransforms && this.props.enableTransforms;
if (enableTransforms && this.state.activated) {
style[TRANSFORM_PROP] = 'translate3d(0,' + Math.round(pos) + 'px,0)';
} else {
style.top = pos + 'px';
}
}
}, {
key: 'shouldComponentUpdate',
value: function shouldComponentUpdate(nextProps, nextState) {
return !this.props.shouldFreeze() && !((0, _shallowequal2['default'])(this.props, nextProps) && (0, _shallowequal2['default'])(this.state, nextState));
}
}, {
key: 'render',
value: function render() {
var _classNames,
_this2 = this;
} // when mount, the scrollTop is not necessary on the top
// TODO, "overflow: auto" prevents collapse, need a good way to get children height
var innerStyle = {
position: this.state.status === STATUS_FIXED ? 'fixed' : 'relative',
top: this.state.status === STATUS_FIXED ? '0px' : '',
zIndex: this.props.innerZ
};
var outerStyle = {};
// always use translate3d to enhance the performance
this.translate(innerStyle, this.state.pos);
if (this.state.status !== STATUS_ORIGINAL) {
innerStyle.width = this.state.width + 'px';
outerStyle.height = this.state.height + 'px';
}
this.scrollTop = docBody.scrollTop + docEl.scrollTop;
var outerClasses = (0, _classnames2['default'])('sticky-outer-wrapper', this.props.className, (_classNames = {}, _defineProperty(_classNames, this.props.activeClass, this.state.status === STATUS_FIXED), _defineProperty(_classNames, this.props.releasedClass, this.state.status === STATUS_RELEASED), _classNames));
if (this.props.enabled) {
this.setState({
activated: true
});
this.updateInitialDimension();
this.update();
} // bind the listeners regardless if initially enabled - allows the component to toggle sticky functionality
var children = this.props.children;
return _react2['default'].createElement(
'div',
{ ref: function (outer) {
_this2.outerElement = outer;
}, className: outerClasses, style: outerStyle },
_react2['default'].createElement(
'div',
{ ref: function (inner) {
_this2.innerElement = inner;
}, className: ['sticky-inner-wrapper', this.props.innerClass].join(' '), style: innerStyle },
typeof children === 'function' ? children({ status: this.state.status }) : children
)
);
}
}]);
this.subscribers = [(0, _subscribeUiEvent.subscribe)('scrollStart', this.handleScrollStart.bind(this), {
useRAF: true
}), (0, _subscribeUiEvent.subscribe)('scroll', this.handleScroll.bind(this), {
useRAF: true,
enableScrollInfo: true
}), (0, _subscribeUiEvent.subscribe)('resize', this.handleResize.bind(this), {
enableResizeInfo: true
})];
}
}, {
key: "translate",
value: function translate(style, pos) {
var enableTransforms = canEnableTransforms && this.props.enableTransforms;
return Sticky;
})(_react.Component);
if (enableTransforms && this.state.activated) {
style[TRANSFORM_PROP] = 'translate3d(0,' + Math.round(pos) + 'px,0)';
} else {
style.top = pos + 'px';
}
}
}, {
key: "shouldComponentUpdate",
value: function shouldComponentUpdate(nextProps, nextState) {
return !this.props.shouldFreeze() && !((0, _shallowequal.default)(this.props, nextProps) && (0, _shallowequal.default)(this.state, nextState));
}
}, {
key: "render",
value: function render() {
var _classNames,
_this3 = this;
// TODO, "overflow: auto" prevents collapse, need a good way to get children height
var innerStyle = {
position: this.state.status === STATUS_FIXED ? 'fixed' : 'relative',
top: this.state.status === STATUS_FIXED ? '0px' : '',
zIndex: this.props.innerZ
};
var outerStyle = {}; // always use translate3d to enhance the performance
this.translate(innerStyle, this.state.pos);
if (this.state.status !== STATUS_ORIGINAL) {
innerStyle.width = this.state.width + 'px';
outerStyle.height = this.state.height + 'px';
}
var outerClasses = (0, _classnames.default)('sticky-outer-wrapper', this.props.className, (_classNames = {}, _defineProperty(_classNames, this.props.activeClass, this.state.status === STATUS_FIXED), _defineProperty(_classNames, this.props.releasedClass, this.state.status === STATUS_RELEASED), _classNames));
var children = this.props.children;
return /*#__PURE__*/_react.default.createElement("div", {
ref: function ref(outer) {
_this3.outerElement = outer;
},
className: outerClasses,
style: outerStyle
}, /*#__PURE__*/_react.default.createElement("div", {
ref: function ref(inner) {
_this3.innerElement = inner;
},
className: ['sticky-inner-wrapper', this.props.innerClass].join(' '),
style: innerStyle
}, typeof children === 'function' ? children({
status: this.state.status
}) : children));
}
}]);
return Sticky;
}(_react.Component);
Sticky.displayName = 'Sticky';
Sticky.defaultProps = {
shouldFreeze: function shouldFreeze() {
return false;
},
enabled: true,
top: 0,
bottomBoundary: 0,
enableTransforms: true,
activeClass: 'active',
releasedClass: 'released',
onStateChange: null,
innerClass: ''
shouldFreeze: function shouldFreeze() {
return false;
},
enabled: true,
top: 0,
bottomBoundary: 0,
enableTransforms: true,
activeClass: 'active',
releasedClass: 'released',
onStateChange: null,
innerClass: ''
};
/**

@@ -481,20 +563,19 @@ * @param {Bool} enabled A switch to enable or disable Sticky.

*/
Sticky.propTypes = {
enabled: _propTypes2['default'].bool,
top: _propTypes2['default'].oneOfType([_propTypes2['default'].string, _propTypes2['default'].number]),
bottomBoundary: _propTypes2['default'].oneOfType([_propTypes2['default'].object, // TODO, may remove
_propTypes2['default'].string, _propTypes2['default'].number]),
enableTransforms: _propTypes2['default'].bool,
activeClass: _propTypes2['default'].string,
releasedClass: _propTypes2['default'].string,
innerClass: _propTypes2['default'].string,
onStateChange: _propTypes2['default'].func,
shouldFreeze: _propTypes2['default'].func,
innerZ: _propTypes2['default'].oneOfType([_propTypes2['default'].string, _propTypes2['default'].number])
enabled: _propTypes.default.bool,
top: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
bottomBoundary: _propTypes.default.oneOfType([_propTypes.default.object, // TODO, may remove
_propTypes.default.string, _propTypes.default.number]),
enableTransforms: _propTypes.default.bool,
activeClass: _propTypes.default.string,
releasedClass: _propTypes.default.string,
innerClass: _propTypes.default.string,
onStateChange: _propTypes.default.func,
shouldFreeze: _propTypes.default.func,
innerZ: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number])
};
Sticky.STATUS_ORIGINAL = STATUS_ORIGINAL;
Sticky.STATUS_RELEASED = STATUS_RELEASED;
Sticky.STATUS_FIXED = STATUS_FIXED;
module.exports = Sticky;
module.exports = Sticky;

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

'grunt-contrib-watch',
'grunt-babel',
'grunt-shell',

@@ -41,3 +40,2 @@ 'grunt-webpack'

functional: 'tests/functional',
spec: 'tests/spec',
coverage_dir: grunt.option('coverage_dir') || 'artifacts',

@@ -92,65 +90,2 @@ test_results_dir: grunt.option('test_results_dir') || 'artifacts'

},
// react
// compiles jsx to js
babel: {
dist: {
options: {
sourceMap: false
},
files: [
{
expand: true,
cwd: '<%= project.src %>',
src: ['**/*.*'],
dest: '<%= project.dist %>/',
extDot: 'last',
ext: '.js'
}
]
},
functional: {
options: {
sourceMap: false
},
files: [
{
expand: true,
src: ['<%= project.functional %>/**/*.jsx'],
extDot: 'last',
ext: '.js'
}
]
},
unit: {
files: [
{
expand: true,
src: [
'<%= project.unit %>/**/*.*'
],
dest: '<%= project.tmp %>',
extDot: 'last',
ext: '.js'
}
]
}
},
// shell
// shell commands to run protractor and istanbul
shell: {
istanbul: {
options: {
execOptions: {
env: env
}
},
command: 'node tests/helpers/rAF.js 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'
}
},
// webpack

@@ -167,3 +102,3 @@ // create js rollup with webpack module loader for functional tests

{ test: /\.css$/, loader: 'style!css' },
{ test: /\.jsx$/, loader: require.resolve('babel-loader') },
// { test: /\.jsx$/, loader: require.resolve('babel-loader') },
{ test: /\.json$/, loader: 'json-loader'}

@@ -206,3 +141,3 @@ ]

options: {
testname: 'react-i13n func test',
testname: 'react-stickynode func test',
urls: [

@@ -222,7 +157,2 @@ 'http://127.0.0.1:9999/tests/functional/page.html'

browserName: 'internet explorer',
platform: 'Windows 7',
version: '9'
},
{
browserName: 'internet explorer',
platform: 'Windows 8',

@@ -297,32 +227,4 @@ version: '10'

// cover
// 1. clean tmp/
// 2. compile jsx to js in tmp/
// 3. run istanbul cover in tmp/ using mocha command
// 4. clean tmp/
grunt.registerTask('cover', [
'clean:tmp',
'clean:dist',
'babel:unit',
'babel:dist',
'shell:istanbul',
'clean:tmp'
]);
grunt.registerTask('unit', [
'clean:tmp',
'clean:dist',
'babel:unit',
'babel:dist',
'shell:mocha'
]);
// dist
// 1. clean dist/
// 2. compile jsx to js in dist/
grunt.registerTask('dist', ['clean:dist', 'babel:dist']);
grunt.registerTask('test', ['clean:dist', 'babel:dist', 'clean:tmp', 'babel:unit']);
// default
grunt.registerTask('default', ['dist']);
grunt.registerTask('default', ['functional']);
};
{
"name": "react-stickynode",
"version": "3.0.2",
"description": "A performant and comprehensive React sticky",
"version": "3.0.3",
"description": "A performant and comprehensive React sticky component",
"main": "index.js",
"scripts": {
"build": "grunt dist",
"devtest": "grunt unit",
"func": "./tests/functional/saucelabs.sh",
"build": "babel src --out-dir dist",
"ci": "./tests/functional/saucelabs.sh",
"lint": "eslint --cache --ext .js,.jsx . --fix",
"prepublish": "grunt dist",
"test": "grunt cover"
"prepublish": "npm run build",
"test": "jest --coverage tests/unit",
"test:func": "grunt func",
"test:watch": "jest --watch"
},

@@ -34,2 +35,3 @@ "repository": {

"classnames": "^2.0.0",
"core-js": "^3.6.5",
"prop-types": "^15.6.0",

@@ -40,7 +42,12 @@ "shallowequal": "^1.0.0",

"devDependencies": {
"babel": "^5.0.0",
"babel-loader": "^5.0.0",
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.6",
"@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4",
"@babel/register": "^7.9.0",
"@testing-library/react": "^10.0.4",
"babel-jest": "^26.0.1",
"coveralls": "^3.1.0",
"es5-shim": "^4.5.14",
"eslint": "^6.8.0",
"eslint": "^7.0.0",
"eslint-plugin-react": "^7.19.0",

@@ -50,23 +57,18 @@ "expect.js": "^0.3.1",

"grunt-atomizer": "^3.0.0",
"grunt-babel": "^5.0.0",
"grunt-cli": "^1.1.0",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-connect": "^1.0.0",
"grunt-contrib-clean": "^2.0.0",
"grunt-contrib-connect": "^2.1.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-saucelabs": "^8.3.2",
"grunt-shell": "^1.1.2",
"grunt-webpack": "^1.0.8",
"istanbul": "^0.4.0",
"jsdom": "^8.0.0",
"jsx-test": "^2.1.0",
"grunt-saucelabs": "^9.0.1",
"grunt-webpack": "^3.1.3",
"jest": "^26.0.1",
"jsdom": "^16.2.2",
"minimist": "^1.2.5",
"mocha": "^7.1.2",
"mockery": "^1.4.0",
"pre-commit": "^1.0.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"sinon": "^1.17.3",
"webpack": "^1.15.0",
"webpack-dev-server": "^1.16.5",
"xunit-file": "~0.0.9"
"react-test-renderer": "^16.13.1",
"webpack": "^4.43.0",
"webpack-dev-server": "^3.10.3"
},

@@ -81,3 +83,9 @@ "peerDependencies": {

],
"license": "BSD-3-Clause"
"license": "BSD-3-Clause",
"browserslist": [
"last 2 versions",
"ie >= 11",
"iOS >= 12",
"Android >= 6"
]
}

@@ -5,4 +5,2 @@ # react-stickynode

[![Coverage Status](https://coveralls.io/repos/yahoo/react-stickynode/badge.svg)](https://coveralls.io/r/yahoo/react-stickynode)
[![Dependency Status](https://david-dm.org/yahoo/react-stickynode.svg)](https://david-dm.org/yahoo/react-stickynode)
[![devDependency Status](https://david-dm.org/yahoo/react-stickynode/dev-status.svg)](https://david-dm.org/yahoo/react-stickynode#info=devDependencies)

@@ -119,5 +117,10 @@ A performant and comprehensive React sticky component.

```bash
grunt unit
npm run test
```
**Linting**
```bash
npm run lint
```
## License

@@ -124,0 +127,0 @@

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