create-expo-cljs-app
Version:
Create a react native application with Expo and Shadow-CLJS!
160 lines (142 loc) • 3.91 kB
JavaScript
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
;
import type { Props as TouchableWithoutFeedbackProps } from '../TouchableWithoutFeedback';
import type { ViewProps } from '../View';
import * as React from 'react';
import { useCallback, useMemo, useState, useRef } from 'react';
import useMergeRefs from '../../modules/useMergeRefs';
import usePressEvents from '../../modules/usePressEvents';
import StyleSheet from '../StyleSheet';
import View from '../View';
type ViewStyle = $PropertyType<ViewProps, 'style'>;
type Props = $ReadOnly<{|
...TouchableWithoutFeedbackProps,
activeOpacity?: ?number,
style?: ?ViewStyle
|}>;
/**
* A wrapper for making views respond properly to touches.
* On press down, the opacity of the wrapped view is decreased, dimming it.
*/
function TouchableOpacity(props: Props, forwardedRef): React.Node {
const {
activeOpacity,
delayPressIn,
delayPressOut,
delayLongPress,
disabled,
focusable,
onLongPress,
onPress,
onPressIn,
onPressOut,
rejectResponderTermination,
style,
...rest
} = props;
const hostRef = useRef(null);
const setRef = useMergeRefs(forwardedRef, hostRef);
const [duration, setDuration] = useState('0s');
const [opacityOverride, setOpacityOverride] = useState(null);
const setOpacityTo = useCallback(
(value: ?number, duration: number) => {
setOpacityOverride(value);
setDuration(duration ? `${duration / 1000}s` : '0s');
},
[setOpacityOverride, setDuration]
);
const setOpacityActive = useCallback(
(duration: number) => {
setOpacityTo(activeOpacity ?? 0.2, duration);
},
[activeOpacity, setOpacityTo]
);
const setOpacityInactive = useCallback(
(duration: number) => {
setOpacityTo(null, duration);
},
[setOpacityTo]
);
const pressConfig = useMemo(
() => ({
cancelable: !rejectResponderTermination,
disabled,
delayLongPress,
delayPressStart: delayPressIn,
delayPressEnd: delayPressOut,
onLongPress,
onPress,
onPressStart(event) {
const isGrant =
event.dispatchConfig != null
? event.dispatchConfig.registrationName === 'onResponderGrant'
: event.type === 'keydown';
setOpacityActive(isGrant ? 0 : 150);
if (onPressIn != null) {
onPressIn(event);
}
},
onPressEnd(event) {
setOpacityInactive(250);
if (onPressOut != null) {
onPressOut(event);
}
}
}),
[
delayLongPress,
delayPressIn,
delayPressOut,
disabled,
onLongPress,
onPress,
onPressIn,
onPressOut,
rejectResponderTermination,
setOpacityActive,
setOpacityInactive
]
);
const pressEventHandlers = usePressEvents(hostRef, pressConfig);
return (
<View
{...rest}
{...pressEventHandlers}
accessibilityDisabled={disabled}
focusable={!disabled && focusable !== false}
ref={setRef}
style={[
styles.root,
!disabled && styles.actionable,
style,
opacityOverride != null && { opacity: opacityOverride },
{ transitionDuration: duration }
]}
/>
);
}
const styles = StyleSheet.create({
root: {
transitionProperty: 'opacity',
transitionDuration: '0.15s',
userSelect: 'none'
},
actionable: {
cursor: 'pointer',
touchAction: 'manipulation'
}
});
const MemoedTouchableOpacity = React.memo(React.forwardRef(TouchableOpacity));
MemoedTouchableOpacity.displayName = 'TouchableOpacity';
export default (MemoedTouchableOpacity: React.AbstractComponent<
Props,
React.ElementRef<typeof View>
>);