react95-native
Version:
Refreshed Windows 95 style UI components for your React Native app
223 lines (199 loc) • 9.15 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _useAsyncReference = _interopRequireDefault(require("../../hooks/useAsyncReference"));
var _theming = require("../../core/theming");
var _ = require("../..");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { 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 _extends() { _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; }; return _extends.apply(this, arguments); }
// TODO: performance improvements (callbacks, refs ...etc)
// TODO: disable scroll buttons when scroll position reached min or max
// TODO: add 'scrollIncrement' prop (granularity of scroll buttons)
const ScrollView = ({
alwaysShowScrollbars = false,
children,
horizontal = false,
small = false,
scrollViewProps = {},
style,
theme,
...rest
}) => {
const scrollViewRef = (0, _react.useRef)(null);
const [contentOffset, setContentOffset] = (0, _useAsyncReference.default)(0);
const [contentSize, setContentSize] = (0, _useAsyncReference.default)(0);
const [scrollViewSize, setScrollViewSize] = (0, _useAsyncReference.default)(0);
const scrollbarThickness = small ? 26 : 30;
const scrollbarButtonSize = scrollbarThickness;
const scrollbarAxis = horizontal ? 'x' : 'y';
const scrollbarLengthDimension = horizontal ? 'width' : 'height';
const scrollbarThicknessDimension = horizontal ? 'height' : 'width';
const contentFullyVisible = contentSize.current <= scrollViewSize.current;
const visibleContentRatio = scrollViewSize.current / contentSize.current;
const scrolledContentRatio = contentOffset.current / contentSize.current;
const thumbPosition = Math.max(0, Math.min(1 - visibleContentRatio, parseFloat(scrolledContentRatio.toFixed(3)))) * 100; // CALLBACKS
const scrollTo = (distance, animated = false) => {
if (scrollViewRef.current) {
scrollViewRef.current.scrollTo({
[scrollbarAxis]: distance,
animated
});
}
};
const handleScrollButtonPress = direction => {
scrollTo(contentOffset.current + 24 * direction, true);
};
const handleTrackPress = direction => {
scrollTo(contentOffset.current + scrollViewSize.current * direction);
};
const handleScroll = e => {
var _scrollViewProps$onSc;
(_scrollViewProps$onSc = scrollViewProps.onScroll) === null || _scrollViewProps$onSc === void 0 ? void 0 : _scrollViewProps$onSc.call(scrollViewProps, e);
setContentOffset(e.nativeEvent.contentOffset[scrollbarAxis]);
};
const handleContentSizeChange = (width, height) => {
var _scrollViewProps$onCo;
(_scrollViewProps$onCo = scrollViewProps.onContentSizeChange) === null || _scrollViewProps$onCo === void 0 ? void 0 : _scrollViewProps$onCo.call(scrollViewProps, width, height);
setContentSize(horizontal ? width : height);
};
const handleLayout = e => {
var _scrollViewProps$onLa;
(_scrollViewProps$onLa = scrollViewProps.onLayout) === null || _scrollViewProps$onLa === void 0 ? void 0 : _scrollViewProps$onLa.call(scrollViewProps, e);
setScrollViewSize(e.nativeEvent.layout[scrollbarLengthDimension]);
};
const dragStartScrollPositionRef = (0, _react.useRef)(0);
const panResponder = (0, _react.useRef)(_reactNative.PanResponder.create({
onStartShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => true,
onMoveShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: () => {
dragStartScrollPositionRef.current = contentOffset.current;
},
onPanResponderMove: (_evt, gestureState) => {
const scrollTrackLength = scrollViewSize.current - 2 * scrollbarButtonSize;
const scrollDistanceChange = gestureState[horizontal ? 'dx' : 'dy'] / scrollTrackLength;
const translatedDistance = scrollDistanceChange * contentSize.current;
scrollTo(dragStartScrollPositionRef.current + translatedDistance);
},
onPanResponderTerminationRequest: () => true
})).current;
return /*#__PURE__*/_react.default.createElement(_reactNative.View, _extends({
style: [styles.wrapper, {
flexDirection: horizontal ? 'column' : 'row'
}, style]
}, rest), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: [styles.content]
}, /*#__PURE__*/_react.default.createElement(_reactNative.ScrollView, _extends({}, scrollViewProps, {
showsVerticalScrollIndicator: false,
showsHorizontalScrollIndicator: false,
scrollEventThrottle: 10,
ref: scrollViewRef,
onScroll: handleScroll,
onContentSizeChange: handleContentSizeChange,
onLayout: handleLayout,
horizontal: horizontal
}), children)), (!contentFullyVisible || alwaysShowScrollbars) && /*#__PURE__*/_react.default.createElement(_reactNative.View, {
accessibilityRole: "scrollbar",
style: [{
flexDirection: horizontal ? 'row' : 'column',
[scrollbarLengthDimension]: '100%',
[scrollbarThicknessDimension]: scrollbarThickness,
backgroundColor: theme.material
}]
}, /*#__PURE__*/_react.default.createElement(_reactNative.ImageBackground, {
style: [styles.background],
imageStyle: {
resizeMode: 'repeat'
},
source: {
// TODO: create util function for generating checkered background
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAIUlEQVQoU2P8////fwYkwMjIyIjCp4MCZPtAbAwraa8AAEGrH/nfAIhgAAAAAElFTkSuQmCC'
}
}), /*#__PURE__*/_react.default.createElement(_.Button, {
theme: theme,
variant: "raised",
onPress: () => handleScrollButtonPress(-1),
disabled: contentFullyVisible,
style: {
height: scrollbarButtonSize,
width: scrollbarButtonSize,
padding: 0
}
}, /*#__PURE__*/_react.default.createElement(_.ArrowIcon, {
theme: theme,
direction: horizontal ? 'left' : 'up',
disabled: contentFullyVisible,
segments: small ? 3 : 4
})), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: [styles.scrollbarTrack]
}, !contentFullyVisible && /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: {
flex: 1,
flexDirection: horizontal ? 'row' : 'column'
}
}, /*#__PURE__*/_react.default.createElement(_reactNative.TouchableWithoutFeedback, {
onPressIn: () => handleTrackPress(-1)
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: {
[scrollbarLengthDimension]: "".concat(thumbPosition, "%")
}
})), /*#__PURE__*/_react.default.createElement(_.Panel, _extends({
theme: theme,
variant: "raised",
style: {
[scrollbarLengthDimension]: "".concat(visibleContentRatio * 100, "%")
}
}, panResponder.panHandlers)), /*#__PURE__*/_react.default.createElement(_reactNative.TouchableWithoutFeedback, {
onPressIn: () => handleTrackPress(1)
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: {
flex: 1
}
})))), /*#__PURE__*/_react.default.createElement(_.Button, {
theme: theme,
variant: "raised",
onPress: () => handleScrollButtonPress(1),
disabled: contentFullyVisible,
style: {
height: scrollbarButtonSize,
width: scrollbarButtonSize,
padding: 0
}
}, /*#__PURE__*/_react.default.createElement(_.ArrowIcon, {
theme: theme,
direction: horizontal ? 'right' : 'down',
disabled: contentFullyVisible,
segments: small ? 3 : 4
}))));
};
const styles = _reactNative.StyleSheet.create({
wrapper: {
display: 'flex',
position: 'relative'
},
content: {
flexGrow: 1,
flexShrink: 1
},
scrollbarTrack: {
overflow: 'hidden',
flex: 1
},
background: {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0
}
});
var _default = (0, _theming.withTheme)(ScrollView);
exports.default = _default;
//# sourceMappingURL=ScrollView.js.map