Comparing version 2.0.0-rc2 to 2.0.0-rc3
@@ -11,2 +11,3 @@ # Change Log | ||
- [Button] Prevent sticky hover for touch devices by leveraging mouseEnter & mouseLeave instead of the :hover pseudo class [8f590e2](https://github.com/nikgraf/belle/commit/8f590e27bf0da53828ff7d8fdac32d759e480aa5) | ||
- [Toggle] Hide Webkit tap highlight on touch [5faf2c5](https://github.com/nikgraf/belle/commit/5faf2c56a05f461b20795fc4c097d5259aca3e54) | ||
@@ -39,2 +40,3 @@ ### Added | ||
- [ComboBox] Fix hovering and selecting Options with values of type Number [64a2797](https://github.com/nikgraf/belle/commit/64a27974ecfa6f327063810484e1150d94276699) | ||
- [TextInput] fix calculating the height in case a defaultValue was provided and props were updated [f1a9bc2](https://github.com/nikgraf/belle/commit/f1a9bc2ee0c3fdb74daf805b854fa0c20a249439) | ||
@@ -41,0 +43,0 @@ ### Removed |
@@ -31,2 +31,10 @@ 'use strict'; | ||
* ActionArea | ||
* | ||
* The purpose of this component is to provide a button like behaviour for a | ||
* click like interaction within other components. Button can't be used in such | ||
* cases as it always will have it's own focus which is not desired in | ||
* components like DatePicker e.g. next month button. | ||
* | ||
* Note: Use the ActionArea's onUpdate instead of onClick as otherwise on iOS9 | ||
* the ActionArea will trigger onFocus for it's parent with a set tabindex. | ||
*/ | ||
@@ -42,2 +50,9 @@ | ||
this.state = { | ||
// Note: On touch devices mouseEnter is fired while mouseLeave is not. | ||
// This would result in a hover effect that keeps active until another | ||
// element is focused on. This would result in the same behaviour as using | ||
// the :hover pseudo class. To prevent it from happening activating the | ||
// hover state is prevented when a touch event has been triggered before. | ||
// source: http://stackoverflow.com/a/22444532/837709 | ||
isIgnoringHover: false, | ||
isActive: false, | ||
@@ -68,3 +83,6 @@ isHovered: false | ||
/** | ||
* TODO | ||
* As soon as the mouse enters the component the isHovered state is activated. | ||
* | ||
* The state isHovered is not set to true in case onMouseEnter was triggered | ||
* by a touch event. | ||
*/ | ||
@@ -74,5 +92,8 @@ }, { | ||
value: function _onMouseEnter(event) { | ||
this.setState({ | ||
isHovered: true | ||
}); | ||
if (!this.state.isIgnoringHover) { | ||
this.setState({ | ||
isHovered: true, | ||
isIgnoringHover: false | ||
}); | ||
} | ||
@@ -85,3 +106,3 @@ if (this.props.onMouseEnter) { | ||
/** | ||
* TODO | ||
* Deactivate the isHovered state. | ||
*/ | ||
@@ -101,3 +122,3 @@ }, { | ||
/** | ||
* TODO | ||
* Activates the active state in case the main mouse button was pressed. | ||
*/ | ||
@@ -119,3 +140,5 @@ }, { | ||
/** | ||
* TODO | ||
* Triggers onUpdate in case the mouse button was pressed on this element. | ||
* | ||
* In addition the active state is deactivated. | ||
*/ | ||
@@ -125,2 +148,3 @@ }, { | ||
value: function _onMouseUp(event) { | ||
var isActive = this.state.isActive; | ||
if (event.button === 0) { | ||
@@ -135,6 +159,11 @@ this.setState({ | ||
} | ||
if (event.button === 0 && isActive && this.props.onUpdate) { | ||
this.props.onUpdate({}); | ||
} | ||
} | ||
/** | ||
* TODO | ||
* Updates the button to be active and makes sure the next onMouseEnter is | ||
* ignored. | ||
*/ | ||
@@ -146,3 +175,4 @@ }, { | ||
this.setState({ | ||
isActive: true | ||
isActive: true, | ||
isIgnoringHover: true | ||
}); | ||
@@ -157,3 +187,4 @@ } | ||
/** | ||
* TODO | ||
* Triggers onUpdate in case the touch event started on this element and makes | ||
* sure the next onMouseEnter is ignored. | ||
*/ | ||
@@ -163,4 +194,7 @@ }, { | ||
value: function _onTouchEnd() { | ||
var isActive = this.state.isActive; | ||
this.setState({ | ||
isActive: false | ||
isActive: false, | ||
isIgnoringHover: true | ||
}); | ||
@@ -171,6 +205,11 @@ | ||
} | ||
if (isActive && this.props.onUpdate) { | ||
this.props.onUpdate({}); | ||
} | ||
} | ||
/** | ||
* TODO | ||
* Updates the button to be release and makes sure the next onMouseEnter is | ||
* ignored. | ||
*/ | ||
@@ -181,3 +220,4 @@ }, { | ||
this.setState({ | ||
isActive: false | ||
isActive: false, | ||
isIgnoringHover: true | ||
}); | ||
@@ -203,3 +243,4 @@ | ||
'div', | ||
_extends({}, this.childProps, { | ||
_extends({ role: 'button' | ||
}, this.childProps, { | ||
onMouseDown: this._onMouseDown.bind(this), | ||
@@ -235,2 +276,3 @@ onMouseUp: this._onMouseUp.bind(this), | ||
onMouseUp: _react.PropTypes.func, | ||
onUpdate: _react.PropTypes.func, | ||
style: _react.PropTypes.object | ||
@@ -237,0 +279,0 @@ }, |
@@ -79,6 +79,2 @@ 'use strict'; | ||
function updatePseudoClassStyle(styleId, properties, preventFocusStyleForTouchAndClick) { | ||
var baseActiveStyle = properties.primary ? _styleButton2['default'].primaryActiveStyle : _styleButton2['default'].activeStyle; | ||
var activeStyle = _extends({}, baseActiveStyle, properties.activeStyle); | ||
var focusStyle = undefined; | ||
@@ -94,6 +90,2 @@ if (preventFocusStyleForTouchAndClick) { | ||
id: styleId, | ||
style: activeStyle, | ||
pseudoClass: 'active' | ||
}, { | ||
id: styleId, | ||
style: focusStyle, | ||
@@ -130,3 +122,11 @@ pseudoClass: 'focus' | ||
isActive: false, | ||
isHovered: false | ||
isHovered: false, | ||
// Note: On touch devices mouseEnter is fired while mouseLeave is not. | ||
// This would result in a hover effect that keeps active until another | ||
// element is focused on. This would result in the same behaviour as using | ||
// the :hover pseudo class. To prevent it from happening activating the | ||
// hover state is prevented when a touch event has been triggered before. | ||
// source: http://stackoverflow.com/a/22444532/837709 | ||
isIgnoringHover: false | ||
}; | ||
@@ -241,3 +241,6 @@ | ||
if (!this.props.disabled && event.touches.length === 1) { | ||
this.setState({ isActive: true }); | ||
this.setState({ | ||
isActive: true, | ||
isIgnoringHover: true | ||
}); | ||
} | ||
@@ -256,3 +259,6 @@ | ||
value: function _onTouchEnd(event) { | ||
this.setState({ isActive: false }); | ||
this.setState({ | ||
isActive: false, | ||
isIgnoringHover: true | ||
}); | ||
@@ -270,3 +276,6 @@ if (this.props.onTouchEnd) { | ||
value: function _onTouchCancel(event) { | ||
this.setState({ isActive: false }); | ||
this.setState({ | ||
isActive: false, | ||
isIgnoringHover: true | ||
}); | ||
@@ -284,5 +293,8 @@ if (this.props.onTouchEnd) { | ||
value: function _onMouseEnter(event) { | ||
this.setState({ | ||
isHovered: true | ||
}); | ||
if (!this.state.isIgnoringHover) { | ||
this.setState({ | ||
isHovered: true, | ||
isIgnoringHover: false | ||
}); | ||
} | ||
@@ -289,0 +301,0 @@ if (this.props.onMouseEnter) { |
@@ -70,3 +70,3 @@ 'use strict'; | ||
function sanitizeDayProps(properties) { | ||
return (0, _utilsHelpers.omit)(properties, ['key', 'ref', 'onMouseDown', 'onMouseUp', 'onMouseEnter', 'onMouseLeave', 'onTouchStart', 'onTouchEnd', 'onTouchCancel', 'aria-current', 'aria-selected', 'style', 'role']); | ||
return (0, _utilsHelpers.omit)(properties, ['key', 'ref', 'onMouseDown', 'onMouseUp', 'onMouseEnter', 'onMouseLeave', 'onTouchStart', 'onTouchEnd', 'onTouchCancel', 'aria-selected', 'style', 'role']); | ||
} | ||
@@ -79,3 +79,3 @@ | ||
function sanitizePrevMonthNavProps(properties) { | ||
return (0, _utilsHelpers.omit)(properties, ['className', 'onClick', 'style']); | ||
return (0, _utilsHelpers.omit)(properties, ['aria-label', 'className', 'onClick', 'style']); | ||
} | ||
@@ -88,3 +88,3 @@ | ||
function sanitizeNextMonthNavProps(properties) { | ||
return (0, _utilsHelpers.omit)(properties, ['className', 'onClick', 'style']); | ||
return (0, _utilsHelpers.omit)(properties, ['aria-label', 'className', 'onClick', 'style']); | ||
} | ||
@@ -468,4 +468,4 @@ | ||
/** | ||
* Function will handle pageUp key down event. | ||
*/ | ||
* Function will handle pageUp key down event. | ||
*/ | ||
}, { | ||
@@ -499,4 +499,4 @@ key: '_onPageUpKeyDown', | ||
/** | ||
* Function will handle pageDown key down event. | ||
*/ | ||
* Function will handle pageDown key down event. | ||
*/ | ||
}, { | ||
@@ -634,3 +634,3 @@ key: '_onPageDownKeyDown', | ||
value: function _onDayTouchEnd(dateKey, day, month, year, event) { | ||
if (!this.props.disabled && !this.props.readOnly && event.touches.length === 1) { | ||
if (!this.props.disabled && !this.props.readOnly) { | ||
this._triggerSelectDate(day, month, year); | ||
@@ -846,5 +846,6 @@ if (this.state.activeDay === dateKey) { | ||
_ActionArea2['default'], | ||
_extends({ onClick: this._onClickPrevMonth.bind(this), | ||
_extends({ onUpdate: this._onClickPrevMonth.bind(this), | ||
style: prevMonthNavStyle, | ||
className: className | ||
className: className, | ||
'aria-label': 'Go to previous month' | ||
}, this.prevMonthNavProps), | ||
@@ -869,5 +870,6 @@ _react2['default'].createElement('div', _extends({ style: prevMonthNavIconStyle | ||
_ActionArea2['default'], | ||
_extends({ onClick: this._onClickNextMonth.bind(this), | ||
_extends({ onUpdate: this._onClickNextMonth.bind(this), | ||
style: nextMonthNavStyle, | ||
className: className | ||
className: className, | ||
'aria-label': 'Go to next month' | ||
}, this.nextMonthNavProps), | ||
@@ -951,3 +953,2 @@ _react2['default'].createElement('div', _extends({ style: nextMonthNavIconStyle | ||
// According to http://www.w3.org/TR/wai-aria-1.1/#aria-current an empty value for aria-current indicated false. | ||
/** | ||
@@ -978,3 +979,2 @@ * Function will return jsx for rendering the a day. | ||
var ariaCurrent = ''; | ||
var ariaSelected = false; | ||
@@ -1002,3 +1002,2 @@ | ||
dayStyle = _extends({}, dayStyle, _styleDatePicker2['default'].todayStyle, this.props.todayStyle); | ||
ariaCurrent = 'date'; | ||
} | ||
@@ -1055,3 +1054,2 @@ | ||
onTouchCancel: this._onDayTouchCancel.bind(this, dateKey), | ||
'aria-current': ariaCurrent, | ||
'aria-selected': ariaSelected, | ||
@@ -1058,0 +1056,0 @@ style: dayStyle, |
@@ -756,3 +756,3 @@ 'use strict'; | ||
value: function _getValueForIndex(index) { | ||
return this.props.children[index].props.value; | ||
return this.options[index].props.value; | ||
} | ||
@@ -792,5 +792,57 @@ | ||
}, { | ||
key: '_renderChildren', | ||
value: function _renderChildren() { | ||
var _this2 = this; | ||
var optionsIndex = 0; | ||
return _react2['default'].Children.map(this.children, function (entry, index) { | ||
if (isOption(entry)) { | ||
var _ret = (function () { | ||
// filter out all non-Option Components | ||
var localOptionIndex = optionsIndex; | ||
var isHovered = entry.props.value === _this2.state.focusedOptionValue; | ||
var element = _react2['default'].createElement( | ||
'li', | ||
{ onClick: function () { | ||
return _this2._onClickAtOption(localOptionIndex); | ||
}, | ||
onTouchStart: function (event) { | ||
return _this2._onTouchStartAtOption(event, localOptionIndex); | ||
}, | ||
onTouchMove: _this2._onTouchMoveAtOption.bind(_this2), | ||
onTouchEnd: function (event) { | ||
return _this2._onTouchEndAtOption(event, localOptionIndex); | ||
}, | ||
onTouchCancel: _this2._onTouchCancelAtOption.bind(_this2), | ||
key: index, | ||
onMouseEnter: function () { | ||
return _this2._onMouseEnterAtOption(localOptionIndex); | ||
}, | ||
role: 'option', | ||
'aria-selected': isHovered }, | ||
entry | ||
); | ||
optionsIndex++; | ||
return { | ||
v: element | ||
}; | ||
})(); | ||
if (typeof _ret === 'object') return _ret.v; | ||
} else if (isSeparator(entry)) { | ||
return _react2['default'].createElement( | ||
'li', | ||
{ key: index, | ||
role: 'presentation' }, | ||
entry | ||
); | ||
} | ||
}); | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var _this2 = this; | ||
var _this3 = this; | ||
@@ -812,3 +864,3 @@ var defaultStyle = _extends({}, _styleSelect2['default'].style, this.props.style); | ||
var selectedEntry = (0, _utilsHelpers.find)(this.children, function (entry) { | ||
return entry.props.value === _this2.state.selectedValue; | ||
return entry.props.value === _this3.state.selectedValue; | ||
}); | ||
@@ -897,37 +949,3 @@ | ||
}, this.state.menuProps), | ||
_react2['default'].Children.map(this.children, function (entry, index) { | ||
if (isOption(entry)) { | ||
// filter out all non-Option Components | ||
var isHovered = entry.props.value === _this2.state.focusedOptionValue; | ||
return _react2['default'].createElement( | ||
'li', | ||
{ onClick: function () { | ||
return _this2._onClickAtOption(index); | ||
}, | ||
onTouchStart: function (event) { | ||
return _this2._onTouchStartAtOption(event, index); | ||
}, | ||
onTouchMove: _this2._onTouchMoveAtOption.bind(_this2), | ||
onTouchEnd: function (event) { | ||
return _this2._onTouchEndAtOption(event, index); | ||
}, | ||
onTouchCancel: _this2._onTouchCancelAtOption.bind(_this2), | ||
key: index, | ||
onMouseEnter: function () { | ||
return _this2._onMouseEnterAtOption(index); | ||
}, | ||
role: 'option', | ||
'aria-selected': isHovered }, | ||
entry | ||
); | ||
} else if (isSeparator(entry)) { | ||
return _react2['default'].createElement( | ||
'li', | ||
{ key: index, | ||
role: 'presentation' }, | ||
entry | ||
); | ||
} | ||
}) | ||
this._renderChildren() | ||
) | ||
@@ -934,0 +952,0 @@ ); |
@@ -123,5 +123,5 @@ 'use strict'; | ||
height: 'auto', | ||
inputValue: inputValue, | ||
textareaProps: sanitizeChildProps(properties) | ||
inputValue: inputValue | ||
}; | ||
this.textareaProps = sanitizeChildProps(properties); | ||
} | ||
@@ -159,4 +159,7 @@ | ||
value: function componentWillReceiveProps(properties) { | ||
var _this = this; | ||
// Makes sure we have inputValue available when triggering a resize. | ||
var newState = { | ||
textareaProps: sanitizeChildProps(properties) | ||
inputValue: this.state.inputValue | ||
}; | ||
@@ -169,6 +172,8 @@ if ((0, _utilsHelpers.has)(properties, 'valueLink')) { | ||
this.setState(newState); | ||
this.textareaProps = sanitizeChildProps(properties); | ||
(0, _utilsInjectStyle.removeStyle)(this._styleId); | ||
updatePseudoClassStyle(this._styleId, properties); | ||
this._triggerResize(newState.inputValue); | ||
this.setState(newState, function () { | ||
return _this._triggerResize(newState.inputValue); | ||
}); | ||
} | ||
@@ -259,3 +264,3 @@ | ||
onKeyDown: this._onKeyDown.bind(this) | ||
}, this.state.textareaProps)); | ||
}, this.textareaProps)); | ||
} | ||
@@ -262,0 +267,0 @@ }], [{ |
@@ -11,3 +11,2 @@ 'use strict'; | ||
color: '#716D6D', | ||
cursor: 'pointer', | ||
fontSize: 17, | ||
@@ -52,3 +51,4 @@ paddingTop: '11px', | ||
hoverStyle: { | ||
background: '#EEE' | ||
background: '#EEE', | ||
cursor: 'pointer' | ||
}, | ||
@@ -55,0 +55,0 @@ |
@@ -35,3 +35,9 @@ 'use strict'; | ||
transition: 'left 0.1s', | ||
transitionTimingFunction: 'ease-in-out' | ||
transitionTimingFunction: 'ease-in-out', | ||
/* | ||
Prevent flickering while tapping on WebKit | ||
http://stackoverflow.com/a/3516243/837709 | ||
*/ | ||
WebkitTapHighlightColor: 'transparent' | ||
}, | ||
@@ -38,0 +44,0 @@ |
{ | ||
"name": "belle", | ||
"version": "2.0.0-rc2", | ||
"version": "2.0.0-rc3", | ||
"description": "Configurable React Components with great UX", | ||
@@ -36,26 +36,28 @@ "author": { | ||
"lint:eslint": "eslint ./", | ||
"lint:jscs": "jscs ./" | ||
"lint:jscs": "jscs ./", | ||
"alex": "alex README.md" | ||
}, | ||
"devDependencies": { | ||
"babel": "^5.8.23", | ||
"babel-core": "^5.8.25", | ||
"babel-eslint": "^4.1.3", | ||
"alex": "^1.5.0", | ||
"babel": "^5.8.29", | ||
"babel-core": "^5.8.33", | ||
"babel-eslint": "^4.1.6", | ||
"babel-jest": "^5.3.0", | ||
"babel-loader": "^5.3.2", | ||
"babel-loader": "^5.3.3", | ||
"babel-plugin-react-transform": "^1.1.1", | ||
"eslint": "^1.8.0", | ||
"eslint-config-airbnb": "0.1.0", | ||
"eslint-plugin-react": "^3.6.3", | ||
"jest-cli": "^0.7.0", | ||
"jscs": "^2.5.0", | ||
"react": "^0.14.2", | ||
"react-addons-test-utils": "^0.14.2", | ||
"react-dom": "^0.14.2", | ||
"eslint": "^1.10.1", | ||
"eslint-config-airbnb": "1.0.0", | ||
"eslint-plugin-react": "^3.10.0", | ||
"jest-cli": "^0.8.0", | ||
"jscs": "^2.6.0", | ||
"react": "^0.14.3", | ||
"react-addons-test-utils": "^0.14.3", | ||
"react-dom": "^0.14.3", | ||
"react-transform-catch-errors": "^1.0.0", | ||
"react-transform-hmr": "^1.0.1", | ||
"redbox-react": "^1.1.1", | ||
"webpack": "^1.12.2", | ||
"webpack-dev-middleware": "^1.2.0", | ||
"webpack-dev-server": "^1.12.1", | ||
"webpack-hot-middleware": "^2.4.1" | ||
"redbox-react": "^1.2.0", | ||
"webpack": "^1.12.9", | ||
"webpack-dev-middleware": "^1.4.0", | ||
"webpack-dev-server": "^1.14.0", | ||
"webpack-hot-middleware": "^2.5.0" | ||
}, | ||
@@ -62,0 +64,0 @@ "jest": { |
@@ -24,3 +24,3 @@ # Belle | ||
``` | ||
npm install belle@2.0.0-rc2 | ||
npm install belle@2.0.0-rc3 | ||
``` | ||
@@ -124,3 +124,3 @@ | ||
The user should see affects of his actions instantly. Any delay can cause confusion | ||
The user should see affects of their actions instantly. Any delay can cause confusion | ||
and frustration. While instant certainly is not always possible Belle strives to | ||
@@ -169,3 +169,3 @@ provide an experience close to instant. | ||
Special thanks to [https://github.com/jpuri](Jyoti Puri) for the tremendous amount of work she put into this endeavor. | ||
Special thanks to [Jyoti Puri](https://github.com/jpuri) for the tremendous amount of work she put into this endeavor. | ||
@@ -172,0 +172,0 @@ ## License |
Sorry, the diff of this file is not supported yet
384456
9131
22