mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-21 05:55:48 +00:00
[change] Explicitly forward props and introduce unstable_{ariaSet,dataSet}
Rather than filtering props, they are explicitly forwarded in each component. This makes it easier to see exactly which props are being forwarded to host components by each React Native component. Two new props - `unstable_ariaSet` and `unstable_dataSet` - are introduced to avoid iterating over props to find `aria` and `data` props. The `accessibilityValue` prop is also implemented.
This commit is contained in:
@@ -3,12 +3,12 @@ import PropTypes, { any, bool, func, object, oneOf, string } from 'prop-types';
|
||||
const ofProps = () => {};
|
||||
|
||||
ofProps.propTypes = {
|
||||
/* test */
|
||||
accessibilityLabel: PropTypes.string,
|
||||
accessibilityLiveRegion: oneOf(['assertive', 'none', 'polite']),
|
||||
accessibilityRelationship: object,
|
||||
accessibilityRole: string,
|
||||
accessibilityState: object,
|
||||
accessibilityValue: object,
|
||||
accessible: bool,
|
||||
children: any,
|
||||
forwardedRef: any,
|
||||
|
||||
@@ -89,6 +89,10 @@ assistive technologies of a `role` value change.
|
||||
|
||||
...
|
||||
|
||||
### accessibilityValue: ?object
|
||||
|
||||
...
|
||||
|
||||
### accessible
|
||||
|
||||
When `true`, indicates that the view is an accessibility element. When a view
|
||||
|
||||
@@ -14,6 +14,8 @@ import StyleSheet from '../StyleSheet';
|
||||
import View from '../View';
|
||||
import React, { forwardRef } from 'react';
|
||||
|
||||
const accessibilityValue = { max: 1, min: 0 };
|
||||
|
||||
const createSvgCircle = style => (
|
||||
<circle cx="16" cy="16" fill="none" r="14" strokeWidth="4" style={style} />
|
||||
);
|
||||
@@ -54,8 +56,7 @@ const ActivityIndicator = forwardRef<ActivityIndicatorProps, *>((props, ref) =>
|
||||
<View
|
||||
{...other}
|
||||
accessibilityRole="progressbar"
|
||||
aria-valuemax="1"
|
||||
aria-valuemin="0"
|
||||
accessibilityValue={accessibilityValue}
|
||||
ref={ref}
|
||||
style={[styles.container, style]}
|
||||
>
|
||||
|
||||
@@ -48,9 +48,11 @@ const ProgressBar = forwardRef<ProgressBarProps, *>((props, ref) => {
|
||||
<View
|
||||
{...other}
|
||||
accessibilityRole="progressbar"
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={indeterminate ? null : percentageProgress}
|
||||
accessibilityValue={{
|
||||
max: 100,
|
||||
min: 0,
|
||||
now: indeterminate ? null : percentageProgress
|
||||
}}
|
||||
ref={ref}
|
||||
style={[styles.track, style, { backgroundColor: trackColor }]}
|
||||
>
|
||||
|
||||
+128
-17
@@ -12,7 +12,6 @@ import type { TextProps } from './types';
|
||||
|
||||
import createElement from '../createElement';
|
||||
import css from '../StyleSheet/css';
|
||||
import filterSupportedProps from '../View/filterSupportedProps';
|
||||
import setAndForwardRef from '../../modules/setAndForwardRef';
|
||||
import useElementLayout from '../../hooks/useElementLayout';
|
||||
import usePlatformMethods from '../../hooks/usePlatformMethods';
|
||||
@@ -21,7 +20,69 @@ import StyleSheet from '../StyleSheet';
|
||||
import TextAncestorContext from './TextAncestorContext';
|
||||
|
||||
const Text = forwardRef<TextProps, *>((props, ref) => {
|
||||
const { dir, forwardedRef, numberOfLines, onLayout, onPress, selectable } = props;
|
||||
const {
|
||||
accessibilityLabel,
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRelationship,
|
||||
accessibilityRole,
|
||||
accessibilityState,
|
||||
children,
|
||||
dir,
|
||||
forwardedRef,
|
||||
importantForAccessibility,
|
||||
lang,
|
||||
nativeID,
|
||||
numberOfLines,
|
||||
onBlur,
|
||||
onContextMenu,
|
||||
onFocus,
|
||||
onLayout,
|
||||
onPress,
|
||||
onMoveShouldSetResponder,
|
||||
onMoveShouldSetResponderCapture,
|
||||
onResponderEnd,
|
||||
onResponderGrant,
|
||||
onResponderMove,
|
||||
onResponderReject,
|
||||
onResponderRelease,
|
||||
onResponderStart,
|
||||
onResponderTerminate,
|
||||
onResponderTerminationRequest,
|
||||
onScrollShouldSetResponder,
|
||||
onScrollShouldSetResponderCapture,
|
||||
onSelectionChangeShouldSetResponder,
|
||||
onSelectionChangeShouldSetResponderCapture,
|
||||
onStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture,
|
||||
selectable,
|
||||
testID,
|
||||
// unstable
|
||||
onMouseDown,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
onMouseMove,
|
||||
onMouseOver,
|
||||
onMouseOut,
|
||||
onMouseUp,
|
||||
onTouchCancel,
|
||||
onTouchCancelCapture,
|
||||
onTouchEnd,
|
||||
onTouchEndCapture,
|
||||
onTouchMove,
|
||||
onTouchMoveCapture,
|
||||
onTouchStart,
|
||||
onTouchStartCapture,
|
||||
href,
|
||||
itemID,
|
||||
itemRef,
|
||||
itemProp,
|
||||
itemScope,
|
||||
itemType,
|
||||
rel,
|
||||
target,
|
||||
unstable_ariaSet,
|
||||
unstable_dataSet
|
||||
} = props;
|
||||
|
||||
const hasTextAncestor = useContext(TextAncestorContext);
|
||||
const hostRef = useRef(null);
|
||||
@@ -63,22 +124,72 @@ const Text = forwardRef<TextProps, *>((props, ref) => {
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
const element = createElement(component, {
|
||||
accessibilityLabel,
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRelationship,
|
||||
accessibilityRole,
|
||||
accessibilityState,
|
||||
accessible: onPress != null ? true : null,
|
||||
children,
|
||||
classList,
|
||||
// allow browsers to automatically infer the language writing direction
|
||||
dir: dir !== undefined ? dir : 'auto',
|
||||
importantForAccessibility,
|
||||
lang,
|
||||
nativeID,
|
||||
onBlur,
|
||||
onFocus,
|
||||
onMoveShouldSetResponder,
|
||||
onMoveShouldSetResponderCapture,
|
||||
onResponderEnd,
|
||||
onResponderGrant,
|
||||
onResponderMove,
|
||||
onResponderReject,
|
||||
onResponderRelease,
|
||||
onResponderStart,
|
||||
onResponderTerminate,
|
||||
onResponderTerminationRequest,
|
||||
onScrollShouldSetResponder,
|
||||
onScrollShouldSetResponderCapture,
|
||||
onSelectionChangeShouldSetResponder,
|
||||
onSelectionChangeShouldSetResponderCapture,
|
||||
onStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture,
|
||||
ref: setRef,
|
||||
style,
|
||||
testID,
|
||||
// unstable
|
||||
onClick: onPress != null ? createPressHandler(onPress) : null,
|
||||
onContextMenu,
|
||||
onKeyDown: onPress != null ? createEnterHandler(onPress) : null,
|
||||
onMouseDown,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
onMouseMove,
|
||||
onMouseOver,
|
||||
onMouseOut,
|
||||
onMouseUp,
|
||||
onTouchCancel,
|
||||
onTouchCancelCapture,
|
||||
onTouchEnd,
|
||||
onTouchEndCapture,
|
||||
onTouchMove,
|
||||
onTouchMoveCapture,
|
||||
onTouchStart,
|
||||
onTouchStartCapture,
|
||||
href,
|
||||
itemID,
|
||||
itemRef,
|
||||
itemProp,
|
||||
itemScope,
|
||||
itemType,
|
||||
rel,
|
||||
target,
|
||||
unstable_ariaSet,
|
||||
unstable_dataSet
|
||||
});
|
||||
|
||||
return hasTextAncestor ? (
|
||||
element
|
||||
|
||||
+41
-2
@@ -104,14 +104,53 @@ export type TextProps = {
|
||||
onFocus?: (e: any) => void,
|
||||
onLayout?: (e: LayoutEvent) => void,
|
||||
onPress?: (e: any) => void,
|
||||
onMoveShouldSetResponder?: (e: any) => boolean,
|
||||
onMoveShouldSetResponderCapture?: (e: any) => boolean,
|
||||
onResponderEnd?: (e: any) => void,
|
||||
onResponderGrant?: (e: any) => void,
|
||||
onResponderMove?: (e: any) => void,
|
||||
onResponderReject?: (e: any) => void,
|
||||
onResponderRelease?: (e: any) => void,
|
||||
onResponderStart?: (e: any) => void,
|
||||
onResponderTerminate?: (e: any) => void,
|
||||
onResponderTerminationRequest?: (e: any) => void,
|
||||
onScrollShouldSetResponder?: (e: any) => boolean,
|
||||
onScrollShouldSetResponderCapture?: (e: any) => boolean,
|
||||
onSelectionChangeShouldSetResponder?: (e: any) => boolean,
|
||||
onSelectionChangeShouldSetResponderCapture?: (e: any) => boolean,
|
||||
onStartShouldSetResponder?: (e: any) => boolean,
|
||||
onStartShouldSetResponderCapture?: (e: any) => boolean,
|
||||
selectable?: boolean,
|
||||
style?: GenericStyleProp<TextStyle>,
|
||||
testID?: string,
|
||||
// web extensions
|
||||
// unstable
|
||||
onContextMenu?: (e: any) => void,
|
||||
onKeyDown?: (e: any) => void,
|
||||
onKeyPress?: (e: any) => void,
|
||||
onKeyUp?: (e: any) => void,
|
||||
onMouseDown?: (e: any) => void,
|
||||
onMouseEnter?: (e: any) => void,
|
||||
onMouseLeave?: (e: any) => void,
|
||||
onMouseMove?: (e: any) => void,
|
||||
onMouseOver?: (e: any) => void,
|
||||
onMouseOut?: (e: any) => void,
|
||||
onMouseUp?: (e: any) => void,
|
||||
onTouchCancel?: (e: any) => void,
|
||||
onTouchCancelCapture?: (e: any) => void,
|
||||
onTouchEnd?: (e: any) => void,
|
||||
onTouchEndCapture?: (e: any) => void,
|
||||
onTouchMove?: (e: any) => void,
|
||||
onTouchMoveCapture?: (e: any) => void,
|
||||
onTouchStart?: (e: any) => void,
|
||||
onTouchStartCapture?: (e: any) => void,
|
||||
href?: string,
|
||||
itemID?: string,
|
||||
itemRef?: string,
|
||||
itemProp?: string,
|
||||
itemScope?: string,
|
||||
itemType?: string
|
||||
itemType?: string,
|
||||
rel?: string,
|
||||
target?: string,
|
||||
unstable_ariaSet?: Object,
|
||||
unstable_dataSet?: Object
|
||||
};
|
||||
|
||||
+84
-32
@@ -12,11 +12,11 @@ import type { TextInputProps } from './types';
|
||||
|
||||
import createElement from '../createElement';
|
||||
import css from '../StyleSheet/css';
|
||||
import filterSupportedProps from '../View/filterSupportedProps';
|
||||
import setAndForwardRef from '../../modules/setAndForwardRef';
|
||||
import useElementLayout from '../../hooks/useElementLayout';
|
||||
import usePlatformMethods from '../../hooks/usePlatformMethods';
|
||||
import { forwardRef, useEffect, useRef } from 'react';
|
||||
import useLayoutEffect from '../../hooks/useLayoutEffect';
|
||||
import { usePlatformInputMethods } from '../../hooks/usePlatformMethods';
|
||||
import { forwardRef, useRef } from 'react';
|
||||
import StyleSheet from '../StyleSheet';
|
||||
import TextInputState from '../../modules/TextInputState';
|
||||
|
||||
@@ -50,6 +50,9 @@ const setSelection = (node, selection) => {
|
||||
|
||||
const TextInput = forwardRef<TextInputProps, *>((props, ref) => {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
accessibilityRelationship,
|
||||
accessibilityState,
|
||||
autoCapitalize = 'sentences',
|
||||
autoComplete,
|
||||
autoCompleteType,
|
||||
@@ -60,27 +63,58 @@ const TextInput = forwardRef<TextInputProps, *>((props, ref) => {
|
||||
defaultValue,
|
||||
disabled,
|
||||
editable = true,
|
||||
forwardedRef,
|
||||
importantForAccessibility,
|
||||
keyboardType = 'default',
|
||||
maxLength,
|
||||
multiline = false,
|
||||
nativeID,
|
||||
numberOfLines = 1,
|
||||
onBlur,
|
||||
onChange,
|
||||
onChangeText,
|
||||
onContentSizeChange,
|
||||
onContextMenu,
|
||||
onFocus,
|
||||
onKeyPress,
|
||||
onLayout,
|
||||
onScroll,
|
||||
onSelectionChange,
|
||||
onSubmitEditing,
|
||||
onMoveShouldSetResponder,
|
||||
onMoveShouldSetResponderCapture,
|
||||
onResponderEnd,
|
||||
onResponderGrant,
|
||||
onResponderMove,
|
||||
onResponderReject,
|
||||
onResponderRelease,
|
||||
onResponderStart,
|
||||
onResponderTerminate,
|
||||
onResponderTerminationRequest,
|
||||
onScrollShouldSetResponder,
|
||||
onScrollShouldSetResponderCapture,
|
||||
onSelectionChangeShouldSetResponder,
|
||||
onSelectionChangeShouldSetResponderCapture,
|
||||
onStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture,
|
||||
placeholder,
|
||||
placeholderTextColor,
|
||||
pointerEvents,
|
||||
returnKeyType,
|
||||
secureTextEntry = false,
|
||||
selection = emptyObject,
|
||||
selectTextOnFocus,
|
||||
spellCheck,
|
||||
value
|
||||
testID,
|
||||
value,
|
||||
// unstable
|
||||
itemID,
|
||||
itemRef,
|
||||
itemProp,
|
||||
itemScope,
|
||||
itemType,
|
||||
unstable_ariaSet,
|
||||
unstable_dataSet
|
||||
} = props;
|
||||
|
||||
let type;
|
||||
@@ -114,7 +148,7 @@ const TextInput = forwardRef<TextInputProps, *>((props, ref) => {
|
||||
const hostRef = useRef(null);
|
||||
const dimensions = useRef({ height: null, width: null });
|
||||
const setRef = setAndForwardRef({
|
||||
getForwardedRef: () => ref,
|
||||
getForwardedRef: () => forwardedRef,
|
||||
setLocalRef: c => {
|
||||
hostRef.current = c;
|
||||
if (hostRef.current != null) {
|
||||
@@ -124,7 +158,6 @@ const TextInput = forwardRef<TextInputProps, *>((props, ref) => {
|
||||
});
|
||||
|
||||
const component = multiline ? 'textarea' : 'input';
|
||||
const supportedProps = filterSupportedProps(props);
|
||||
const classList = [classes.textinput];
|
||||
const style = StyleSheet.compose(
|
||||
props.style,
|
||||
@@ -160,7 +193,7 @@ const TextInput = forwardRef<TextInputProps, *>((props, ref) => {
|
||||
}
|
||||
|
||||
function handleChange(e) {
|
||||
const { text } = e.nativeEvent;
|
||||
const text = e.target.value;
|
||||
e.nativeEvent.text = text;
|
||||
handleContentSizeChange();
|
||||
if (onChange) {
|
||||
@@ -219,7 +252,7 @@ const TextInput = forwardRef<TextInputProps, *>((props, ref) => {
|
||||
e.nativeEvent = { target: e.target, text: e.target.value };
|
||||
onSubmitEditing(e);
|
||||
}
|
||||
if (shouldBlurOnSubmit) {
|
||||
if (shouldBlurOnSubmit && hostRef.current != null) {
|
||||
// $FlowFixMe
|
||||
hostRef.current.blur();
|
||||
}
|
||||
@@ -243,26 +276,21 @@ const TextInput = forwardRef<TextInputProps, *>((props, ref) => {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setSelection(hostRef.current, selection);
|
||||
if (document.activeElement === hostRef.current) {
|
||||
TextInputState._currentlyFocusedNode = hostRef.current;
|
||||
useLayoutEffect(() => {
|
||||
const node = hostRef.current;
|
||||
setSelection(node, selection);
|
||||
if (document.activeElement === node) {
|
||||
TextInputState._currentlyFocusedNode = node;
|
||||
}
|
||||
}, [hostRef, selection]);
|
||||
|
||||
useElementLayout(hostRef, onLayout);
|
||||
usePlatformMethods(hostRef, ref, classList, style, {
|
||||
clear() {
|
||||
if (hostRef.current != null) {
|
||||
hostRef.current.value = '';
|
||||
}
|
||||
},
|
||||
isFocused() {
|
||||
return hostRef.current != null && TextInputState.currentlyFocusedField() === hostRef.current;
|
||||
}
|
||||
});
|
||||
usePlatformInputMethods(hostRef, ref, classList, style);
|
||||
|
||||
Object.assign(supportedProps, {
|
||||
return createElement(component, {
|
||||
accessibilityLabel,
|
||||
accessibilityRelationship,
|
||||
accessibilityState,
|
||||
autoCapitalize,
|
||||
autoComplete: autoComplete || autoCompleteType || 'on',
|
||||
autoCorrect: autoCorrect ? 'on' : 'off',
|
||||
@@ -272,27 +300,51 @@ const TextInput = forwardRef<TextInputProps, *>((props, ref) => {
|
||||
dir: 'auto',
|
||||
disabled,
|
||||
enterkeyhint: returnKeyType,
|
||||
importantForAccessibility,
|
||||
maxLength,
|
||||
nativeID,
|
||||
onBlur: handleBlur,
|
||||
onChange: handleChange,
|
||||
onContextMenu,
|
||||
onFocus: handleFocus,
|
||||
onKeyDown: handleKeyDown,
|
||||
onScroll,
|
||||
onSelect: handleSelectionChange,
|
||||
onMoveShouldSetResponder,
|
||||
onMoveShouldSetResponderCapture,
|
||||
onResponderEnd,
|
||||
onResponderGrant,
|
||||
onResponderMove,
|
||||
onResponderReject,
|
||||
onResponderRelease,
|
||||
onResponderStart,
|
||||
onResponderTerminate,
|
||||
onResponderTerminationRequest,
|
||||
onScrollShouldSetResponder,
|
||||
onScrollShouldSetResponderCapture,
|
||||
onSelectionChangeShouldSetResponder,
|
||||
onSelectionChangeShouldSetResponderCapture,
|
||||
onStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture,
|
||||
placeholder,
|
||||
pointerEvents,
|
||||
testID,
|
||||
readOnly: !editable,
|
||||
ref: setRef,
|
||||
rows: multiline ? numberOfLines : undefined,
|
||||
spellCheck: spellCheck != null ? spellCheck : autoCorrect,
|
||||
style,
|
||||
value
|
||||
type: multiline ? undefined : type,
|
||||
value,
|
||||
// unstable
|
||||
itemID,
|
||||
itemRef,
|
||||
itemProp,
|
||||
itemScope,
|
||||
itemType,
|
||||
unstable_ariaSet,
|
||||
unstable_dataSet
|
||||
});
|
||||
|
||||
if (multiline) {
|
||||
supportedProps.rows = numberOfLines;
|
||||
} else {
|
||||
supportedProps.type = type;
|
||||
}
|
||||
|
||||
return createElement(component, supportedProps);
|
||||
});
|
||||
|
||||
TextInput.displayName = 'TextInput';
|
||||
|
||||
@@ -291,7 +291,10 @@ const TouchableHighlight = ((createReactClass({
|
||||
accessibilityHint={this.props.accessibilityHint}
|
||||
accessibilityLabel={this.props.accessibilityLabel}
|
||||
accessibilityRole={this.props.accessibilityRole}
|
||||
accessibilityState={this.props.accessibilityState}
|
||||
accessibilityState={{
|
||||
disabled: this.props.disabled,
|
||||
...this.props.accessibilityState
|
||||
}}
|
||||
accessible={this.props.accessible !== false}
|
||||
hitSlop={this.props.hitSlop}
|
||||
nativeID={this.props.nativeID}
|
||||
|
||||
@@ -246,7 +246,10 @@ const TouchableOpacity = ((createReactClass({
|
||||
accessibilityHint={this.props.accessibilityHint}
|
||||
accessibilityLabel={this.props.accessibilityLabel}
|
||||
accessibilityRole={this.props.accessibilityRole}
|
||||
accessibilityState={this.props.accessibilityState}
|
||||
accessibilityState={{
|
||||
disabled: this.props.disabled,
|
||||
...this.props.accessibilityState
|
||||
}}
|
||||
accessible={this.props.accessible !== false}
|
||||
hitSlop={this.props.hitSlop}
|
||||
nativeID={this.props.nativeID}
|
||||
|
||||
@@ -148,6 +148,11 @@ const TouchableWithoutFeedback = ((createReactClass({
|
||||
}
|
||||
}
|
||||
|
||||
overrides.accessibilityState = {
|
||||
disabled: this.props.disabled,
|
||||
...this.props.accessibilityState
|
||||
};
|
||||
|
||||
return (React: any).cloneElement(child, {
|
||||
...overrides,
|
||||
accessible: this.props.accessible !== false,
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Nicolas Gallagher.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
const supportedProps = {
|
||||
accessibilityLabel: true,
|
||||
accessibilityLiveRegion: true,
|
||||
accessibilityRelationship: true,
|
||||
accessibilityRole: true,
|
||||
accessibilityState: true,
|
||||
accessible: true,
|
||||
children: true,
|
||||
disabled: true,
|
||||
importantForAccessibility: true,
|
||||
nativeID: true,
|
||||
onBlur: true,
|
||||
onContextMenu: true,
|
||||
onFocus: true,
|
||||
onMoveShouldSetResponder: true,
|
||||
onMoveShouldSetResponderCapture: true,
|
||||
onResponderEnd: true,
|
||||
onResponderGrant: true,
|
||||
onResponderMove: true,
|
||||
onResponderReject: true,
|
||||
onResponderRelease: true,
|
||||
onResponderStart: true,
|
||||
onResponderTerminate: true,
|
||||
onResponderTerminationRequest: true,
|
||||
onScrollShouldSetResponder: true,
|
||||
onScrollShouldSetResponderCapture: true,
|
||||
onSelectionChangeShouldSetResponder: true,
|
||||
onSelectionChangeShouldSetResponderCapture: true,
|
||||
onStartShouldSetResponder: true,
|
||||
onStartShouldSetResponderCapture: true,
|
||||
onTouchCancel: true,
|
||||
onTouchCancelCapture: true,
|
||||
onTouchEnd: true,
|
||||
onTouchEndCapture: true,
|
||||
onTouchMove: true,
|
||||
onTouchMoveCapture: true,
|
||||
onTouchStart: true,
|
||||
onTouchStartCapture: true,
|
||||
pointerEvents: true,
|
||||
style: true,
|
||||
testID: true,
|
||||
/* @platform web */
|
||||
lang: true,
|
||||
onScroll: true,
|
||||
onWheel: true,
|
||||
// keyboard events
|
||||
onKeyDown: true,
|
||||
onKeyPress: true,
|
||||
onKeyUp: true,
|
||||
// mouse events (e.g, hover effects)
|
||||
onMouseDown: true,
|
||||
onMouseEnter: true,
|
||||
onMouseLeave: true,
|
||||
onMouseMove: true,
|
||||
onMouseOver: true,
|
||||
onMouseOut: true,
|
||||
onMouseUp: true,
|
||||
// unstable escape-hatches for web
|
||||
href: true,
|
||||
itemID: true,
|
||||
itemRef: true,
|
||||
itemProp: true,
|
||||
itemScope: true,
|
||||
itemType: true,
|
||||
onClick: true,
|
||||
onClickCapture: true,
|
||||
rel: true,
|
||||
target: true
|
||||
};
|
||||
|
||||
const filterSupportedProps = props => {
|
||||
const safeProps = {};
|
||||
for (const prop in props) {
|
||||
if (props.hasOwnProperty(prop)) {
|
||||
if (supportedProps[prop] || prop.indexOf('aria-') === 0 || prop.indexOf('data-') === 0) {
|
||||
safeProps[prop] = props[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
return safeProps;
|
||||
};
|
||||
|
||||
export default filterSupportedProps;
|
||||
+138
-11
@@ -12,7 +12,6 @@ import type { ViewProps } from './types';
|
||||
|
||||
import createElement from '../createElement';
|
||||
import css from '../StyleSheet/css';
|
||||
import filterSupportedProps from './filterSupportedProps';
|
||||
import setAndForwardRef from '../../modules/setAndForwardRef';
|
||||
import useElementLayout from '../../hooks/useElementLayout';
|
||||
import usePlatformMethods from '../../hooks/usePlatformMethods';
|
||||
@@ -37,7 +36,73 @@ function createHitSlopElement(hitSlop) {
|
||||
}
|
||||
|
||||
const View = forwardRef<ViewProps, *>((props, ref) => {
|
||||
const { children, forwardedRef, hitSlop, onLayout } = props;
|
||||
const {
|
||||
accessibilityLabel,
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRelationship,
|
||||
accessibilityRole,
|
||||
accessibilityState,
|
||||
accessibilityValue,
|
||||
forwardedRef,
|
||||
hitSlop,
|
||||
importantForAccessibility,
|
||||
nativeID,
|
||||
onBlur,
|
||||
onContextMenu,
|
||||
onFocus,
|
||||
onLayout,
|
||||
onMoveShouldSetResponder,
|
||||
onMoveShouldSetResponderCapture,
|
||||
onResponderEnd,
|
||||
onResponderGrant,
|
||||
onResponderMove,
|
||||
onResponderReject,
|
||||
onResponderRelease,
|
||||
onResponderStart,
|
||||
onResponderTerminate,
|
||||
onResponderTerminationRequest,
|
||||
onScrollShouldSetResponder,
|
||||
onScrollShouldSetResponderCapture,
|
||||
onSelectionChangeShouldSetResponder,
|
||||
onSelectionChangeShouldSetResponderCapture,
|
||||
onStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture,
|
||||
pointerEvents,
|
||||
testID,
|
||||
// unstable
|
||||
onClick,
|
||||
onClickCapture,
|
||||
onScroll,
|
||||
onWheel,
|
||||
onKeyDown,
|
||||
onKeyPress,
|
||||
onKeyUp,
|
||||
onMouseDown,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
onMouseMove,
|
||||
onMouseOver,
|
||||
onMouseOut,
|
||||
onMouseUp,
|
||||
onTouchCancel,
|
||||
onTouchCancelCapture,
|
||||
onTouchEnd,
|
||||
onTouchEndCapture,
|
||||
onTouchMove,
|
||||
onTouchMoveCapture,
|
||||
onTouchStart,
|
||||
onTouchStartCapture,
|
||||
href,
|
||||
itemID,
|
||||
itemRef,
|
||||
itemProp,
|
||||
itemScope,
|
||||
itemType,
|
||||
rel,
|
||||
target,
|
||||
unstable_ariaSet,
|
||||
unstable_dataSet
|
||||
} = props;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
React.Children.toArray(props.children).forEach(item => {
|
||||
@@ -56,6 +121,9 @@ const View = forwardRef<ViewProps, *>((props, ref) => {
|
||||
}
|
||||
});
|
||||
|
||||
const children = hitSlop
|
||||
? React.Children.toArray([createHitSlopElement(hitSlop), props.children])
|
||||
: props.children;
|
||||
const classList = [classes.view];
|
||||
const style = StyleSheet.compose(
|
||||
hasTextAncestor && styles.inline,
|
||||
@@ -65,15 +133,74 @@ const View = forwardRef<ViewProps, *>((props, ref) => {
|
||||
useElementLayout(hostRef, onLayout);
|
||||
usePlatformMethods(hostRef, ref, classList, style);
|
||||
|
||||
const supportedProps = filterSupportedProps(props);
|
||||
supportedProps.children = hitSlop
|
||||
? React.Children.toArray([createHitSlopElement(hitSlop), children])
|
||||
: children;
|
||||
supportedProps.classList = classList;
|
||||
supportedProps.ref = setRef;
|
||||
supportedProps.style = style;
|
||||
|
||||
return createElement('div', supportedProps);
|
||||
return createElement('div', {
|
||||
accessibilityLabel,
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRelationship,
|
||||
accessibilityRole,
|
||||
accessibilityState,
|
||||
accessibilityValue,
|
||||
children,
|
||||
classList,
|
||||
importantForAccessibility,
|
||||
nativeID,
|
||||
onBlur,
|
||||
onContextMenu,
|
||||
onFocus,
|
||||
onMoveShouldSetResponder,
|
||||
onMoveShouldSetResponderCapture,
|
||||
onResponderEnd,
|
||||
onResponderGrant,
|
||||
onResponderMove,
|
||||
onResponderReject,
|
||||
onResponderRelease,
|
||||
onResponderStart,
|
||||
onResponderTerminate,
|
||||
onResponderTerminationRequest,
|
||||
onScrollShouldSetResponder,
|
||||
onScrollShouldSetResponderCapture,
|
||||
onSelectionChangeShouldSetResponder,
|
||||
onSelectionChangeShouldSetResponderCapture,
|
||||
onStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture,
|
||||
pointerEvents,
|
||||
ref: setRef,
|
||||
style,
|
||||
testID,
|
||||
// unstable
|
||||
onClick,
|
||||
onClickCapture,
|
||||
onScroll,
|
||||
onWheel,
|
||||
onKeyDown,
|
||||
onKeyPress,
|
||||
onKeyUp,
|
||||
onMouseDown,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
onMouseMove,
|
||||
onMouseOver,
|
||||
onMouseOut,
|
||||
onMouseUp,
|
||||
onTouchCancel,
|
||||
onTouchCancelCapture,
|
||||
onTouchEnd,
|
||||
onTouchEndCapture,
|
||||
onTouchMove,
|
||||
onTouchMoveCapture,
|
||||
onTouchStart,
|
||||
onTouchStartCapture,
|
||||
href,
|
||||
itemID,
|
||||
itemRef,
|
||||
itemProp,
|
||||
itemScope,
|
||||
itemType,
|
||||
rel,
|
||||
target,
|
||||
unstable_ariaSet,
|
||||
unstable_dataSet
|
||||
});
|
||||
});
|
||||
|
||||
View.displayName = 'View';
|
||||
|
||||
+39
-10
@@ -83,6 +83,12 @@ export type ViewProps = {
|
||||
required?: ?boolean,
|
||||
selected?: ?boolean
|
||||
},
|
||||
accessibilityValue?: {
|
||||
max?: ?number,
|
||||
min?: ?number,
|
||||
now?: ?number,
|
||||
text?: ?string
|
||||
},
|
||||
accessible?: boolean,
|
||||
children?: any,
|
||||
forwardedRef?: any,
|
||||
@@ -90,20 +96,43 @@ export type ViewProps = {
|
||||
importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants',
|
||||
nativeID?: string,
|
||||
onBlur?: (e: any) => void,
|
||||
onClick?: (e: any) => void,
|
||||
onClickCapture?: (e: any) => void,
|
||||
onFocus?: (e: any) => void,
|
||||
onLayout?: (e: LayoutEvent) => void,
|
||||
onMoveShouldSetResponder?: (e: any) => boolean,
|
||||
onMoveShouldSetResponderCapture?: (e: any) => boolean,
|
||||
onResponderEnd?: (e: any) => void,
|
||||
onResponderGrant?: (e: any) => void,
|
||||
onResponderMove?: (e: any) => void,
|
||||
onResponderReject?: (e: any) => void,
|
||||
onResponderRelease?: (e: any) => void,
|
||||
onResponderStart?: (e: any) => void,
|
||||
onResponderTerminate?: (e: any) => void,
|
||||
onResponderTerminationRequest?: (e: any) => void,
|
||||
onScrollShouldSetResponder?: (e: any) => boolean,
|
||||
onScrollShouldSetResponderCapture?: (e: any) => boolean,
|
||||
onSelectionChangeShouldSetResponder?: (e: any) => boolean,
|
||||
onSelectionChangeShouldSetResponderCapture?: (e: any) => boolean,
|
||||
onStartShouldSetResponder?: (e: any) => boolean,
|
||||
onStartShouldSetResponderCapture?: (e: any) => boolean,
|
||||
onMoveShouldSetResponder?: (e: any) => boolean,
|
||||
onMoveShouldSetResponderCapture?: (e: any) => boolean,
|
||||
pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto',
|
||||
style?: GenericStyleProp<ViewStyle>,
|
||||
testID?: string,
|
||||
// unstable
|
||||
onClick?: (e: any) => void,
|
||||
onClickCapture?: (e: any) => void,
|
||||
onContextMenu?: (e: any) => void,
|
||||
onScroll?: (e: any) => void,
|
||||
onWheel?: (e: any) => void,
|
||||
onKeyDown?: (e: any) => void,
|
||||
onKeyPress?: (e: any) => void,
|
||||
onKeyUp?: (e: any) => void,
|
||||
onMouseDown?: (e: any) => void,
|
||||
onMouseEnter?: (e: any) => void,
|
||||
onMouseLeave?: (e: any) => void,
|
||||
onMouseMove?: (e: any) => void,
|
||||
onMouseOver?: (e: any) => void,
|
||||
onMouseOut?: (e: any) => void,
|
||||
onMouseUp?: (e: any) => void,
|
||||
onTouchCancel?: (e: any) => void,
|
||||
onTouchCancelCapture?: (e: any) => void,
|
||||
onTouchEnd?: (e: any) => void,
|
||||
@@ -112,14 +141,14 @@ export type ViewProps = {
|
||||
onTouchMoveCapture?: (e: any) => void,
|
||||
onTouchStart?: (e: any) => void,
|
||||
onTouchStartCapture?: (e: any) => void,
|
||||
pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto',
|
||||
style?: GenericStyleProp<ViewStyle>,
|
||||
testID?: string,
|
||||
// web extensions
|
||||
onContextMenu?: (e: any) => void,
|
||||
href?: string,
|
||||
itemID?: string,
|
||||
itemRef?: string,
|
||||
itemProp?: string,
|
||||
itemScope?: string,
|
||||
itemType?: string
|
||||
itemType?: string,
|
||||
rel?: string,
|
||||
target?: string,
|
||||
unstable_ariaSet?: Object,
|
||||
unstable_dataSet?: Object
|
||||
};
|
||||
|
||||
+83
-33
@@ -13,6 +13,34 @@ import type { ElementRef } from 'react';
|
||||
import UIManager from '../exports/UIManager';
|
||||
import createDOMProps from '../modules/createDOMProps';
|
||||
import { useImperativeHandle, useRef } from 'react';
|
||||
import TextInputState from '../modules/TextInputState';
|
||||
|
||||
function setNativeProps(node, nativeProps, classList, style, previousStyle) {
|
||||
if (node != null && nativeProps) {
|
||||
const domProps = createDOMProps(null, {
|
||||
...nativeProps,
|
||||
classList: [nativeProps.className, classList],
|
||||
style: [style, nativeProps.style]
|
||||
});
|
||||
|
||||
const nextDomStyle = domProps.style;
|
||||
|
||||
if (previousStyle.current != null) {
|
||||
if (domProps.style == null) {
|
||||
domProps.style = {};
|
||||
}
|
||||
for (const styleName in previousStyle.current) {
|
||||
if (domProps.style[styleName] == null) {
|
||||
domProps.style[styleName] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
previousStyle.current = nextDomStyle;
|
||||
|
||||
UIManager.updateView(node, domProps);
|
||||
}
|
||||
}
|
||||
|
||||
export default function usePlatformMethods(
|
||||
hostRef: ElementRef<any>,
|
||||
@@ -26,52 +54,74 @@ export default function usePlatformMethods(
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => {
|
||||
const hostNode = hostRef.current;
|
||||
return {
|
||||
blur() {
|
||||
UIManager.blur(hostRef.current);
|
||||
UIManager.blur(hostNode);
|
||||
},
|
||||
focus() {
|
||||
UIManager.focus(hostRef.current);
|
||||
UIManager.focus(hostNode);
|
||||
},
|
||||
measure(callback) {
|
||||
UIManager.measure(hostRef.current, callback);
|
||||
UIManager.measure(hostNode, callback);
|
||||
},
|
||||
measureLayout(relativeToNativeNode, onFail, onSuccess) {
|
||||
UIManager.measureLayout(hostRef.current, relativeToNativeNode, onFail, onSuccess);
|
||||
UIManager.measureLayout(hostNode, relativeToNativeNode, onFail, onSuccess);
|
||||
},
|
||||
measureInWindow(callback) {
|
||||
UIManager.measureInWindow(hostRef.current, callback);
|
||||
UIManager.measureInWindow(hostNode, callback);
|
||||
},
|
||||
setNativeProps(nativeProps) {
|
||||
const node = hostRef.current;
|
||||
if (node && nativeProps) {
|
||||
const domProps = createDOMProps(null, {
|
||||
...nativeProps,
|
||||
classList: [nativeProps.className, classList],
|
||||
style: [style, nativeProps.style]
|
||||
});
|
||||
|
||||
const nextDomStyle = domProps.style;
|
||||
|
||||
if (previousStyle.current != null) {
|
||||
if (domProps.style == null) {
|
||||
domProps.style = {};
|
||||
}
|
||||
for (const styleName in previousStyle.current) {
|
||||
if (domProps.style[styleName] == null) {
|
||||
domProps.style[styleName] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
previousStyle.current = nextDomStyle;
|
||||
|
||||
UIManager.updateView(node, domProps);
|
||||
}
|
||||
},
|
||||
...extras
|
||||
setNativeProps(hostNode, nativeProps, classList, style, previousStyle);
|
||||
}
|
||||
};
|
||||
},
|
||||
[classList, hostRef, style, extras]
|
||||
[classList, hostRef, style]
|
||||
);
|
||||
}
|
||||
|
||||
export function usePlatformInputMethods(
|
||||
hostRef: ElementRef<any>,
|
||||
ref: ElementRef<any>,
|
||||
classList: Array<boolean | string>,
|
||||
style: GenericStyleProp<any>,
|
||||
extras: any
|
||||
) {
|
||||
const previousStyle = useRef(null);
|
||||
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => {
|
||||
const hostNode = hostRef.current;
|
||||
return {
|
||||
blur() {
|
||||
UIManager.blur(hostNode);
|
||||
},
|
||||
clear() {
|
||||
if (hostNode != null) {
|
||||
hostNode.value = '';
|
||||
}
|
||||
},
|
||||
focus() {
|
||||
UIManager.focus(hostNode);
|
||||
},
|
||||
isFocused() {
|
||||
return hostNode != null && TextInputState.currentlyFocusedField() === hostNode;
|
||||
},
|
||||
measure(callback) {
|
||||
UIManager.measure(hostNode, callback);
|
||||
},
|
||||
measureLayout(relativeToNativeNode, onFail, onSuccess) {
|
||||
UIManager.measureLayout(hostNode, relativeToNativeNode, onFail, onSuccess);
|
||||
},
|
||||
measureInWindow(callback) {
|
||||
UIManager.measureInWindow(hostNode, callback);
|
||||
},
|
||||
setNativeProps(nativeProps) {
|
||||
setNativeProps(hostNode, nativeProps, classList, style, previousStyle);
|
||||
}
|
||||
};
|
||||
},
|
||||
[classList, hostRef, style]
|
||||
);
|
||||
}
|
||||
|
||||
+4
-1
@@ -17,7 +17,10 @@ describe('modules/AccessibilityUtil/propsToAccessibilityComponent', () => {
|
||||
|
||||
test('when "accessibilityRole" is "heading" and "aria-level" is set', () => {
|
||||
expect(
|
||||
propsToAccessibilityComponent({ accessibilityRole: 'heading', 'aria-level': 3 })
|
||||
propsToAccessibilityComponent({
|
||||
accessibilityRole: 'heading',
|
||||
unstable_ariaSet: { level: 3 }
|
||||
})
|
||||
).toEqual('h3');
|
||||
});
|
||||
|
||||
+6
-2
@@ -34,8 +34,12 @@ const propsToAccessibilityComponent = (props: Object = emptyObject) => {
|
||||
const role = propsToAriaRole(props);
|
||||
if (role) {
|
||||
if (role === 'heading') {
|
||||
const level = props['aria-level'] || 1;
|
||||
return `h${level}`;
|
||||
const ariaSet = props.unstable_ariaSet;
|
||||
if (ariaSet != null && ariaSet.level) {
|
||||
const level = ariaSet.level;
|
||||
return `h${level}`;
|
||||
}
|
||||
return 'h1';
|
||||
}
|
||||
return roleComponents[role];
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import styleResolver from '../../exports/StyleSheet/styleResolver';
|
||||
import { STYLE_GROUPS } from '../../exports/StyleSheet/constants';
|
||||
|
||||
const emptyObject = {};
|
||||
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
// Reset styles for heading, link, and list DOM elements
|
||||
const classes = css.create(
|
||||
@@ -65,8 +66,8 @@ const createDOMProps = (component, props, styleResolver) => {
|
||||
accessibilityLiveRegion,
|
||||
accessibilityRelationship,
|
||||
accessibilityState,
|
||||
accessibilityValue,
|
||||
classList,
|
||||
className: deprecatedClassName,
|
||||
disabled: providedDisabled,
|
||||
importantForAccessibility,
|
||||
nativeID,
|
||||
@@ -77,6 +78,8 @@ const createDOMProps = (component, props, styleResolver) => {
|
||||
accessible,
|
||||
accessibilityRole,
|
||||
/* eslint-enable */
|
||||
unstable_ariaSet,
|
||||
unstable_dataSet,
|
||||
...domProps
|
||||
} = props;
|
||||
|
||||
@@ -84,6 +87,30 @@ const createDOMProps = (component, props, styleResolver) => {
|
||||
(accessibilityState != null && accessibilityState.disabled === true) || providedDisabled;
|
||||
const role = AccessibilityUtil.propsToAriaRole(props);
|
||||
|
||||
// unstable_ariaSet
|
||||
if (unstable_ariaSet != null) {
|
||||
for (const prop in unstable_ariaSet) {
|
||||
if (hasOwnProperty.call(unstable_ariaSet, prop)) {
|
||||
const value = unstable_ariaSet[prop];
|
||||
if (value != null) {
|
||||
domProps[`aria-${prop}`] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unstable_dataSet
|
||||
if (unstable_dataSet != null) {
|
||||
for (const prop in unstable_dataSet) {
|
||||
if (hasOwnProperty.call(unstable_dataSet, prop)) {
|
||||
const value = unstable_dataSet[prop];
|
||||
if (value != null) {
|
||||
domProps[`data-${prop}`] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// accessibilityLabel
|
||||
if (accessibilityLabel != null) {
|
||||
domProps['aria-label'] = accessibilityLabel;
|
||||
@@ -126,6 +153,17 @@ const createDOMProps = (component, props, styleResolver) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// accessibilityValue
|
||||
if (accessibilityValue != null) {
|
||||
for (const prop in accessibilityValue) {
|
||||
const value = accessibilityValue[prop];
|
||||
if (value != null) {
|
||||
domProps[`aria-value${prop}`] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// legacy fallbacks
|
||||
if (importantForAccessibility === 'no-hide-descendants') {
|
||||
domProps['aria-hidden'] = true;
|
||||
@@ -182,12 +220,7 @@ const createDOMProps = (component, props, styleResolver) => {
|
||||
component === 'ul' ||
|
||||
role === 'heading';
|
||||
// Classic CSS styles
|
||||
const finalClassList = [
|
||||
deprecatedClassName,
|
||||
needsReset && classes.reset,
|
||||
needsCursor && classes.cursor,
|
||||
classList
|
||||
];
|
||||
const finalClassList = [needsReset && classes.reset, needsCursor && classes.cursor, classList];
|
||||
|
||||
// Resolve styles
|
||||
const { className, style } = styleResolver(reactNativeStyle, finalClassList);
|
||||
@@ -202,7 +235,7 @@ const createDOMProps = (component, props, styleResolver) => {
|
||||
|
||||
// OTHER
|
||||
// Native element ID
|
||||
if (nativeID && nativeID.constructor === String) {
|
||||
if (nativeID != null) {
|
||||
domProps.id = nativeID;
|
||||
}
|
||||
|
||||
@@ -214,7 +247,7 @@ const createDOMProps = (component, props, styleResolver) => {
|
||||
domProps.rel = `${domProps.rel || ''} noopener noreferrer`;
|
||||
}
|
||||
// Automated test IDs
|
||||
if (testID && testID.constructor === String) {
|
||||
if (testID != null) {
|
||||
domProps['data-testid'] = testID;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user