create-expo-cljs-app
Version:
Create a react native application with Expo and Shadow-CLJS!
463 lines (396 loc) • 21.5 kB
JavaScript
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
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; }
import * as React from 'react';
import { Dimensions, Platform, View } from 'react-native';
import Animated from 'react-native-reanimated';
import { PanGestureHandler, TapGestureHandler, State as GestureState } from 'react-native-gesture-handler';
const {
height: screenHeight
} = Dimensions.get('window');
const P = (android, ios) => Platform.OS === 'ios' ? ios : android;
const magic = {
damping: 50,
mass: 0.3,
stiffness: 121.6,
overshootClamping: true,
restSpeedThreshold: 0.3,
restDisplacementThreshold: 0.3,
deceleration: 0.999,
bouncyFactor: 1,
velocityFactor: P(1, 0.8),
toss: 0.4,
coefForTranslatingVelocities: 5
};
const {
damping,
mass,
stiffness,
overshootClamping,
restSpeedThreshold,
restDisplacementThreshold,
deceleration,
velocityFactor,
toss
} = magic;
const {
set,
cond,
onChange,
block,
eq,
greaterOrEq,
sqrt,
not,
defined,
max,
add,
and,
Value,
spring,
or,
divide,
greaterThan,
sub,
event,
diff,
multiply,
clockRunning,
startClock,
stopClock,
decay,
Clock,
lessThan,
call,
lessOrEq,
neq
} = Animated;
function runDecay(clock, value, velocity, wasStartedFromBegin) {
const state = {
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
time: new Value(0)
};
const config = {
deceleration
};
return [cond(clockRunning(clock), 0, [cond(wasStartedFromBegin, 0, [set(wasStartedFromBegin, 1), set(state.finished, 0), set(state.velocity, multiply(velocity, velocityFactor)), set(state.position, value), set(state.time, 0), startClock(clock)])]), cond(clockRunning(clock), decay(clock, state, config)), cond(state.finished, stopClock(clock)), state.position];
}
function withPreservingAdditiveOffset(drag, state) {
const prev = new Value(0);
const valWithPreservedOffset = new Value(0);
return block([cond(eq(state, GestureState.BEGAN), [set(prev, 0)], [set(valWithPreservedOffset, add(valWithPreservedOffset, sub(drag, prev))), set(prev, drag)]), valWithPreservedOffset]);
}
function withDecaying(drag, state, decayClock, velocity, prevent) {
const valDecayed = new Value(0);
const offset = new Value(0); // since there might be moar than one clock
const wasStartedFromBegin = new Value(0);
return block([cond(eq(state, GestureState.END), [cond(prevent, stopClock(decayClock), set(valDecayed, runDecay(decayClock, add(drag, offset), velocity, wasStartedFromBegin)))], [stopClock(decayClock), cond(eq(state, GestureState.BEGAN), set(prevent, 0)), cond(or(eq(state, GestureState.BEGAN), eq(state, GestureState.ACTIVE)), set(wasStartedFromBegin, 0)), cond(eq(state, GestureState.BEGAN), [set(offset, sub(valDecayed, drag))]), set(valDecayed, add(drag, offset))]), valDecayed]);
}
export default class BottomSheetBehavior extends React.Component {
constructor(props) {
super(props);
_defineProperty(this, "decayClock", new Clock());
_defineProperty(this, "panState", new Value(0));
_defineProperty(this, "tapState", new Value(0));
_defineProperty(this, "velocity", new Value(0));
_defineProperty(this, "panMasterState", new Value(GestureState.END));
_defineProperty(this, "masterVelocity", new Value(0));
_defineProperty(this, "isManuallySetValue", new Value(0));
_defineProperty(this, "manuallySetValue", new Value(0));
_defineProperty(this, "masterClockForOverscroll", new Clock());
_defineProperty(this, "preventDecaying", new Value(0));
_defineProperty(this, "dragMasterY", new Value(0));
_defineProperty(this, "dragY", new Value(0));
_defineProperty(this, "translateMaster", void 0);
_defineProperty(this, "panRef", void 0);
_defineProperty(this, "master", void 0);
_defineProperty(this, "tapRef", void 0);
_defineProperty(this, "snapPoint", void 0);
_defineProperty(this, "Y", void 0);
_defineProperty(this, "clampingValue", new Value(0));
_defineProperty(this, "onOpenStartValue", new Value(0));
_defineProperty(this, "onOpenEndValue", new Value(0));
_defineProperty(this, "onCloseStartValue", new Value(1));
_defineProperty(this, "onCloseEndValue", new Value(0));
_defineProperty(this, "handleMasterPan", event([{
nativeEvent: {
translationY: this.dragMasterY,
state: this.panMasterState,
velocityY: this.masterVelocity
}
}]));
_defineProperty(this, "handlePan", event([{
nativeEvent: {
translationY: this.props.enabledInnerScrolling ? this.dragY : this.dragMasterY,
state: this.props.enabledInnerScrolling ? this.panState : this.panMasterState,
velocityY: this.props.enabledInnerScrolling ? this.velocity : this.masterVelocity
}
}]));
_defineProperty(this, "handleTap", event([{
nativeEvent: {
state: this.tapState
}
}]));
_defineProperty(this, "snapTo", index => {
if (!this.props.enabledImperativeSnapping) {
return;
}
this.isManuallySetValue.setValue(1);
this.manuallySetValue.setValue( // @ts-ignore
this.state.snapPoints[this.state.propsToNewIndices[index]]);
});
_defineProperty(this, "height", new Value(0));
_defineProperty(this, "handleLayoutHeader", ({
nativeEvent: {
layout: {
height: heightOfHeader
}
}
}) => {
this.state.heightOfHeaderAnimated.setValue(heightOfHeader);
this.setState({
heightOfHeader
});
});
_defineProperty(this, "handleFullHeader", ({
nativeEvent: {
layout: {
height
}
}
}) => requestAnimationFrame(() => this.height.setValue(height)));
_defineProperty(this, "handleLayoutContent", ({
nativeEvent: {
layout: {
height
}
}
}) => this.state.heightOfContent.setValue(height - this.state.initSnap));
this.panRef = props.innerGestureHandlerRefs[0];
this.master = props.innerGestureHandlerRefs[1];
this.tapRef = props.innerGestureHandlerRefs[2];
this.state = BottomSheetBehavior.getDerivedStateFromProps(props, undefined);
const {
snapPoints,
init
} = this.state;
const middlesOfSnapPoints = [];
for (let i = 1; i < snapPoints.length; i++) {
const tuple = [add(snapPoints[i - 1], 10), sub(snapPoints[i], 25)];
middlesOfSnapPoints.push(tuple);
}
const masterOffseted = new Value(init); // destination point is a approximation of movement if finger released
const tossForMaster = props.springConfig.hasOwnProperty('toss') && props.springConfig.toss != undefined ? props.springConfig.toss : toss;
const destinationPoint = add(masterOffseted, multiply(tossForMaster, this.masterVelocity));
const positive = greaterOrEq(multiply(tossForMaster, this.masterVelocity), 0); // method for generating condition for finding the nearest snap point
const currentSnapPoint = (i = 0) => i + 1 === snapPoints.length ? snapPoints[i] : cond(positive, cond(greaterThan(destinationPoint, middlesOfSnapPoints[i][0]), cond(lessThan(destinationPoint, middlesOfSnapPoints[i][1]), snapPoints[i + 1], currentSnapPoint(i + 1)), snapPoints[i]), cond(greaterThan(destinationPoint, middlesOfSnapPoints[i][1]), cond(lessThan(destinationPoint, middlesOfSnapPoints[i][0]), snapPoints[i + 1], currentSnapPoint(i + 1)), snapPoints[i])); // current snap point desired
this.snapPoint = currentSnapPoint();
if (props.enabledBottomClamp) {
this.clampingValue.setValue(snapPoints[snapPoints.length - 1]);
}
const masterClock = new Clock();
const prevMasterDrag = new Value(0);
const wasRun = new Value(0);
this.translateMaster = block([cond(or(eq(this.panMasterState, GestureState.END), eq(this.panMasterState, GestureState.CANCELLED), eq(this.panMasterState, GestureState.FAILED)), [set(prevMasterDrag, 0), cond(or(clockRunning(masterClock), not(wasRun), this.isManuallySetValue), [cond(this.isManuallySetValue, stopClock(masterClock)), set(masterOffseted, this.runSpring(masterClock, masterOffseted, this.masterVelocity, cond(this.isManuallySetValue, this.manuallySetValue, this.snapPoint), wasRun, this.isManuallySetValue, this.masterVelocity)), set(this.isManuallySetValue, 0)])], [stopClock(masterClock), set(this.preventDecaying, 1), set(masterOffseted, add(masterOffseted, sub(this.dragMasterY, prevMasterDrag))), set(prevMasterDrag, this.dragMasterY), set(wasRun, 0), // not sure about this move for cond-began
cond(eq(this.panMasterState, GestureState.BEGAN), stopClock(this.masterClockForOverscroll))]), cond(greaterThan(masterOffseted, snapPoints[0]), cond(and(props.enabledBottomClamp ? 1 : 0, greaterThan(masterOffseted, this.clampingValue)), this.clampingValue, masterOffseted), max(multiply(sub(snapPoints[0], sqrt(add(1, sub(snapPoints[0], masterOffseted)))), !props.enabledInnerScrolling ? props.overdragResistanceFactor : 0), masterOffseted))]);
this.Y = this.withEnhancedLimits(withDecaying(withPreservingAdditiveOffset(this.dragY, this.panState), this.panState, this.decayClock, this.velocity, this.preventDecaying), masterOffseted);
}
componentDidUpdate(_prevProps, prevState) {
const {
snapPoints
} = this.state;
if (this.props.enabledBottomClamp && snapPoints !== prevState.snapPoints) {
this.clampingValue.setValue(snapPoints[snapPoints.length - 1]);
}
}
runSpring(clock, value, velocity, dest, wasRun, isManuallySet, valueToBeZeroed) {
const state = {
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
time: new Value(0)
};
const config = _objectSpread({
damping,
mass,
stiffness,
overshootClamping,
restSpeedThreshold,
restDisplacementThreshold,
toValue: new Value(0)
}, this.props.springConfig);
return [cond(clockRunning(clock), 0, [set(state.finished, 0), set(state.velocity, velocity), set(state.position, value), set(config.toValue, dest), cond(and(wasRun, not(isManuallySet)), 0, startClock(clock)), cond(defined(wasRun), set(wasRun, 1))]), spring(clock, state, config), cond(state.finished, [stopClock(clock), set(valueToBeZeroed, 0)]), state.position];
}
withEnhancedLimits(val, masterOffseted) {
const wasRunMaster = new Value(0);
const min = multiply(-1, add(this.state.heightOfContent, this.state.heightOfHeaderAnimated));
const prev = new Value(0);
const limitedVal = new Value(0);
const diffPres = new Value(0);
const flagWasRunSpring = new Value(0);
const justEndedIfEnded = new Value(1);
const wasEndedMasterAfterInner = new Value(1);
const prevMaster = new Value(1);
const prevState = new Value(0);
const rev = new Value(0);
return block([set(rev, limitedVal), cond(or(eq(this.panState, GestureState.BEGAN), and(eq(this.panState, GestureState.ACTIVE), eq(prevState, GestureState.END))), [set(prev, val), set(flagWasRunSpring, 0), stopClock(this.masterClockForOverscroll), set(wasRunMaster, 0)], [set(limitedVal, add(limitedVal, sub(val, prev))), cond(lessThan(limitedVal, min), set(limitedVal, min))]), set(prevState, this.panState), // on iOS sometimes BEGAN event does not trigger
set(diffPres, sub(prev, val)), set(prev, val), cond(or(greaterOrEq(limitedVal, 0), greaterThan(masterOffseted, 0)), [cond(eq(this.panState, GestureState.ACTIVE), set(masterOffseted, sub(masterOffseted, diffPres))), cond(greaterThan(masterOffseted, 0), [set(limitedVal, 0)]), cond(not(eq(this.panState, GestureState.END)), set(justEndedIfEnded, 1)), cond(or(eq(this.panState, GestureState.ACTIVE), eq(this.panMasterState, GestureState.ACTIVE)), set(wasEndedMasterAfterInner, 0)), cond(and(eq(prevMaster, GestureState.ACTIVE), eq(this.panMasterState, GestureState.END), eq(this.panState, GestureState.END)), set(wasEndedMasterAfterInner, 1)), set(prevMaster, this.panMasterState), cond(and(eq(this.panState, GestureState.END), not(wasEndedMasterAfterInner), not(eq(this.panMasterState, GestureState.ACTIVE)), not(eq(this.panMasterState, GestureState.BEGAN)), or(clockRunning(this.masterClockForOverscroll), not(wasRunMaster))), [// cond(justEndedIfEnded, set(this.masterVelocity, diff(val))),
set(this.masterVelocity, cond(justEndedIfEnded, diff(val), this.velocity)), set(masterOffseted, this.runSpring(this.masterClockForOverscroll, masterOffseted, diff(val), this.snapPoint, wasRunMaster, 0, this.masterVelocity)), set(this.masterVelocity, 0)]), // cond(eq(this.panState, State.END), set(wasEndedMasterAfterInner, 0)),
cond(eq(this.panState, GestureState.END), set(justEndedIfEnded, 0)), set(this.preventDecaying, 1), 0], [set(this.preventDecaying, 0), limitedVal])]);
}
static getDerivedStateFromProps(props, state) {
let snapPoints;
const sortedPropsSnapPoints = props.snapPoints.map((s, i) => {
if (typeof s === 'number') {
return {
val: s,
ind: i
};
} else if (typeof s === 'string') {
return {
val: BottomSheetBehavior.renumber(s),
ind: i
};
}
throw new Error("Invalid type for value ".concat(s, ": ").concat(typeof s));
}).sort(({
val: a
}, {
val: b
}) => b - a);
if (state && state.snapPoints) {
state.snapPoints.forEach((s, i) => // @ts-ignore
s.__initialized && s.setValue(sortedPropsSnapPoints[0].val - sortedPropsSnapPoints[i].val));
snapPoints = state.snapPoints;
} else {
snapPoints = sortedPropsSnapPoints.map(p => new Value(sortedPropsSnapPoints[0].val - p.val));
}
const propsToNewIndices = {};
sortedPropsSnapPoints.forEach(({
ind
}, i) => propsToNewIndices[ind] = i);
const {
initialSnap
} = props;
let init = sortedPropsSnapPoints[0].val - sortedPropsSnapPoints[propsToNewIndices[initialSnap]].val;
if (props.enabledBottomInitialAnimation) {
init = sortedPropsSnapPoints[sortedPropsSnapPoints.length - 1 - propsToNewIndices[initialSnap]].val;
}
return {
init,
propsToNewIndices,
heightOfHeaderAnimated: state && state.heightOfHeaderAnimated || new Value(0),
heightOfContent: state && state.heightOfContent || new Value(0),
initSnap: sortedPropsSnapPoints[0].val,
snapPoints,
heightOfHeader: state && state.heightOfHeader || 0
};
}
render() {
const {
borderRadius
} = this.props;
return React.createElement(React.Fragment, null, React.createElement(Animated.View, {
style: {
height: '100%',
width: 0,
position: 'absolute'
},
onLayout: this.handleFullHeader
}), React.createElement(Animated.View, {
style: {
width: '100%',
position: 'absolute',
zIndex: 100,
opacity: cond(this.height, 1, 0),
transform: [{
translateY: this.translateMaster
}, {
translateY: sub(this.height, this.state.initSnap)
}]
}
}, React.createElement(PanGestureHandler, {
enabled: this.props.enabledGestureInteraction && this.props.enabledHeaderGestureInteraction,
ref: this.master,
waitFor: this.panRef,
onGestureEvent: this.handleMasterPan,
onHandlerStateChange: this.handleMasterPan,
simultaneousHandlers: this.props.simultaneousHandlers
}, React.createElement(Animated.View, {
style: {
zIndex: 101
},
onLayout: this.handleLayoutHeader
}, this.props.renderHeader && this.props.renderHeader())), React.createElement(View, {
style: this.props.enabledInnerScrolling && {
height: this.state.initSnap - this.state.heightOfHeader,
overflow: this.props.overflow || 'hidden',
borderTopLeftRadius: borderRadius,
borderTopRightRadius: borderRadius
}
}, React.createElement(PanGestureHandler, {
enabled: this.props.enabledGestureInteraction && this.props.enabledContentGestureInteraction,
waitFor: this.master,
ref: this.panRef,
onGestureEvent: this.handlePan,
onHandlerStateChange: this.handlePan,
simultaneousHandlers: this.props.simultaneousHandlers
}, React.createElement(Animated.View, null, React.createElement(TapGestureHandler, {
ref: this.tapRef,
enabled: this.props.enabledGestureInteraction && this.props.enabledContentGestureInteraction && this.props.enabledContentTapInteraction,
onHandlerStateChange: this.handleTap,
simultaneousHandlers: this.props.simultaneousHandlers
}, React.createElement(Animated.View, {
style: {
width: '100%',
transform: [{
translateY: this.Y
}]
},
onLayout: this.handleLayoutContent
}, this.props.renderContent && this.props.renderContent())))), React.createElement(Animated.Code, {
exec: onChange(this.tapState, cond(eq(this.tapState, GestureState.BEGAN), stopClock(this.decayClock)))
}), this.props.callbackNode && React.createElement(Animated.Code, {
exec: onChange(this.translateMaster, set(this.props.callbackNode, divide(this.translateMaster, this.state.snapPoints[this.state.snapPoints.length - 1])))
}), (this.props.onOpenStart || this.props.onCloseEnd) && React.createElement(Animated.Code, {
exec: onChange(this.translateMaster, [cond(and(lessOrEq(divide(this.translateMaster, this.state.snapPoints[this.state.snapPoints.length - 1]), 1 - (this.props.callbackThreshold ? this.props.callbackThreshold : 0.01)), neq(this.onOpenStartValue, 1)), [call([], () => {
if (this.props.onOpenStart) this.props.onOpenStart();
}), set(this.onOpenStartValue, 1), cond(defined(this.onCloseEndValue), set(this.onCloseEndValue, 0))])])
}), (this.props.onOpenEnd || this.props.onCloseStart) && React.createElement(Animated.Code, {
exec: onChange(this.translateMaster, [cond(and(lessOrEq(divide(this.translateMaster, this.state.snapPoints[this.state.snapPoints.length - 1]), this.props.callbackThreshold ? this.props.callbackThreshold : 0.01), neq(this.onOpenEndValue, 1)), [call([], () => {
if (this.props.onOpenEnd) this.props.onOpenEnd();
}), set(this.onOpenEndValue, 1), cond(defined(this.onCloseStartValue), set(this.onCloseStartValue, 0))])])
}), (this.props.onCloseStart || this.props.onOpenEnd) && React.createElement(Animated.Code, {
exec: onChange(this.translateMaster, [cond(and(greaterOrEq(divide(this.translateMaster, this.state.snapPoints[this.state.snapPoints.length - 1]), this.props.callbackThreshold ? this.props.callbackThreshold : 0.01), neq(this.onCloseStartValue, 1)), [call([], () => {
if (this.props.onCloseStart) this.props.onCloseStart();
}), set(this.onCloseStartValue, 1), cond(defined(this.onCloseStartValue), set(this.onOpenEndValue, 0))])])
}), (this.props.onCloseEnd || this.props.onOpenStart) && React.createElement(Animated.Code, {
exec: onChange(this.translateMaster, [cond(and(greaterOrEq(divide(this.translateMaster, this.state.snapPoints[this.state.snapPoints.length - 1]), 1 - (this.props.callbackThreshold ? this.props.callbackThreshold : 0.01)), neq(this.onCloseEndValue, 1)), [call([], () => {
if (this.props.onCloseEnd) this.props.onCloseEnd();
}), set(this.onCloseEndValue, 1), cond(defined(this.onOpenStartValue), set(this.onOpenStartValue, 0)), cond(defined(this.onOpenEndValue), set(this.onOpenEndValue, 0))])])
}), this.props.contentPosition && React.createElement(Animated.Code, {
exec: onChange(this.Y, set(this.props.contentPosition, sub(0, this.Y)))
}), this.props.headerPosition && React.createElement(Animated.Code, {
exec: onChange(this.translateMaster, set(this.props.headerPosition, this.translateMaster))
}))));
}
}
_defineProperty(BottomSheetBehavior, "defaultProps", {
overdragResistanceFactor: 0,
initialSnap: 0,
enabledImperativeSnapping: true,
enabledGestureInteraction: true,
enabledBottomClamp: false,
enabledBottomInitialAnimation: false,
enabledHeaderGestureInteraction: true,
enabledContentGestureInteraction: true,
enabledContentTapInteraction: true,
enabledInnerScrolling: true,
springConfig: {},
innerGestureHandlerRefs: [React.createRef(), React.createRef(), React.createRef()],
callbackThreshold: 0.01
});
_defineProperty(BottomSheetBehavior, "renumber", str => Number(str.split('%')[0]) * screenHeight / 100);
//# sourceMappingURL=index.js.map