Compare commits

...

5 Commits

Author SHA1 Message Date
Nicolas Gallagher
24eda7c4ad 0.0.73 2017-02-24 12:35:18 -08:00
Nicolas Gallagher
44ebd8f5a3 [change] modality-specific focus styles
Remove the default focus ring when the keyboard is not being used. This
provides a superior UX when using touch or mouse.

Fix #310
2017-02-18 13:39:25 -08:00
Matthias Le Brun
a3ed8f05e6 [add] resize 'TextInput' style
Fix #363
2017-02-18 12:49:25 -08:00
Nicolas Gallagher
b653fe0bd3 [add] fontFeatureSettings 'Text' style
Fix #331
2017-02-18 12:18:28 -08:00
Nicolas Gallagher
30da226e4d Update component style docs 2017-02-18 12:07:30 -08:00
13 changed files with 172 additions and 43 deletions

View File

@@ -63,6 +63,7 @@ Lets the user select the text.
+ ...[View#style](View.md)
+ `color`
+ `fontFamily`
+ `fontFeatureSettings`
+ `fontSize`
+ `fontStyle`
+ `fontWeight`
@@ -71,17 +72,19 @@ Lets the user select the text.
+ `textAlign`
+ `textAlignVertical`
+ `textDecorationLine`
+ `textOverflow`
+ `textRendering`
+ `textOverflow`
+ `textRendering`
+ `textShadowColor`
+ `textShadowOffset`
+ `textShadowRadius`
+ `textTransform`
+ `unicodeBidi`
+ `textTransform`
+ `unicodeBidi`
+ `whiteSpace`
+ `wordWrap`
+ `wordWrap`
+ `writingDirection`
‡ web only.
**testID**: string
Used to locate this view in end-to-end tests.

View File

@@ -144,7 +144,9 @@ If `true`, all text will automatically be selected on focus.
**style**: style
+ ...[Text#style](./Text.md)
+ `outline`
+ `resize`
‡ web only.
**testID**: string

View File

@@ -99,23 +99,23 @@ from `style`.
+ `alignContent`
+ `alignItems`
+ `alignSelf`
+ `animationDelay`
+ `animationDirection`
+ `animationDuration`
+ `animationFillMode`
+ `animationIterationCount`
+ `animationName`
+ `animationPlayState`
+ `animationTimingFunction`
+ `animationDelay`
+ `animationDirection`
+ `animationDuration`
+ `animationFillMode`
+ `animationIterationCount`
+ `animationName`
+ `animationPlayState`
+ `animationTimingFunction`
+ `backfaceVisibility`
+ `backgroundAttachment`
+ `backgroundClip`
+ `backgroundAttachment`
+ `backgroundClip`
+ `backgroundColor`
+ `backgroundImage`
+ `backgroundOrigin`
+ `backgroundPosition`
+ `backgroundRepeat`
+ `backgroundSize`
+ `backgroundImage`
+ `backgroundOrigin`
+ `backgroundPosition`
+ `backgroundRepeat`
+ `backgroundSize`
+ `borderColor` (single value)
+ `borderTopColor`
+ `borderBottomColor`
@@ -139,7 +139,8 @@ from `style`.
+ `bottom`
+ `boxShadow`
+ `boxSizing`
+ `cursor`
+ `cursor`
+ `display`
+ `flex` (number)
+ `flexBasis`
+ `flexDirection`
@@ -162,9 +163,10 @@ from `style`.
+ `minWidth`
+ `opacity`
+ `order`
+ `outline`
+ `overflow`
+ `overflowX`
+ `overflowY`
+ `overflowX`
+ `overflowY`
+ `padding` (single value)
+ `paddingBottom`
+ `paddingHorizontal`
@@ -172,22 +174,25 @@ from `style`.
+ `paddingRight`
+ `paddingTop`
+ `paddingVertical`
+ `perspective`
+ `perspectiveOrigin`
+ `perspective`
+ `perspectiveOrigin`
+ `position`
+ `right`
+ `top`
+ `transform`
+ `transformOrigin`
+ `transitionDelay`
+ `transitionDuration`
+ `transitionProperty`
+ `transitionTimingFunction`
+ `userSelect`
+ `visibility`
+ `transformOrigin`
+ `transitionDelay`
+ `transitionDuration`
+ `transitionProperty`
+ `transitionTimingFunction`
+ `userSelect`
+ `visibility`
+ `width`
+ `willChange`
+ `zIndex`
‡ web only.
Default:
```js

View File

@@ -1,6 +1,6 @@
{
"name": "react-native-web",
"version": "0.0.72",
"version": "0.0.73",
"description": "React Native for Web",
"main": "dist/index.js",
"files": [

View File

@@ -11,6 +11,7 @@ import { PropTypes } from 'react'
import ImageStylePropTypes from '../../components/Image/ImageStylePropTypes'
import ReactPropTypeLocations from 'react-dom/lib/ReactPropTypeLocations'
import ReactPropTypesSecret from 'react-dom/lib/ReactPropTypesSecret'
import TextInputStylePropTypes from '../../components/TextInput/TextInputStylePropTypes'
import TextStylePropTypes from '../../components/Text/TextStylePropTypes'
import ViewStylePropTypes from '../../components/View/ViewStylePropTypes'
import warning from 'fbjs/lib/warning'
@@ -66,17 +67,16 @@ var allStylePropTypes = {};
StyleSheetValidation.addValidStylePropTypes(ImageStylePropTypes)
StyleSheetValidation.addValidStylePropTypes(TextStylePropTypes)
StyleSheetValidation.addValidStylePropTypes(TextInputStylePropTypes)
StyleSheetValidation.addValidStylePropTypes(ViewStylePropTypes)
StyleSheetValidation.addValidStylePropTypes({
appearance: PropTypes.string,
clear: PropTypes.string,
cursor: PropTypes.string,
display: PropTypes.string,
float: PropTypes.oneOf([ 'left', 'none', 'right' ]),
font: PropTypes.string, /* @private */
listStyle: PropTypes.string,
pointerEvents: PropTypes.string,
WebkitOverflowScrolling: PropTypes.string /* @private */
pointerEvents: PropTypes.string
})
module.exports = StyleSheetValidation

View File

@@ -12,6 +12,7 @@ const WritingDirectionPropType = oneOf([ 'auto', 'ltr', 'rtl' ]);
const TextOnlyStylePropTypes = {
color: ColorPropType,
fontFamily: string,
fontFeatureSettings: string,
fontSize: numberOrString,
fontStyle: string,
fontWeight: string,

View File

@@ -0,0 +1,14 @@
import TextStylePropTypes from '../Text/TextStylePropTypes';
import { PropTypes } from 'react';
const { oneOf } = PropTypes;
const TextInputOnlyStylePropTypes = {
/* @platform web */
resize: oneOf([ 'none', 'vertical', 'horizontal', 'both' ])
};
module.exports = {
...TextStylePropTypes,
...TextInputOnlyStylePropTypes
};

View File

@@ -5,7 +5,7 @@ import createDOMElement from '../../modules/createDOMElement';
import findNodeHandle from '../../modules/findNodeHandle';
import StyleSheet from '../../apis/StyleSheet';
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
import TextStylePropTypes from '../Text/TextStylePropTypes';
import TextInputStylePropTypes from './TextInputStylePropTypes';
import TextareaAutosize from 'react-textarea-autosize';
import TextInputState from './TextInputState';
import ViewPropTypes from '../View/ViewPropTypes';
@@ -84,7 +84,7 @@ class TextInput extends Component {
start: PropTypes.number.isRequired,
end: PropTypes.number
}),
style: StyleSheetPropType(TextStylePropTypes),
style: StyleSheetPropType(TextInputStylePropTypes),
value: PropTypes.string
};
@@ -277,7 +277,8 @@ const styles = StyleSheet.create({
boxSizing: 'border-box',
color: 'inherit',
font: 'inherit',
padding: 0
padding: 0,
resize: 'none'
}
});

View File

@@ -33,7 +33,6 @@ module.exports = {
backgroundSize: string,
boxShadow: string,
cursor: string,
display: string,
outline: string,
overflowX: autoOrHiddenOrVisible,
overflowY: autoOrHiddenOrVisible,
@@ -45,6 +44,6 @@ module.exports = {
transitionTimingFunction: string,
userSelect: string,
visibility: hiddenOrVisible,
WebkitOverflowScrolling: oneOf([ 'auto', 'touch' ]),
willChange: string
willChange: string,
WebkitOverflowScrolling: oneOf([ 'auto', 'touch' ])
};

View File

@@ -18,6 +18,9 @@ import View from './components/View';
// modules
import createDOMElement from './modules/createDOMElement';
import modality from './modules/modality';
modality();
const ReactNativeCore = {
createDOMElement,

View File

@@ -39,6 +39,7 @@ import View from './components/View';
// modules
import createDOMElement from './modules/createDOMElement';
import modality from './modules/modality';
import NativeModules from './modules/NativeModules';
// propTypes
@@ -46,6 +47,8 @@ import ColorPropType from './propTypes/ColorPropType';
import EdgeInsetsPropType from './propTypes/EdgeInsetsPropType';
import PointPropType from './propTypes/PointPropType';
modality();
const ReactNative = {
// top-level API
findNodeHandle,

View File

@@ -0,0 +1,97 @@
/* global document, window */
/**
* Adapts focus styles based on the user's active input modality (i.e., how
* they are interacting with the UI right now).
*
* Focus styles are only relevant when using the keyboard to interact with the
* page. If we only show the focus ring when relevant, we can avoid user
* confusion without compromising accessibility.
*
* The script uses two heuristics to determine whether the keyboard is being used:
*
* 1. a keydown event occurred immediately before a focus event;
* 2. a focus event happened on an element which requires keyboard interaction (e.g., a text field);
*
* Based on https://github.com/WICG/modality
*/
const modality = () => {
/**
* Determine whether the keyboard is required when an element is focused
*/
const proto = window.Element.prototype;
const matcher = proto.matches || proto.mozMatchesSelector || proto.msMatchesSelector || proto.webkitMatchesSelector;
const keyboardModalityWhitelist = [
'input:not([type])',
'input[type=text]',
'input[type=number]',
'input[type=date]',
'input[type=time]',
'input[type=datetime]',
'textarea',
'[role=textbox]',
// indicates that a custom element supports the keyboard
'[supports-modality=keyboard]'
].join(',');
const focusTriggersKeyboardModality = (el) => {
if (matcher) {
return matcher.call(el, keyboardModalityWhitelist) && matcher.call(el, ':not([readonly])');
} else {
return false;
}
};
/**
* Disable the focus ring by default
*/
const id = 'modality__';
const style = `<style id="${id}">:focus { outline: none; }</style>`;
document.head.insertAdjacentHTML('afterbegin', style);
const styleElement = document.getElementById(id);
const disableFocus = () => {
if (styleElement) {
styleElement.disabled = false;
}
};
const enableFocus = () => {
if (styleElement) {
styleElement.disabled = true;
}
};
/**
* Manage the modality focus state
*/
let keyboardTimer;
let hadKeyboardEvent = false;
// track when the keyboard is in use
document.body.addEventListener('keydown', () => {
hadKeyboardEvent = true;
if (keyboardTimer) {
clearTimeout(keyboardTimer);
}
keyboardTimer = setTimeout(() => {
hadKeyboardEvent = false;
}, 100);
}, true);
// disable focus style reset when the keyboard is in use
document.body.addEventListener('focus', (e) => {
if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {
enableFocus();
}
}, true);
// enable focus style reset when keyboard is no longer in use
document.body.addEventListener('blur', () => {
if (!hadKeyboardEvent) {
disableFocus();
}
}, true);
};
export default modality;

View File

@@ -11,6 +11,7 @@ const LayoutPropTypes = {
borderRightWidth: numberOrString,
borderTopWidth: numberOrString,
boxSizing: string,
display: string,
height: numberOrString,
margin: numberOrString,
marginBottom: numberOrString,