[fix] add support for TextInput placeholderTextColor prop

This change also ensures that potential object-styles (user-provided or
placeholderTextColor) are group together at the end of the style array.

Fix #560
This commit is contained in:
Nicolas Gallagher
2018-01-23 16:36:26 -08:00
parent 240cf7e05f
commit 31d428a649
9 changed files with 126 additions and 30 deletions
@@ -37,6 +37,8 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
}
@keyframes rn-ActivityIndicator-animation{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg);}}
@keyframes rn-ProgressBar-animation{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);}100%{-webkit-transform:translateX(400%);transform:translateX(400%);}}
.rn-pointerEvents-12vffkv > *{pointer-events:auto}
.rn-pointerEvents-12vffkv{pointer-events:none !important}
.rn-alignItems-1oszu61{-ms-flex-align:stretch;-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
.rn-borderTopStyle-1efd50x{border-top-style:solid}
.rn-borderRightStyle-14skgim{border-right-style:solid}
@@ -70,7 +72,5 @@ input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit
.rn-left-1d2f490{left:0px}
.rn-position-u8s1d{position:absolute}
.rn-right-zchlnj{right:0px}
.rn-top-ipm5af{top:0px}
.rn-pointerEvents-12vffkv > *{pointer-events:auto}
.rn-pointerEvents-12vffkv{pointer-events:none !important}"
.rn-top-ipm5af{top:0px}"
`;
@@ -158,13 +158,13 @@ export default class ReactNativeStyleResolver {
props.classList.push(className);
} else {
// Certain properties and values are not transformed by 'createReactDOMStyle' as they
// require more complex transforms into multiple CSS rules. Here we make sure the styles
// can be represented by a className and don't end up as invalid inline-styles.
if (styleProp === 'pointerEvents') {
// require more complex transforms into multiple CSS rules. Here we assume that StyleManager
// can bind these styles to a className, and prevent them becoming invalid inline-styles.
if (styleProp === 'pointerEvents' || styleProp === 'placeholderTextColor') {
const className = this.styleSheetManager.injectDeclaration(styleProp, value);
props.classList.push(className);
// } else if (styleProp ==='placeholderTextColor') {
// } else if (styleProp ==='animationName') {
if (className) {
props.classList.push(className);
}
} else {
if (!props.style) {
props.style = {};
@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StyleSheet/createAtomicRules transforms custom placeholderTextColor declaration 1`] = `
Array [
"@media all {
.test::-webkit-input-placeholder{color:gray;opacity:1}
.test::-moz-placeholder{color:gray;opacity:1}
.test:-ms-input-placeholder{color:gray;opacity:1}
.test::placeholder{color:gray;opacity:1}
}",
]
`;
exports[`StyleSheet/createAtomicRules transforms custom pointerEvents declaration 1`] = `
Array [
".test > *{pointer-events:none}",
".test{pointer-events:auto !important}",
]
`;
exports[`StyleSheet/createAtomicRules transforms standard declarations to a single rule 1`] = `
Array [
".test{margin:0px}",
]
`;
@@ -0,0 +1,17 @@
/* eslint-env jasmine, jest */
import createAtomicRules from '../createAtomicRules';
describe('StyleSheet/createAtomicRules', () => {
test('transforms standard declarations to a single rule', () => {
expect(createAtomicRules('.test', 'margin', 0)).toMatchSnapshot();
});
test('transforms custom pointerEvents declaration', () => {
expect(createAtomicRules('.test', 'pointerEvents', 'box-only')).toMatchSnapshot();
});
test('transforms custom placeholderTextColor declaration', () => {
expect(createAtomicRules('.test', 'placeholderTextColor', 'gray')).toMatchSnapshot();
});
});
@@ -2,29 +2,47 @@ import createRuleBlock from './createRuleBlock';
const createAtomicRules = (selector, prop, value) => {
const rules = [];
let val = value;
// pointerEvents is a special case that requires custom values and additional rules
// See #513
if (prop === 'pointerEvents') {
if (value === 'auto' || value === 'box-only') {
val = 'auto !important';
if (value === 'box-only') {
const block = createRuleBlock({ [prop]: 'none' });
rules.push(`${selector} > *{${block}}`);
}
} else if (value === 'none' || value === 'box-none') {
val = 'none !important';
if (value === 'box-none') {
const block = createRuleBlock({ [prop]: 'auto' });
rules.push(`${selector} > *{${block}}`);
switch (prop) {
// pointerEvents is a special case that requires custom values and additional rules
// See #513
case 'pointerEvents': {
let val = value;
if (value === 'auto' || value === 'box-only') {
val = 'auto !important';
if (value === 'box-only') {
const block = createRuleBlock({ [prop]: 'none' });
rules.push(`${selector} > *{${block}}`);
}
} else if (value === 'none' || value === 'box-none') {
val = 'none !important';
if (value === 'box-none') {
const block = createRuleBlock({ [prop]: 'auto' });
rules.push(`${selector} > *{${block}}`);
}
}
const block = createRuleBlock({ [prop]: val });
rules.push(`${selector}{${block}}`);
break;
}
case 'placeholderTextColor': {
const block = createRuleBlock({ color: value, opacity: 1 });
rules.push(`@media all {
${selector}::-webkit-input-placeholder{${block}}
${selector}::-moz-placeholder{${block}}
${selector}:-ms-input-placeholder{${block}}
${selector}::placeholder{${block}}
}`);
break;
}
default: {
const block = createRuleBlock({ [prop]: value });
rules.push(`${selector}{${block}}`);
}
}
const block = createRuleBlock({ [prop]: val });
rules.push(`${selector}{${block}}`);
return rules;
};
+1 -2
View File
@@ -104,6 +104,7 @@ class TextInput extends Component<*> {
onSelectionChange: func,
onSubmitEditing: func,
placeholder: string,
placeholderTextColor: ColorPropType,
secureTextEntry: bool,
selectTextOnFocus: bool,
selection: shape({
@@ -126,7 +127,6 @@ class TextInput extends Component<*> {
onContentSizeChange: func,
onEndEditing: func,
onScroll: func,
placeholderTextColor: ColorPropType,
returnKeyLabel: string,
returnKeyType: string,
selectionColor: ColorPropType,
@@ -198,7 +198,6 @@ class TextInput extends Component<*> {
onContentSizeChange,
onEndEditing,
onScroll,
placeholderTextColor,
returnKeyLabel,
returnKeyType,
selectionColor,
@@ -68,6 +68,7 @@ const createDOMProps = (component, props, styleResolver) => {
accessibilityLabel,
accessibilityLiveRegion,
importantForAccessibility,
placeholderTextColor,
pointerEvents,
style: providedStyle,
testID,
@@ -89,8 +90,9 @@ const createDOMProps = (component, props, styleResolver) => {
role === 'heading' && resetStyles.heading,
component === 'ul' && resetStyles.list,
role === 'button' && !isDisabled && resetStyles.ariaButton,
pointerEvents && pointerEventsStyles[pointerEvents],
providedStyle,
pointerEvents && pointerEventsStyles[pointerEvents]
placeholderTextColor && { placeholderTextColor }
];
const { className, style } = styleResolver(reactNativeStyle);
@@ -14,6 +14,7 @@ import PropMultiline from './examples/PropMultiline';
import PropNumberOfLines from './examples/PropNumberOfLines';
import PropOnSelectionChange from './examples/PropOnSelectionChange';
import PropPlaceholder from './examples/PropPlaceholder';
import PropPlaceholderTextColor from './examples/PropPlaceholderTextColor';
import PropSecureTextEntry from './examples/PropSecureTextEntry';
import PropSelectTextOnFocus from './examples/PropSelectTextOnFocus';
import TextInputEvents from './examples/TextInputEvents';
@@ -262,6 +263,15 @@ nativeEvent: { key: keyValue } }`}</Code>{' '}
}}
/>
<DocItem
name="placeholderTextColor"
typeInfo="?color"
description="The text color of the placeholder string."
example={{
render: () => <PropPlaceholderTextColor />
}}
/>
<DocItem
name="secureTextEntry"
typeInfo="?boolean = false"
@@ -0,0 +1,25 @@
/**
* @flow
*/
import React from 'react';
import { styles } from '../helpers';
import { TextInput, View } from 'react-native';
const TextInputPlaceholderTextColorExample = () => (
<View>
<TextInput
placeholder="This is placeholder text"
placeholderTextColor="orange"
style={styles.textinput}
/>
<TextInput
multiline={true}
placeholder="This is placeholder text"
placeholderTextColor="red"
style={styles.multiline}
/>
</View>
);
export default TextInputPlaceholderTextColorExample;