From 68068f8cb664ec553d49778bb12de2d674bc4532 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 20 Mar 2017 22:29:32 -0700 Subject: [PATCH] [fix] support React Native props in 'setNativeProps' React Native allows props like 'pointerEvents' to be set using 'setNativeProps'. Fix #392 --- src/modules/NativeMethodsMixin/index.js | 8 +-- src/modules/createDOMElement/index.js | 49 +--------------- src/modules/createDOMProps/index.js | 75 +++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 51 deletions(-) create mode 100644 src/modules/createDOMProps/index.js diff --git a/src/modules/NativeMethodsMixin/index.js b/src/modules/NativeMethodsMixin/index.js index 152bcd7b..51113f39 100644 --- a/src/modules/NativeMethodsMixin/index.js +++ b/src/modules/NativeMethodsMixin/index.js @@ -6,6 +6,7 @@ * @flow */ +import createDOMProps from '../createDOMProps'; import findNodeHandle from '../findNodeHandle'; import StyleRegistry from '../../apis/StyleSheet/registry'; import UIManager from '../../apis/UIManager'; @@ -70,10 +71,9 @@ const NativeMethodsMixin = { const node = findNodeHandle(this); const classList = [...node.classList]; - const { className, style } = StyleRegistry.resolveStateful(nativeProps.style, classList); - const props = { ...nativeProps, className, style }; - - UIManager.updateView(node, props, this); + const domProps = createDOMProps(nativeProps, style => + StyleRegistry.resolveStateful(style, classList)); + UIManager.updateView(node, domProps, this); } }; diff --git a/src/modules/createDOMElement/index.js b/src/modules/createDOMElement/index.js index 94639992..7bcc3f1a 100644 --- a/src/modules/createDOMElement/index.js +++ b/src/modules/createDOMElement/index.js @@ -1,5 +1,6 @@ import '../injectResponderEventPlugin'; +import createDOMProps from '../createDOMProps'; import getAccessibilityRole from '../getAccessibilityRole'; import normalizeNativeEvent from '../normalizeNativeEvent'; import React from 'react'; @@ -52,28 +53,12 @@ const wrapEventHandler = handler => e => { }; const createDOMElement = (component, rnProps) => { - const { - accessibilityLabel, - accessibilityLiveRegion, - accessible = true, - style: rnStyle, - testID, - type, - /* eslint-disable */ - accessibilityComponentType, - accessibilityRole, - accessibilityTraits, - /* eslint-enable */ - ...domProps - } = rnProps || emptyObject; - // use equivalent platform elements where possible const role = getAccessibilityRole(rnProps || emptyObject); const accessibilityComponent = role && roleComponents[role]; const Component = accessibilityComponent || component; - // convert React Native styles to DOM styles - const { className, style } = StyleRegistry.resolve(rnStyle) || emptyObject; + const domProps = createDOMProps(rnProps, style => StyleRegistry.resolve(style)); // normalize DOM events to match React Native events // TODO: move this out of the render path @@ -86,36 +71,6 @@ const createDOMElement = (component, rnProps) => { } } - if (!accessible) { - domProps['aria-hidden'] = true; - } - if (accessibilityLabel) { - domProps['aria-label'] = accessibilityLabel; - } - if (accessibilityLiveRegion) { - domProps['aria-live'] = accessibilityLiveRegion; - } - if (className && className !== '') { - domProps.className = domProps.className ? `${domProps.className} ${className}` : className; - } - if (role) { - domProps.role = role; - if (role === 'button') { - domProps.type = 'button'; - } else if (role === 'link' && domProps.target === '_blank') { - domProps.rel = `${domProps.rel || ''} noopener noreferrer`; - } - } - if (style) { - domProps.style = style; - } - if (testID) { - domProps['data-testid'] = testID; - } - if (type) { - domProps.type = type; - } - return ; }; diff --git a/src/modules/createDOMProps/index.js b/src/modules/createDOMProps/index.js new file mode 100644 index 00000000..0396dd50 --- /dev/null +++ b/src/modules/createDOMProps/index.js @@ -0,0 +1,75 @@ +import getAccessibilityRole from '../getAccessibilityRole'; +import StyleSheet from '../../apis/StyleSheet'; + +const emptyObject = {}; + +const pointerEventStyles = StyleSheet.create({ + auto: { + pointerEvents: 'auto' + }, + 'box-none': { + pointerEvents: 'box-none' + }, + 'box-only': { + pointerEvents: 'box-only' + }, + none: { + pointerEvents: 'none' + } +}); + +const createDOMProps = (rnProps, resolveStyle) => { + const { + accessibilityLabel, + accessibilityLiveRegion, + accessible = true, + pointerEvents, + style: rnStyle, + testID, + type, + /* eslint-disable */ + accessibilityComponentType, + accessibilityRole, + accessibilityTraits, + /* eslint-enable */ + ...domProps + } = rnProps || emptyObject; + + const pointerEventStyle = pointerEvents && pointerEventStyles[pointerEvents]; + const { className, style } = resolveStyle([rnStyle, pointerEventStyle]) || emptyObject; + const role = getAccessibilityRole(rnProps || emptyObject); + + if (!accessible) { + domProps['aria-hidden'] = true; + } + if (accessibilityLabel) { + domProps['aria-label'] = accessibilityLabel; + } + if (accessibilityLiveRegion) { + domProps['aria-live'] = accessibilityLiveRegion; + } + if (className && className !== '') { + domProps.className = domProps.className ? `${domProps.className} ${className}` : className; + } + if (role) { + domProps.role = role; + if (role === 'button') { + domProps.type = 'button'; + } else if (role === 'link' && domProps.target === '_blank') { + domProps.rel = `${domProps.rel || ''} noopener noreferrer`; + } + } + if (style) { + domProps.style = style; + } + if (testID) { + domProps['data-testid'] = testID; + } + if (type) { + domProps.type = type; + } + + return domProps; +}; + +module.exports = createDOMProps;