[change] modernize Text

Rewrite Text to use function components and hooks.
This commit is contained in:
Nicolas Gallagher
2020-02-04 13:19:03 -08:00
parent 2724ca0293
commit 35236a3cc2
3 changed files with 68 additions and 63 deletions
+56 -52
View File
@@ -10,66 +10,45 @@
import type { TextProps } from './types'; import type { TextProps } from './types';
import applyLayout from '../../modules/applyLayout';
import applyNativeMethods from '../../modules/applyNativeMethods';
import createElement from '../createElement'; import createElement from '../createElement';
import css from '../StyleSheet/css'; import css from '../StyleSheet/css';
import filterSupportedProps from '../View/filterSupportedProps'; import filterSupportedProps from '../View/filterSupportedProps';
import React from 'react'; import setAndForwardRef from '../../modules/setAndForwardRef';
import useElementLayout from '../../hooks/useElementLayout';
import usePlatformMethods from '../../hooks/usePlatformMethods';
import React, { forwardRef, useContext, useRef } from 'react';
import StyleSheet from '../StyleSheet'; import StyleSheet from '../StyleSheet';
import TextAncestorContext from './TextAncestorContext'; import TextAncestorContext from './TextAncestorContext';
class Text extends React.Component<TextProps> { const Text = forwardRef<TextProps, *>((props, ref) => {
static displayName = 'Text'; const { dir, forwardedRef, numberOfLines, onLayout, onPress, selectable } = props;
renderText(hasTextAncestor) { const hasTextAncestor = useContext(TextAncestorContext);
const { dir, forwardedRef, numberOfLines, onPress, selectable, style } = this.props; const hostRef = useRef(null);
const setRef = setAndForwardRef({
const supportedProps = filterSupportedProps(this.props); getForwardedRef: () => forwardedRef,
setLocalRef: c => {
if (onPress) { hostRef.current = c;
supportedProps.accessible = true;
supportedProps.onClick = this._createPressHandler(onPress);
supportedProps.onKeyDown = this._createEnterHandler(onPress);
} }
});
supportedProps.classList = [ const classList = [
classes.text, classes.text,
hasTextAncestor === true && classes.textHasAncestor, hasTextAncestor === true && classes.textHasAncestor,
numberOfLines === 1 && classes.textOneLine, numberOfLines === 1 && classes.textOneLine,
numberOfLines != null && numberOfLines > 1 && classes.textMultiLine numberOfLines != null && numberOfLines > 1 && classes.textMultiLine
]; ];
// allow browsers to automatically infer the language writing direction const style = [
supportedProps.dir = dir !== undefined ? dir : 'auto'; props.style,
supportedProps.ref = forwardedRef; numberOfLines != null && numberOfLines > 1 && { WebkitLineClamp: numberOfLines },
supportedProps.style = [ selectable === false && styles.notSelectable,
style, onPress && styles.pressable
numberOfLines != null && numberOfLines > 1 && { WebkitLineClamp: numberOfLines }, ];
selectable === false && styles.notSelectable,
onPress && styles.pressable
];
const component = hasTextAncestor ? 'span' : 'div'; useElementLayout(hostRef, onLayout);
usePlatformMethods(hostRef, ref, classList, style);
return createElement(component, supportedProps); function createEnterHandler(fn) {
}
render() {
return (
<TextAncestorContext.Consumer>
{hasTextAncestor => {
const element = this.renderText(hasTextAncestor);
return hasTextAncestor ? (
element
) : (
<TextAncestorContext.Provider value={true}>{element}</TextAncestorContext.Provider>
);
}}
</TextAncestorContext.Consumer>
);
}
_createEnterHandler(fn) {
return e => { return e => {
if (e.keyCode === 13) { if (e.keyCode === 13) {
fn && fn(e); fn && fn(e);
@@ -77,13 +56,38 @@ class Text extends React.Component<TextProps> {
}; };
} }
_createPressHandler(fn) { function createPressHandler(fn) {
return e => { return e => {
e.stopPropagation(); e.stopPropagation();
fn && fn(e); fn && fn(e);
}; };
} }
}
const supportedProps = filterSupportedProps(props);
if (onPress) {
supportedProps.accessible = true;
supportedProps.onClick = createPressHandler(onPress);
supportedProps.onKeyDown = createEnterHandler(onPress);
}
supportedProps.classList = classList;
// allow browsers to automatically infer the language writing direction
supportedProps.dir = dir !== undefined ? dir : 'auto';
supportedProps.ref = setRef;
supportedProps.style = style;
const component = hasTextAncestor ? 'span' : 'div';
const element = createElement(component, supportedProps);
return hasTextAncestor ? (
element
) : (
<TextAncestorContext.Provider value={true}>{element}</TextAncestorContext.Provider>
);
});
Text.displayName = 'Text';
const classes = css.create({ const classes = css.create({
text: { text: {
@@ -127,4 +131,4 @@ const styles = StyleSheet.create({
} }
}); });
export default applyLayout(applyNativeMethods(Text)); export default Text;
+11 -10
View File
@@ -37,7 +37,7 @@ function createHitSlopElement(hitSlop) {
} }
const View = forwardRef<ViewProps, *>((props, ref) => { const View = forwardRef<ViewProps, *>((props, ref) => {
const { forwardedRef, hitSlop, onLayout, style, ...rest } = props; const { children, forwardedRef, hitSlop, onLayout } = props;
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
React.Children.toArray(props.children).forEach(item => { React.Children.toArray(props.children).forEach(item => {
@@ -47,10 +47,8 @@ const View = forwardRef<ViewProps, *>((props, ref) => {
}); });
} }
const classList = [classes.view];
const hasTextAncestor = useContext(TextAncestorContext); const hasTextAncestor = useContext(TextAncestorContext);
const hostRef = useRef(null); const hostRef = useRef(null);
const setRef = setAndForwardRef({ const setRef = setAndForwardRef({
getForwardedRef: () => forwardedRef, getForwardedRef: () => forwardedRef,
setLocalRef: c => { setLocalRef: c => {
@@ -58,19 +56,22 @@ const View = forwardRef<ViewProps, *>((props, ref) => {
} }
}); });
const classList = [classes.view];
const style = StyleSheet.compose(
hasTextAncestor && styles.inline,
props.style
);
useElementLayout(hostRef, onLayout); useElementLayout(hostRef, onLayout);
usePlatformMethods(hostRef, ref, classList, style); usePlatformMethods(hostRef, ref, classList, style);
const supportedProps = filterSupportedProps(rest); const supportedProps = filterSupportedProps(props);
supportedProps.children = hitSlop supportedProps.children = hitSlop
? React.Children.toArray([createHitSlopElement(hitSlop), props.children]) ? React.Children.toArray([createHitSlopElement(hitSlop), children])
: props.children; : children;
supportedProps.classList = classList; supportedProps.classList = classList;
supportedProps.ref = setRef; supportedProps.ref = setRef;
supportedProps.style = StyleSheet.compose( supportedProps.style = style;
hasTextAncestor && styles.inline,
style
);
return createElement('div', supportedProps); return createElement('div', supportedProps);
}); });
+1 -1
View File
@@ -17,7 +17,7 @@ import { useImperativeHandle, useRef } from 'react';
export default function usePlatformMethods( export default function usePlatformMethods(
hostRef: ElementRef<any>, hostRef: ElementRef<any>,
ref: ElementRef<any>, ref: ElementRef<any>,
classList: Array<string>, classList: Array<boolean | string>,
style: GenericStyleProp<any> style: GenericStyleProp<any>
) { ) {
const previousStyle = useRef(null); const previousStyle = useRef(null);