UNPKG

kubric

Version:

Android's co-ordinator layout ported to work on react native (iOS and Android)

328 lines (327 loc) 17 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); var React = __importStar(require("react")); var react_native_1 = require("react-native"); var Styles_1 = require("./resources/Styles"); var bars_1 = require("./bars"); var Behaviours_1 = require("./Behaviours"); var ANIMATION_DURATION = 300; var MIN_ANIMATION_DURATION = 150; var CLContainer = /** @class */ (function (_super) { __extends(CLContainer, _super); function CLContainer(props, context) { var _this = _super.call(this, props, context) || this; _this._scrollBehaviourOffset = 0; _this._scrollBehaviourOffsetAnimatedValue = new react_native_1.Animated.Value(0); _this._lastOffsetY = 0; _this._minPaddingY = 0; _this._maxPaddingY = 0; _this._cummulativeDimensionRange = { appBar: { minHeight: 0, maxHeight: 0 }, bottomBar: { minHeight: 0, maxHeight: 0 } }; _this._contentSize = { width: 0, height: 0 }; _this._scrollviewLayout = { x: 0, y: 0, width: 0, height: 0 }; _this._animating = false; _this._onContentSizeChange = function (w, h) { _this._contentSize.width = w; _this._contentSize.height = h; }; _this._onScrollEndDrag = function (event) { var nativeEvent = event && event.nativeEvent; if (nativeEvent && nativeEvent.velocity && nativeEvent.velocity.y !== 0) { return; } _this._finishTransition(); }; _this._onMomentumScrollEnd = function (event) { var nativeEvent = event && event.nativeEvent; if (!nativeEvent || (nativeEvent && ((nativeEvent.velocity && nativeEvent.velocity.y === 0) || nativeEvent.velocity === undefined))) { _this._finishTransition(); } }; _this._calculateBehaviour = function (newProps) { var safeAreaInsets = newProps.safeAreaInsets ? newProps.safeAreaInsets : { top: 0, left: 0, bottom: 0, right: 0 }; var cummulativeAppBarDimensionRange; var cummulativeBottomBarDimensionRange; var hasAppBar = newProps.appBarScrollBehaviours && newProps.appBarScrollBehaviours.length > 0 && newProps.appBarContentRenderer !== undefined; var hasBottomBar = newProps.bottomBarScrollBehaviours && newProps.bottomBarScrollBehaviours.length > 0 && newProps.bottomBarContentRenderer !== undefined; if (newProps.appBarScrollBehaviours) { cummulativeAppBarDimensionRange = _this._calculateBehaviourForBar(newProps.appBarScrollBehaviours, __assign(__assign({}, safeAreaInsets), { bottom: 0, top: hasAppBar ? safeAreaInsets.top : 0 })); } else { cummulativeAppBarDimensionRange = { minHeight: 0, maxHeight: 0 }; } if (newProps.bottomBarScrollBehaviours) { cummulativeBottomBarDimensionRange = _this._calculateBehaviourForBar(newProps.bottomBarScrollBehaviours, __assign(__assign({}, safeAreaInsets), { top: 0, bottom: hasBottomBar ? safeAreaInsets.bottom : 0 })); } else { cummulativeBottomBarDimensionRange = { minHeight: 0, maxHeight: 0 }; } return { appBar: { minHeight: cummulativeAppBarDimensionRange.minHeight, maxHeight: cummulativeAppBarDimensionRange.maxHeight }, bottomBar: { minHeight: cummulativeBottomBarDimensionRange.minHeight, maxHeight: cummulativeBottomBarDimensionRange.maxHeight } }; }; _this._calculateBehaviourForBar = function (scrollBehaviours, safeAreaInsets) { var _deducedItemDimensionBehaviours = []; var minHeight = safeAreaInsets ? (safeAreaInsets.top || 0) + (safeAreaInsets.bottom || 0) : 0; var maxHeight = minHeight; for (var _i = 0, scrollBehaviours_1 = scrollBehaviours; _i < scrollBehaviours_1.length; _i++) { var behaviour = scrollBehaviours_1[_i]; var deducedDimensionRange = { minHeight: 0, maxHeight: behaviour.maxHeight }; if (behaviour.scrollEffect & Behaviours_1.CLScrollEffect.COLLAPSE) { deducedDimensionRange.minHeight = behaviour.minHeight; } else if ((behaviour.scrollEffect & Behaviours_1.CLScrollEffect.SCROLL) === Behaviours_1.CLScrollEffect.NONE) { deducedDimensionRange.minHeight = behaviour.maxHeight; } _deducedItemDimensionBehaviours.push(deducedDimensionRange); minHeight += deducedDimensionRange.minHeight; maxHeight += deducedDimensionRange.maxHeight; } return { minHeight: minHeight, maxHeight: maxHeight }; }; _this._animateToScrollBehaviourOffset = function (targetOffset, from, animate) { if (animate) { if (_this._animating) { return; } _this._animating = true; var fromOffset = from || (targetOffset > 0.5 ? 1 : 0); var duration = Math.max((targetOffset > fromOffset ? 1 : -1) * (targetOffset - fromOffset) * ANIMATION_DURATION, MIN_ANIMATION_DURATION); react_native_1.Animated.timing(_this._scrollBehaviourOffsetAnimatedValue, { toValue: targetOffset, duration: duration, easing: react_native_1.Easing.ease, useNativeDriver: _this.props.useNativeDriver ? _this.props.useNativeDriver : false }).start(function (_result) { _this._scrollBehaviourOffset = targetOffset; _this._animating = false; _this._notifyProgress(); }); } }; _this._updateScrollBehavior = function (nextY) { var delta = (nextY - _this._lastOffsetY) / (_this._maxPaddingY - _this._minPaddingY); _this._scrollDirection = delta > 0 ? 'down' : delta < 0 ? 'up' : _this._scrollDirection; var nextOffset = _this._scrollBehaviourOffset + delta; _this._setBehaviourOffset(nextOffset); _this._lastOffsetY = nextY; }; _this._onScrollViewLayout = function (event) { if (_this.props.onLayout) { _this.props.onLayout(event); } var rectangle = event.nativeEvent.layout; _this._scrollviewLayout.width = rectangle.width; _this._scrollviewLayout.height = rectangle.height; }; _this._scrollListner = function (event) { if (_this._animating) { return; } if (event) { var nextY = event.nativeEvent.contentOffset.y; var isOffsetWithinBounds = nextY + event.nativeEvent.layoutMeasurement.height <= event.nativeEvent.contentSize.height; var isContentHeightGreaterThanLayout = nextY > event.nativeEvent.contentSize.height - event.nativeEvent.layoutMeasurement.height; if (nextY < 0 || isContentHeightGreaterThanLayout || !isOffsetWithinBounds) { return; } _this._updateScrollBehavior(nextY); } }; _this._cummulativeDimensionRange = _this._calculateBehaviour(_this.props); return _this; } CLContainer.prototype.UNSAFE_componentWillMount = function () { if (this.props.offset) { this._setBehaviourOffset(this.props.offset); } }; CLContainer.prototype.UNSAFE_componentWillReceiveProps = function (nextProps, _nextContext) { this._cummulativeDimensionRange = this._calculateBehaviour(nextProps); if (this.props.offset !== nextProps.offset) { this._setBehaviourOffset(nextProps.offset ? nextProps.offset : 0); } }; CLContainer.prototype.render = function () { var hasScroller = this.props.renderScrollComponent !== undefined; var hasAppBar = this.props.appBarScrollBehaviours && this.props.appBarScrollBehaviours.length > 0 && this.props.appBarContentRenderer !== undefined; var hasBottomBar = this.props.bottomBarScrollBehaviours && this.props.bottomBarScrollBehaviours.length > 0 && this.props.bottomBarContentRenderer !== undefined; var safeAreaInsets = this.props.safeAreaInsets ? this.props.safeAreaInsets : { top: 0, left: 0, bottom: 0, right: 0 }; var paddingTop = hasAppBar ? 0 : safeAreaInsets.top; var paddingBottom = hasBottomBar ? 0 : safeAreaInsets.bottom; this._minPaddingY = this._cummulativeDimensionRange.appBar.minHeight + this._cummulativeDimensionRange.bottomBar.minHeight; this._maxPaddingY = this._cummulativeDimensionRange.appBar.maxHeight + this._cummulativeDimensionRange.bottomBar.maxHeight; var scrollBehvavioutOffsetInterpolation = this._scrollBehaviourOffsetAnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [0, 1], extrapolate: 'clamp' }); if (!hasScroller && !hasAppBar && !hasBottomBar) { return <react_native_1.View style={[Styles_1.styles.fill, this.props.style]}/>; } return (<react_native_1.View style={[{ paddingBottom: paddingBottom, paddingTop: paddingTop }, Styles_1.styles.fill, this.props.style]}> {this.props.renderScrollComponent ? this.props.renderScrollComponent({ contentContainerStyle: { paddingTop: this._cummulativeDimensionRange.appBar.maxHeight, paddingBottom: this._cummulativeDimensionRange.bottomBar.minHeight }, style: Styles_1.styles.fill, scrollEventThrottle: 16, onScroll: this._maxPaddingY === this._minPaddingY ? undefined : this._scrollListner, onScrollEndDrag: this._onScrollEndDrag, onMomentumScrollEnd: this._onMomentumScrollEnd, onContentSizeChange: this._onContentSizeChange, onLayout: this._onScrollViewLayout }) : undefined} {this.props.appBarContentRenderer && this.props.appBarScrollBehaviours !== undefined ? (this.props.renderAppBar ? (this.props.renderAppBar({ style: Styles_1.styles.header, safeAreaInsets: __assign(__assign({}, safeAreaInsets), { bottom: 0 }), scrollBehaviourOffset: scrollBehvavioutOffsetInterpolation, scrollBehaviours: this.props.appBarScrollBehaviours, contentRenderer: this.props.appBarContentRenderer, showSeparator: true })) : (<bars_1.CLAppBar style={Styles_1.styles.header} safeAreaInsets={__assign(__assign({}, safeAreaInsets), { bottom: 0 })} scrollBehaviourOffset={scrollBehvavioutOffsetInterpolation} scrollBehaviours={this.props.appBarScrollBehaviours} contentRenderer={this.props.appBarContentRenderer} showSeparator/>)) : (undefined)} {this.props.bottomBarContentRenderer && this.props.bottomBarScrollBehaviours !== undefined ? (this.props.renderBottomBar ? (this.props.renderBottomBar({ style: Styles_1.styles.footer, safeAreaInsets: __assign(__assign({}, safeAreaInsets), { top: 0 }), scrollBehaviourOffset: scrollBehvavioutOffsetInterpolation, scrollBehaviours: this.props.bottomBarScrollBehaviours, contentRenderer: this.props.bottomBarContentRenderer, showSeparator: true })) : (<bars_1.CLBottomBar style={Styles_1.styles.footer} safeAreaInsets={__assign(__assign({}, safeAreaInsets), { top: 0 })} scrollBehaviourOffset={scrollBehvavioutOffsetInterpolation} scrollBehaviours={this.props.bottomBarScrollBehaviours} contentRenderer={this.props.bottomBarContentRenderer} showSeparator/>)) : (undefined)} </react_native_1.View>); }; /** * expandLayout * Use this method to reset the layout to beginning offset */ CLContainer.prototype.expandLayout = function () { this._animateToScrollBehaviourOffset(0, this._scrollBehaviourOffset, true); }; /** * collapseLayout * Use this method to apply full behaviour offset to bar i.e. collapse the bars */ CLContainer.prototype.collapseLayout = function () { this._animateToScrollBehaviourOffset(1, this._scrollBehaviourOffset, true); }; CLContainer.prototype._notifyProgress = function () { if (this.props.onProgress) { this.props.onProgress(this._scrollBehaviourOffset, this._scrollBehaviourOffsetAnimatedValue, this._cummulativeDimensionRange); } }; CLContainer.prototype._setBehaviourOffset = function (nextOffset) { this._scrollBehaviourOffset = nextOffset > 1 ? 1 : nextOffset < 0 ? 0 : nextOffset; this._scrollBehaviourOffsetAnimatedValue.setValue(this._scrollBehaviourOffset); this._notifyProgress(); }; CLContainer.prototype._finishTransition = function () { if (this._scrollBehaviourOffset === 0 || this._scrollBehaviourOffset === 1) { return; } var targetOffset; if (this._lastOffsetY < this._cummulativeDimensionRange.appBar.maxHeight) { targetOffset = 0; } else if (this._scrollDirection === 'up') { targetOffset = this._scrollBehaviourOffset < 0.1 ? 0 : 1; } else if (this._scrollDirection === 'down') { targetOffset = this._scrollBehaviourOffset > 0.9 ? 1 : 0; } else { targetOffset = this._scrollBehaviourOffset < 0.5 ? 0 : 1; } this._animateToScrollBehaviourOffset(targetOffset, this._scrollBehaviourOffset, true); }; return CLContainer; }(React.Component)); exports.CLContainer = CLContainer; /** ************************* Experimental, Do NOT delete **************************** */ // export interface BarContentProps extends ViewProperties { // scrollBehaviourOffset: Animated.AnimatedInterpolation; // scrollBehaviour: CLScrollBehaviour; // } // export abstract class BarContent extends React.Component<BarContentProps, any> { // getScrollBehaviour(): CLScrollBehaviour { // return this.props.scrollBehaviour; // } // abstract getDimensionBehaviour(): CLDimensionBehaviour; // abstract render(): JSX.Element; // } // export class BaseBarContent extends BarContent { // private _maxHeight: number = 0; // private _minHeight: number = 0; // constructor(props: BarContentProps) { // super(props); // this.getDimensionBehaviour = this.getDimensionBehaviour.bind(this); // this.getScrollBehaviour = this.getScrollBehaviour.bind(this); // this._maxHeight = 66; // if (this.props.scrollBehaviour | CLScrollBehaviour.SCROLL) { // this._minHeight = 0; // } // } // getDimensionBehaviour() { // return { maxHeight: this._maxHeight, minHeight: this._minHeight }; // } // render() { // // debugger; // const height = this.props.scrollBehaviourOffset.interpolate({ // inputRange: [0, 1], // outputRange: [this._maxHeight, this._minHeight], // extrapolate: 'clamp' // }); // return ( // <Animated.View style={[styles.barContent, { height: height }]} {...this.props}> // <Text>BottomBarContent</Text> // </Animated.View> // ); // } // } // } //# sourceMappingURL=Container.js.map