Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ yarn-error.log*

# build
node_modules
dist
examples/dist
98 changes: 98 additions & 0 deletions dist/ScrollLock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

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 _exenv = require('exenv');

var _TouchScrollable = require('./TouchScrollable');

var _withLockSheet = require('./withLockSheet');

var _withLockSheet2 = _interopRequireDefault(_withLockSheet);

var _withTouchListeners = require('./withTouchListeners');

var _withTouchListeners2 = _interopRequireDefault(_withTouchListeners);

var _utils = require('./utils');

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; }

var ScrollLock = function (_PureComponent) {
_inherits(ScrollLock, _PureComponent);

function ScrollLock() {
_classCallCheck(this, ScrollLock);

return _possibleConstructorReturn(this, (ScrollLock.__proto__ || Object.getPrototypeOf(ScrollLock)).apply(this, arguments));
}

_createClass(ScrollLock, [{
key: 'componentDidMount',
value: function componentDidMount() {
if (!_exenv.canUseDOM) return;
this.initialHeight = window.innerHeight;
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
var offset = window.innerHeight - this.initialHeight;

// adjust scroll if the window has been resized since the lock was engaged
// e.g. mobile safari dynamic chrome heights
if (offset) {
window.scrollTo(0, window.pageYOffset + offset);
}

// reset the initial height in case this scroll lock is used again
this.initialHeight = window.innerHeight;
}
}, {
key: 'render',
value: function render() {
var children = this.props.children;


return children ? _react2.default.createElement(
_TouchScrollable.TouchScrollable,
null,
children
) : null;
}
}]);

return ScrollLock;
}(_react.PureComponent);

// attach the stylesheet and inject styles on [un]mount


var compose = (0, _utils.pipe)(_withTouchListeners2.default, _withLockSheet2.default);
var SheetLock = compose(ScrollLock);

// toggle the lock based on `isActive` prop
var LockToggle = function LockToggle(props) {
return props.isActive ? _react2.default.createElement(SheetLock, props) : props.children;
};

LockToggle.defaultProps = {
accountForScrollbars: true,
children: null,
isActive: true
};

exports.default = LockToggle;
73 changes: 73 additions & 0 deletions dist/TouchScrollable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TouchScrollable = undefined;

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 _exenv = require('exenv');

var _utils = require('./utils');

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; }

var TouchScrollable = exports.TouchScrollable = function (_PureComponent) {
_inherits(TouchScrollable, _PureComponent);

function TouchScrollable() {
var _ref;

var _temp, _this, _ret;

_classCallCheck(this, TouchScrollable);

for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}

return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = TouchScrollable.__proto__ || Object.getPrototypeOf(TouchScrollable)).call.apply(_ref, [this].concat(args))), _this), _this.getScrollableArea = function (ref) {
_this.scrollableArea = ref;
}, _temp), _possibleConstructorReturn(_this, _ret);
}

_createClass(TouchScrollable, [{
key: 'componentDidMount',
value: function componentDidMount() {
if (!_exenv.canUseEventListeners) return;

this.scrollableArea.addEventListener('touchstart', _utils.preventInertiaScroll, _utils.listenerOptions);
this.scrollableArea.addEventListener('touchmove', _utils.allowTouchMove, _utils.listenerOptions);
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
if (!_exenv.canUseEventListeners) return;

this.scrollableArea.removeEventListener('touchstart', _utils.preventInertiaScroll, _utils.listenerOptions);
this.scrollableArea.removeEventListener('touchmove', _utils.allowTouchMove, _utils.listenerOptions);
}
}, {
key: 'render',
value: function render() {
var _props = this.props,
children = _props.children,
rest = _objectWithoutProperties(_props, ['children']);

return typeof children === 'function' ? children(this.getScrollableArea) : (0, _react.cloneElement)(children, _extends({ ref: this.getScrollableArea }, rest));
}
}]);

return TouchScrollable;
}(_react.PureComponent);
14 changes: 14 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react';

interface OneChildrenElement {
children?: React.ReactElement;
}

interface ScrollLockProps extends OneChildrenElement {
accountForScrollbars?: boolean;
isActive?: boolean;
}

