react-native-animateable-text
Version:
A fork of React Native's `<Text/> component that supports Reanimated Shared Values as text!
145 lines • 6.42 kB
JavaScript
import React from 'react';
import { forwardRef, useCallback, useMemo, useRef, useState } from "react";
import { processColor } from "react-native";
// @ts-ignore
import ReactNativeViewAttributes from "react-native/Libraries/Components/View/ReactNativeViewAttributes";
import Touchable from "react-native/Libraries/Components/Touchable/Touchable";
// @ts-ignore
import createReactNativeComponentClass from "react-native/Libraries/Renderer/shims/createReactNativeComponentClass";
import nullthrows from "nullthrows";
const PRESS_RECT_OFFSET = {
top: 20,
left: 20,
right: 20,
bottom: 30
};
const viewConfig = {
validAttributes: {
...ReactNativeViewAttributes.UIView,
isHighlighted: true,
isPressable: true,
numberOfLines: true,
ellipsizeMode: true,
allowFontScaling: true,
dynamicTypeRamp: true,
maxFontSizeMultiplier: true,
disabled: true,
selectable: true,
selectionColor: true,
adjustsFontSizeToFit: true,
minimumFontScale: true,
textBreakStrategy: true,
onTextLayout: true,
onInlineViewLayout: true,
dataDetectorType: true,
android_hyphenationFrequency: true,
lineBreakStrategyIOS: true,
text: true
},
directEventTypes: {
topTextLayout: {
registrationName: "onTextLayout"
},
topInlineViewLayout: {
registrationName: "onInlineViewLayout"
}
},
uiViewClassName: "JBAnimatedText"
};
const isTouchable = props => props.onPress != null || props.onLongPress != null || props.onStartShouldSetResponder != null;
const RCTText = createReactNativeComponentClass(viewConfig.uiViewClassName, () => viewConfig);
const TouchableText = /*#__PURE__*/forwardRef((props, forwardedRef) => {
const [isHighlighted, setHighlighted] = useState(false);
const touchableRef = useRef({});
const hasAttachedTouchHandlers = useRef(false);
const TouchableWithMixin = Touchable;
const attachTouchHandlers = useCallback(() => {
if (hasAttachedTouchHandlers.current) return;
hasAttachedTouchHandlers.current = true;
for (const key in TouchableWithMixin.Mixin) {
if (typeof TouchableWithMixin.Mixin[key] === "function") {
touchableRef.current[key] = TouchableWithMixin.Mixin[key].bind(touchableRef.current);
}
}
touchableRef.current.touchableHandleActivePressIn = () => {
if (!props.suppressHighlighting && isTouchable(props)) {
setHighlighted(true);
}
};
touchableRef.current.touchableHandleActivePressOut = () => {
if (!props.suppressHighlighting && isTouchable(props)) {
setHighlighted(false);
}
};
touchableRef.current.touchableHandlePress = event => {
var _props$onPress;
(_props$onPress = props.onPress) === null || _props$onPress === void 0 || _props$onPress.call(props, event);
};
touchableRef.current.touchableHandleLongPress = event => {
var _props$onLongPress;
(_props$onLongPress = props.onLongPress) === null || _props$onLongPress === void 0 || _props$onLongPress.call(props, event);
};
touchableRef.current.touchableGetPressRectOffset = () => props.pressRetentionOffset ?? PRESS_RECT_OFFSET;
}, [hasAttachedTouchHandlers, props, setHighlighted, touchableRef]);
const responseHandlers = useMemo(() => {
if (!isTouchable(props)) return undefined;
return {
onStartShouldSetResponder: () => {
var _props$onStartShouldS;
const shouldSet = (((_props$onStartShouldS = props.onStartShouldSetResponder) === null || _props$onStartShouldS === void 0 ? void 0 : _props$onStartShouldS.call(props)) ?? false) || isTouchable(props);
if (shouldSet) {
attachTouchHandlers();
}
return shouldSet;
},
onResponderGrant: event => {
var _nullthrows, _props$onResponderGra;
(_nullthrows = nullthrows(touchableRef.current.touchableHandleResponderGrant)) === null || _nullthrows === void 0 || _nullthrows(event);
(_props$onResponderGra = props.onResponderGrant) === null || _props$onResponderGra === void 0 || _props$onResponderGra.call(props, event);
},
onResponderMove: event => {
var _nullthrows2, _props$onResponderMov;
(_nullthrows2 = nullthrows(touchableRef.current.touchableHandleResponderMove)) === null || _nullthrows2 === void 0 || _nullthrows2(event);
(_props$onResponderMov = props.onResponderMove) === null || _props$onResponderMov === void 0 || _props$onResponderMov.call(props, event);
},
onResponderRelease: event => {
var _nullthrows3, _props$onResponderRel;
(_nullthrows3 = nullthrows(touchableRef.current.touchableHandleResponderRelease)) === null || _nullthrows3 === void 0 || _nullthrows3(event);
(_props$onResponderRel = props.onResponderRelease) === null || _props$onResponderRel === void 0 || _props$onResponderRel.call(props, event);
},
onResponderTerminate: event => {
var _nullthrows4, _props$onResponderTer;
(_nullthrows4 = nullthrows(touchableRef.current.touchableHandleResponderTerminate)) === null || _nullthrows4 === void 0 || _nullthrows4(event);
(_props$onResponderTer = props.onResponderTerminate) === null || _props$onResponderTer === void 0 || _props$onResponderTer.call(props, event);
},
onResponderTerminationRequest: () => {
var _props$onResponderTer2;
const defaultRequest = nullthrows(touchableRef.current.touchableHandleResponderTerminationRequest)();
return ((_props$onResponderTer2 = props.onResponderTerminationRequest) === null || _props$onResponderTer2 === void 0 ? void 0 : _props$onResponderTer2.call(props)) ?? defaultRequest;
}
};
}, [props, attachTouchHandlers]);
let selectionColor;
if (props.selectionColor != null) {
selectionColor = processColor(props.selectionColor);
}
const renderedProps = {
...props,
...(responseHandlers ?? {}),
ref: forwardedRef,
isHighlighted,
selectionColor
};
if (isTouchable(props)) {
renderedProps.isHighlighted = isHighlighted;
}
if (__DEV__ && TouchableWithMixin.TOUCH_TARGET_DEBUG && props.onPress != null) {
renderedProps.style = [props.style, {
color: "magenta"
}];
}
return /*#__PURE__*/React.createElement(RCTText, renderedProps);
});
TouchableText.displayName = "TouchableText";
export const AnimateableText = TouchableText;
//# sourceMappingURL=AnimateableText.js.mapleText.js.map