UNPKG

tuya-panel-kit

Version:

a functional component library for developing tuya device panels!

670 lines (566 loc) 24.3 kB
Object.defineProperty(exports, "__esModule", { value: true }); 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 _jsxFileName = 'src/components/tabs/index.js'; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[typeof Symbol === 'function' ? Symbol.iterator : '@@iterator'](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if ((typeof Symbol === 'function' ? Symbol.iterator : '@@iterator') in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); 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 _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactNative = require('react-native'); var _utils = require('../../utils'); var _constant = require('./constant'); var _styled = require('./styled'); var _utils2 = require('./utils'); var _tabMask = require('./tab-mask'); var _tabMask2 = _interopRequireDefault(_tabMask); var _tabPanel = require('./tab-panel'); var _tabPanel2 = _interopRequireDefault(_tabPanel); var _tabContent = require('./tab-content'); var _tabContent2 = _interopRequireDefault(_tabContent); var _tabScrollView = require('./tab-scroll-view'); var _tabScrollView2 = _interopRequireDefault(_tabScrollView); var _TYText = require('../TYText'); var _TYText2 = _interopRequireDefault(_TYText); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 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 get = _utils.CoreUtils.get; var winWidth = _utils.RatioUtils.winWidth; var Tabs = function (_Component) { _inherits(Tabs, _Component); function Tabs(props) { _classCallCheck(this, Tabs); var _this = _possibleConstructorReturn(this, (Tabs.__proto__ || Object.getPrototypeOf(Tabs)).call(this, props)); _initialiseProps.call(_this); if (Array.isArray(props.dataSource) && Array.isArray(props.children) && props.dataSource.length !== props.children.length) { console.warn('Tabs: 数据源与children数量不匹配,请检查是否配置错误'); } _this.state = { activeIndex: _this.getCurActiveIndex(props), scrollX: new _reactNative.Animated.Value(0), underlineLeft: new _reactNative.Animated.Value(0), underlineWidth: new _reactNative.Animated.Value(0) }; var styleObj = _reactNative.StyleSheet.flatten([props.wrapperStyle, props.style]); _this._tabsWidth = (styleObj.width || winWidth) - props.extraSpace; _this._tabWidth = (0, _utils2.getTabWidth)(props.maxItem, _this._tabsWidth); _this._bounds = [0, -_this._tabWidth * props.dataSource.length + _this._tabsWidth]; _this._curDeltaX = 0; _this._tabIsReady = false; _this._tabLayouts = []; _this._cachedChildren = Array.isArray(props.children) ? new Array(props.children.length).fill(0) : []; _this._panResponder = _reactNative.PanResponder.create({ onStartShouldSetPanResponder: function onStartShouldSetPanResponder() { return !_this.props.disabled; }, onStartShouldSetPanResponderCapture: function onStartShouldSetPanResponderCapture() { return !_this.props.disabled; }, onMoveShouldSetPanResponder: function onMoveShouldSetPanResponder() { return !_this.props.disabled; }, onMoveShouldSetPanResponderCapture: function onMoveShouldSetPanResponderCapture() { return !_this.props.disabled; }, onPanResponderTerminationRequest: function onPanResponderTerminationRequest() { return !_this.props.disabled; }, onPanResponderGrant: function onPanResponderGrant() {}, onPanResponderMove: _this._handleMove, onPanResponderRelease: _this._handleRelease, onPanResponderTerminate: _this._handleRelease }); return _this; } _createClass(Tabs, [{ key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { var _this2 = this; if (this._tabIsReady && typeof nextProps.activeKey !== 'undefined') { this.setState({ activeIndex: this.getCurActiveIndex(nextProps) }, function () { _this2._startUnderlineAnimation(_this2.state.activeIndex); }); } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { this._stopAllAnimations(); } }, { key: '_moveTo', value: function _moveTo(dx) { var deltaX = this._curDeltaX + dx; var _bounds = _slicedToArray(this._bounds, 2), leftBound = _bounds[0], rightBound = _bounds[1]; if (dx > 0 && deltaX >= leftBound) { deltaX = leftBound + (deltaX - leftBound) * _constant.FRICTION_LEVEL; } else if (dx < 0 && deltaX <= rightBound) { deltaX = rightBound + (deltaX - rightBound) * _constant.FRICTION_LEVEL; } this.state.scrollX.setValue(deltaX); return deltaX; } }, { key: 'render', value: function render() { var _props = this.props, accessibilityLabel = _props.accessibilityLabel, style = _props.style, wrapperStyle = _props.wrapperStyle, tabContentStyle = _props.tabContentStyle, dataSource = _props.dataSource, tabPosition = _props.tabPosition, swipeable = _props.swipeable, maxItem = _props.maxItem, background = _props.background, preload = _props.preload, preloadTimeout = _props.preloadTimeout, velocityThreshold = _props.velocityThreshold, renderPlaceholder = _props.renderPlaceholder, children = _props.children; var showMask = this.state.activeIndex <= dataSource.length - maxItem; var tabsComponent = _react2.default.createElement( _styled.StyledTab, _extends({ key: 'Tabs', style: [style, { width: this._tabsWidth, backgroundColor: background }], pointerEvents: 'box-only' }, this._panResponder.panHandlers, { __source: { fileName: _jsxFileName, lineNumber: 587 } }), this._renderTabs(), this._renderUnderline(), _react2.default.createElement(_tabMask2.default, { visible: this.isMultiScreen && showMask, color: background, __source: { fileName: _jsxFileName, lineNumber: 595 } }) ); if (_react2.default.Children.count(children) > 0) { var content = [tabsComponent, _react2.default.createElement( _tabContent2.default, { key: 'TabContent', accessibilityLabel: accessibilityLabel, style: [tabContentStyle, { width: this._tabsWidth }], activeIndex: this.state.activeIndex, disabled: !swipeable, preload: preload, preloadTimeout: preloadTimeout, velocityThreshold: velocityThreshold, renderPlaceholder: renderPlaceholder, onMove: this._handleTabContentMove, onRelease: this._handleTabContentRelease, __source: { fileName: _jsxFileName, lineNumber: 601 } }, this.props.children )]; if (tabPosition === 'bottom') content.reverse(); return _react2.default.createElement( _reactNative.View, { style: [{ flex: 1, overflow: 'hidden', backgroundColor: 'transparent' }, wrapperStyle], __source: { fileName: _jsxFileName, lineNumber: 619 } }, content ); } return tabsComponent; } }, { key: 'isMultiScreen', get: function get() { return this.props.dataSource.length > this.props.maxItem; } }]); return Tabs; }(_react.Component); Tabs.TabPanel = _tabPanel2.default; Tabs.TabContent = _tabContent2.default; Tabs.TabScrollView = _tabScrollView2.default; Tabs.propTypes = { accessibilityLabel: _propTypes2.default.string, style: _reactNative.ViewPropTypes.style, wrapperStyle: _reactNative.ViewPropTypes.style, tabStyle: _reactNative.ViewPropTypes.style, tabActiveStyle: _reactNative.ViewPropTypes.style, tabTextStyle: _TYText2.default.propTypes.style, tabActiveTextStyle: _TYText2.default.propTypes.style, tabContentStyle: _reactNative.ViewPropTypes.style, underlineStyle: _reactNative.ViewPropTypes.style, underlineWidth: _propTypes2.default.number, defaultActiveKey: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]), activeKey: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]), dataSource: _propTypes2.default.array.isRequired, disabled: _propTypes2.default.bool, maxItem: _propTypes2.default.number, tabPosition: _propTypes2.default.oneOf(['top', 'bottom']), swipeable: _propTypes2.default.bool, activeColor: _reactNative.ColorPropType, background: _reactNative.ColorPropType, preload: _propTypes2.default.bool, preloadTimeout: _propTypes2.default.number, velocityThreshold: _propTypes2.default.number, renderPlaceholder: _propTypes2.default.func, onChange: _propTypes2.default.func, children: _propTypes2.default.array, extraSpace: _propTypes2.default.number, animationConfig: _propTypes2.default.shape({ duration: _propTypes2.default.number, easing: _propTypes2.default.func, delay: _propTypes2.default.number, isInteraction: _propTypes2.default.bool, useNativeDriver: _propTypes2.default.bool }) }; Tabs.defaultProps = { accessibilityLabel: 'Tabs', style: null, wrapperStyle: null, tabStyle: null, tabActiveStyle: null, tabTextStyle: null, tabActiveTextStyle: null, tabContentStyle: null, underlineStyle: null, underlineWidth: undefined, defaultActiveKey: 0, activeKey: undefined, disabled: false, maxItem: 4, tabPosition: 'top', swipeable: true, activeColor: undefined, background: '#fff', onChange: undefined, preload: true, preloadTimeout: 375, velocityThreshold: 0.5, renderPlaceholder: undefined, children: undefined, extraSpace: 0, animationConfig: { duration: 200, easing: _reactNative.Easing.linear, delay: 0, isInteraction: true, useNativeDriver: false } }; var _initialiseProps = function _initialiseProps() { var _this3 = this; this.getCurActiveIndex = function (props) { var activeKey = props.activeKey, defaultActiveKey = props.defaultActiveKey; var dataSource = _this3.props.dataSource; var activeIndex = dataSource.findIndex(function (d) { return d.value === activeKey || d.value === defaultActiveKey; }); return activeIndex === -1 ? 0 : activeIndex; }; this.getCurTabLayout = function (idx) { var curTabLayout = get(_this3._tabLayouts, '' + idx, {}); return curTabLayout; }; this.scrollToIndex = function (idx, cb) { var _props2 = _this3.props, animationConfig = _props2.animationConfig, dataSource = _props2.dataSource; if (idx > dataSource.length - 1) { return; } var toValue = -_this3._tabWidth * idx; _this3._stopAllAnimations(); _this3._curDeltaX = toValue; _reactNative.Animated.timing(_this3.state.scrollX, _extends({ toValue: toValue }, animationConfig, { useNativeDriver: false })).start(cb); }; this._startUnderlineAnimation = function (idx, cb) { var _props3 = _this3.props, animationConfig = _props3.animationConfig, dataSource = _props3.dataSource, maxItem = _props3.maxItem; if (idx > dataSource.length - 1) { return; } var curTabLayout = _this3.getCurTabLayout(idx); _this3._stopAllAnimations(); _this3.animationFn = _reactNative.Animated.parallel([_reactNative.Animated.timing(_this3.state.underlineLeft, _extends({ toValue: curTabLayout.left }, animationConfig, { useNativeDriver: false })), _reactNative.Animated.timing(_this3.state.underlineWidth, _extends({ toValue: curTabLayout.width }, animationConfig, { useNativeDriver: false }))]); _this3.animationFn.start(function () { var scrollIdx = (0, _utils2.getCenteredScrollIndex)(idx, maxItem, dataSource.length); _this3.scrollToIndex(scrollIdx); typeof cb === 'function' && cb(); }); }; this._stopAllAnimations = function () { _this3.state.scrollX.stopAnimation(); _this3.state.underlineLeft.stopAnimation(); _this3.state.underlineWidth.stopAnimation(); }; this._handleMove = function (e, _ref) { var dx = _ref.dx; if (_this3.isMultiScreen) { _this3._moveTo(dx); } }; this._handleRelease = function (_ref2, _ref3) { var nativeEvent = _ref2.nativeEvent; var dx = _ref3.dx, dy = _ref3.dy, vx = _ref3.vx; var isPress = (0, _utils2.isValidPress)(dx, dy); if (isPress) { var locationX = nativeEvent.locationX; var deltaX = Math.abs(_this3._curDeltaX) + Math.abs(locationX); var idx = (0, _utils2.getIndexByDeltaX)(deltaX, _this3._tabWidth); _this3._handleTabChange(_this3.props.dataSource[idx], idx); } else if (_this3.isMultiScreen) { var _bounds2 = _slicedToArray(_this3._bounds, 2), leftBound = _bounds2[0], rightBound = _bounds2[1]; var _props4 = _this3.props, dataSource = _props4.dataSource, maxItem = _props4.maxItem; var _deltaX = _this3._moveTo(dx); var maxIdx = Math.max(dataSource.length - maxItem, 0); if (dx > 0 && _deltaX >= leftBound || dx < 0 && _deltaX <= rightBound) { var _idx = (0, _utils2.getNearestIndexByDeltaX)(_deltaX, _this3._tabWidth, maxIdx); _this3.scrollToIndex(_idx); } else if ((0, _utils2.isValidSwipe)(vx, dx)) { _this3.state.scrollX.addListener(function (_ref4) { var value = _ref4.value; if (value > leftBound) { _this3._curDeltaX = leftBound; _this3.state.scrollX.stopAnimation(); _this3.state.scrollX.setValue(leftBound); } else if (value < rightBound) { _this3._curDeltaX = rightBound; _this3.state.scrollX.stopAnimation(); _this3.state.scrollX.setValue(rightBound); } else { _this3._curDeltaX = value; } }); _reactNative.Animated.decay(_this3.state.scrollX, { velocity: vx, deceleration: _constant.DECELERATION }).start(function () { _this3._curDeltaX = _this3.state.scrollX._value; _this3.state.scrollX.removeAllListeners(); }); } else { _this3._curDeltaX = _deltaX; } } }; this._handleTabLayout = function (_ref5, idx) { var layout = _ref5.nativeEvent.layout; var dataSource = _this3.props.dataSource; _this3._tabLayouts[idx] = layout; _this3._tabIsReady = _this3._tabLayouts.filter(function (d) { return !!d; }).length === dataSource.length; if (_this3._tabIsReady) { _this3._tabLayouts = (0, _utils2.reduceTabLayoutLeft)(_this3._tabLayouts); _this3._startUnderlineAnimation(_this3.state.activeIndex); } }; this._handleTabChange = function (tab, idx) { var _props5 = _this3.props, dataSource = _props5.dataSource, activeKey = _props5.activeKey, onChange = _props5.onChange; if (idx > dataSource.length - 1 || tab && tab.disabled) { return; } if (typeof activeKey === 'undefined') { _this3.setState({ activeIndex: idx }, function () { _this3._startUnderlineAnimation(idx); }); } typeof onChange === 'function' && _this3.props.onChange(tab, idx); }; this._handleTabContentMove = function (gestureState, idx, percent) { var dataSource = _this3.props.dataSource; var dx = gestureState.dx; var minIdx = 0; var maxIdx = dataSource.length - 1; var isToRight = dx < 0; var rPercent = isToRight ? percent : 1 - percent; var isNextPage = rPercent >= 0.5; if (isToRight) { var nextIdx = Math.min(isNextPage ? idx : idx + 1, maxIdx); if (_this3.state.activeIndex === maxIdx && nextIdx === maxIdx) { return; } var curTabLayout = _this3.getCurTabLayout(_this3.state.activeIndex); var nextTabLayout = _this3.getCurTabLayout(nextIdx); var curLeft = curTabLayout.left, curWidth = curTabLayout.width; var nextLeft = nextTabLayout.left, nextWidth = nextTabLayout.width; var moveDelta = curWidth * 0.666667; var totalLen = nextLeft + nextWidth * 0.5 - curLeft - curWidth; var newWidth = curTabLayout.width + (totalLen - moveDelta) * Math.min(rPercent * 2, 1); var newLeft = curLeft + moveDelta * Math.min(rPercent * 2, 1); if (isNextPage) { var extraWidth = nextLeft - curLeft; newWidth -= extraWidth * Math.min((rPercent - 0.5) * 2, 1); newLeft += extraWidth * Math.min((rPercent - 0.5) * 2, 1); } _this3.state.underlineWidth.setValue(newWidth); _this3.state.underlineLeft.setValue(newLeft); } else { var _nextIdx = Math.max(isNextPage ? idx : idx - 1, minIdx); if (_this3.state.activeIndex === minIdx && _nextIdx === minIdx) { return; } var _curTabLayout = _this3.getCurTabLayout(_this3.state.activeIndex); var _nextTabLayout = _this3.getCurTabLayout(_nextIdx); var _curLeft = _curTabLayout.left, _curWidth = _curTabLayout.width; var _nextLeft = _nextTabLayout.left, _nextWidth = _nextTabLayout.width; var _moveDelta = _curWidth * 0.333333; var _totalLen = _curLeft - _nextLeft - _nextWidth * 0.5; var _newWidth = _curTabLayout.width + (_totalLen - _moveDelta) * Math.min(rPercent * 2, 1); var _newLeft = _curLeft - _moveDelta * Math.min(rPercent * 2, 1); if (isNextPage) { var _extraWidth = _curLeft - _nextLeft; _newWidth -= _extraWidth * Math.min((rPercent - 0.5) * 2, 1); _newLeft -= _extraWidth * Math.min((rPercent - 0.5) * 2, 1); } _this3.state.underlineWidth.setValue(_newWidth); _this3.state.underlineLeft.setValue(_newLeft - (_newWidth - _curWidth)); } }; this._handleTabContentRelease = function (gestureState, idx) { var dataSource = _this3.props.dataSource; _this3._handleTabChange(dataSource[idx], idx); _this3._startUnderlineAnimation(idx); }; this._renderTab = function (tab, idx) { var _props6 = _this3.props, accessibilityLabel = _props6.accessibilityLabel, tabStyle = _props6.tabStyle, tabActiveStyle = _props6.tabActiveStyle, tabTextStyle = _props6.tabTextStyle, tabActiveTextStyle = _props6.tabActiveTextStyle, activeColor = _props6.activeColor, underlineWidth = _props6.underlineWidth; var label = tab.label, renderTab = tab.renderTab, rest = _objectWithoutProperties(tab, ['label', 'renderTab']); var isActive = idx === _this3.state.activeIndex; var isFixedWidth = typeof underlineWidth === 'number'; var TabText = _react2.default.createElement(_styled.StyledTabText, { style: [tabTextStyle, isActive && tabActiveTextStyle], color: activeColor, text: label, isActive: isActive, __source: { fileName: _jsxFileName, lineNumber: 493 } }); return _react2.default.createElement( _styled.Center, _extends({ key: idx }, rest, { accessibilityLabel: accessibilityLabel + '_' + idx, style: [{ width: _this3._tabWidth }, tab.disabled && { opacity: 0.3 }], __source: { fileName: _jsxFileName, lineNumber: 501 } }), _react2.default.createElement( _styled.StyledTabBtn, { style: [isFixedWidth && { width: underlineWidth }, tabStyle, isActive && tabActiveStyle], onLayout: function onLayout(evt) { return _this3._handleTabLayout(evt, idx); }, __source: { fileName: _jsxFileName, lineNumber: 507 } }, !isFixedWidth ? typeof renderTab === 'function' ? renderTab(isActive, _this3.state, _this3.props) : TabText : null ), isFixedWidth ? typeof renderTab === 'function' ? renderTab(isActive, _this3.state, _this3.props) : TabText : null ); }; this._renderTabs = function () { var dataSource = _this3.props.dataSource; if (_this3.isMultiScreen) { var width = dataSource.length * _this3._tabWidth; return _react2.default.createElement( _styled.AnimatedView, { style: { width: width, transform: [{ translateX: _this3.state.scrollX }] }, __source: { fileName: _jsxFileName, lineNumber: 531 } }, dataSource.map(_this3._renderTab) ); } return dataSource.map(_this3._renderTab); }; this._renderUnderline = function () { var _props7 = _this3.props, activeColor = _props7.activeColor, underlineStyle = _props7.underlineStyle, dataSource = _props7.dataSource; var activeIndex = _this3.state.activeIndex; var _StyleSheet$flatten = _reactNative.StyleSheet.flatten([underlineStyle]), backgroundColor = _StyleSheet$flatten.backgroundColor; var disabled = get(dataSource, activeIndex + '.disabled', false); return _react2.default.createElement(_styled.AnimatedUnderline, { style: [underlineStyle, disabled && { opacity: 0.3 }, { width: _this3.state.underlineWidth, transform: [{ translateX: _reactNative.Animated.add(_this3.state.scrollX, _this3.state.underlineLeft) }] }], color: backgroundColor || activeColor, __source: { fileName: _jsxFileName, lineNumber: 554 } }); }; }; exports.default = Tabs;