export default class ScrollLock extends React.Component<ScrollLockProps> {}

export class TouchScrollable extends React.Component<OneChildrenElement> {}
25 changes: 25 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _ScrollLock = require('./ScrollLock');

Object.defineProperty(exports, 'default', {
enumerable: true,
get: function get() {
return _interopRequireDefault(_ScrollLock).default;
}
});

var _TouchScrollable = require('./TouchScrollable');

Object.defineProperty(exports, 'TouchScrollable', {
enumerable: true,
get: function get() {
return _TouchScrollable.TouchScrollable;
}
});

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
151 changes: 151 additions & 0 deletions dist/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.pipe = exports.listenerOptions = undefined;
exports.preventTouchMove = preventTouchMove;
exports.allowTouchMove = allowTouchMove;
exports.preventInertiaScroll = preventInertiaScroll;
exports.isTouchDevice = isTouchDevice;
exports.camelToKebab = camelToKebab;
exports.parse = parse;
exports.getPadding = getPadding;
exports.getWindowHeight = getWindowHeight;
exports.getDocumentHeight = getDocumentHeight;
exports.makeStyleTag = makeStyleTag;
exports.injectStyles = injectStyles;
exports.insertStyleTag = insertStyleTag;

var _exenv = require('exenv');

var listenerOptions = exports.listenerOptions = {
capture: false,
passive: false
};

// ==============================
// Touch Helpers
// ==============================

function preventTouchMove(e) {
e.preventDefault();

return false;
}

function allowTouchMove(e) {
var target = e.currentTarget;

if (target.scrollHeight > target.clientHeight || target.scrollWidth > target.clientWidth) {
e.stopPropagation();
return true;
}

e.preventDefault();
return false;
}

function preventInertiaScroll() {
var top = this.scrollTop;
var totalScroll = this.scrollHeight;
var currentScroll = top + this.offsetHeight;

if (top === 0) {
this.scrollTop = 1;
} else if (currentScroll === totalScroll) {
this.scrollTop = top - 1;
}
}

// `ontouchstart` check works on most browsers
// `maxTouchPoints` works on IE10/11 and Surface
function isTouchDevice() {
if (!_exenv.canUseDOM) return false;
return 'ontouchstart' in window || navigator.maxTouchPoints;
}

// ==============================
// Misc.
// ==============================

function camelToKebab(str) {
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}

function parse(val) {
return isNaN(val) ? val : val + 'px';
}

// Take a list of functions and return a function that applies the list of
// functions from left to right

var pipeFns = function pipeFns(a, b) {
return function () {
return b(a.apply(undefined, arguments));
};
};
var pipe = exports.pipe = function pipe() {
for (var _len = arguments.length, fns = Array(_len), _key = 0; _key < _len; _key++) {
fns[_key] = arguments[_key];
}

return fns.reduce(pipeFns);
};

// ==============================
// Document Helpers
// ==============================

function getPadding() {
if (!_exenv.canUseDOM) return 0;

var paddingRight = parseInt(window.getComputedStyle(document.body).paddingRight, 10);
var scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;

return paddingRight + scrollbarWidth;
}

function getWindowHeight() {
var multiplier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;

if (_exenv.canUseDOM) {
return window.innerHeight * multiplier;
}
}

function getDocumentHeight() {
if (_exenv.canUseDOM) {
return document.body.clientHeight;
}
}

// ==============================
// Style Sheets
// ==============================

function makeStyleTag() {
if (!_exenv.canUseDOM) return;

var tag = document.createElement('style');
tag.type = 'text/css';
tag.setAttribute('data-react-scrolllock', '');

return tag;
}
function injectStyles(tag, css) {
if (!_exenv.canUseDOM) return;

if (tag.styleSheet) {
tag.styleSheet.cssText = css;
} else {
tag.appendChild(document.createTextNode(css));
}
}
function insertStyleTag(tag) {
if (!_exenv.canUseDOM) return;

var head = document.head || document.getElementsByTagName('head')[0];

head.appendChild(tag);
}
Loading