Comparing version 0.0.30 to 0.0.31
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import {Card} from 'belle'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import {Button} from 'belle'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -7,55 +5,55 @@ import {Card} from 'belle'; | ||
const basicCodeExample = `<!-- basic card example --> | ||
<Card style={{ borderTop: '1px solid #f2f2f2' }}> | ||
Add any content here like paragraphs, images or other components … | ||
</Card>`; | ||
const imageCodeExample = `<!-- image card example --> | ||
<Card style={{ borderTop: '1px solid #f2f2f2', | ||
width: 265, | ||
padding: '20px 0' }}> | ||
<img src="images/ngorongoro_caldera_small.jpg" | ||
width="100%" /> | ||
</Card>`; | ||
export default class CardDocumentation extends Component { | ||
render() { | ||
return <div> | ||
return ( | ||
<div> | ||
<h2 style={ {marginTop: 0, marginBottom: 40} }>Card</h2> | ||
<h2 style={ {marginTop: 0, marginBottom: 40} }>Card</h2> | ||
<Card style={{ borderTop: '1px solid #f2f2f2' }}> | ||
Add any content here like paragraphs, images or other components … | ||
</Card> | ||
<Card style={{ borderTop: '1px solid #f2f2f2' }}> | ||
Add any content here like paragraphs, images or other components … | ||
</Card> | ||
<Code value={ basicCodeExample } style={ {marginTop: 40} } /> | ||
<Code value={ basicCodeExample } style={ {marginTop: 40} } /> | ||
<p style={{ marginTop: 40 }}> | ||
<i>Note</i>: The card is designed to work on non-white areas. To provide a | ||
nice appearance on white areas please change the box-shadow or borders. | ||
</p> | ||
<p style={{ marginTop: 40 }}> | ||
<i>Note</i>: The card is designed to work on non-white areas. To provide a | ||
nice appearance on white areas please change the box-shadow or borders. | ||
</p> | ||
<h3>Properties</h3> | ||
<h3>Properties</h3> | ||
<p> | ||
Any property valid for a HTML div like | ||
<span style={ {color: 'grey'} }> style, id, className, …</span> | ||
</p> | ||
<p> | ||
Any property valid for a HTML div like | ||
<span style={ {color: 'grey'} }> style, id, className, …</span> | ||
</p> | ||
<h3>More Examples</h3> | ||
<h3>More Examples</h3> | ||
<p>Card with a full-width image</p> | ||
<p>Card with a full-width image</p> | ||
<Card style={{ borderTop: '1px solid #f2f2f2', | ||
width: 265, | ||
padding: '20px 0' }}> | ||
<img src="images/ngorongoro_caldera_small.jpg" | ||
width="100%" /> | ||
</Card> | ||
<Card style={{ borderTop: '1px solid #f2f2f2', | ||
width: 265, | ||
padding: '20px 0' }}> | ||
<img src="images/ngorongoro_caldera_small.jpg" | ||
width="100%" /> | ||
</Card> | ||
<Code value={ imageCodeExample } style={ {marginTop: 40} } /> | ||
</div>; | ||
<Code value={ imageCodeExample } style={ {marginTop: 40} } /> | ||
</div> | ||
); | ||
} | ||
} | ||
const basicCodeExample = `<!-- basic card example --> | ||
<Card style={{ borderTop: '1px solid #f2f2f2' }}> | ||
Add any content here like paragraphs, images or other components … | ||
</Card>`; | ||
const imageCodeExample = `<!-- image card example --> | ||
<Card style={{ borderTop: '1px solid #f2f2f2', | ||
width: 265, | ||
padding: '20px 0' }}> | ||
<img src="images/ngorongoro_caldera_small.jpg" | ||
width="100%" /> | ||
</Card>`; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import {Choice, Toggle} from 'belle'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import highlightJs from 'highlight.js'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React from 'react'; | ||
@@ -4,0 +2,0 @@ import {omit} from 'underscore'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React from 'react'; | ||
@@ -32,5 +30,7 @@ import {Card, ComboBox, Option, Rating} from 'belle'; | ||
const currencyFilterFunc = function(inputValue, optionValue) { | ||
const babyNames = ['Palma', 'Paloma', 'Pamella', 'Paris', 'Patti', 'Paulina', 'Pearl', 'Pearlie']; | ||
const customFilterFunc = function(inputValue, optionValue) { | ||
if(inputValue && optionValue) { | ||
return optionValue.indexOf(inputValue) === 0; | ||
return optionValue.toLowerCase().indexOf(inputValue.toLowerCase()) === 0; | ||
} | ||
@@ -160,3 +160,3 @@ return false; | ||
<br /> | ||
default: true | ||
default: false | ||
</p> | ||
@@ -171,2 +171,20 @@ <p> | ||
<td style={ propertyNameStyle }> | ||
enableHint | ||
</td> | ||
</tr> | ||
<tr> | ||
<td style={ propertyDescriptionStyle }> | ||
<p> | ||
<i>Object</i> | ||
<br /> | ||
default: false | ||
</p> | ||
<p> | ||
Can be used to enable/disable showing hints to users in combo-box. | ||
</p> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td style={ propertyNameStyle }> | ||
filterFunc | ||
@@ -322,2 +340,23 @@ </td> | ||
<td style={ propertyNameStyle }> | ||
hintStyle | ||
</td> | ||
</tr> | ||
<tr> | ||
<td style={ propertyDescriptionStyle }> | ||
<p> | ||
<i>Object</i> | ||
<br /> | ||
optional | ||
</p> | ||
<p> | ||
Works like React's built-in style property. | ||
Manipulates the styling for underlying input which is suggesting | ||
the first option. This input is only visible of the property `enableHint` | ||
is enabled. | ||
</p> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td style={ propertyNameStyle }> | ||
wrapperProps | ||
@@ -378,6 +417,7 @@ </td> | ||
<h3>ComboBox with each option having an image and description</h3> | ||
<h3>ComboBox with each option having an image, description and caret</h3> | ||
<ComboBox placeholder = { 'Choose an Animal' } | ||
defaultValue = "Ant"> | ||
defaultValue = "Ant" | ||
displayCaret = { true }> | ||
{ | ||
@@ -426,3 +466,3 @@ animals.map(function(animal, index) { | ||
maxOptions = { 5 } | ||
filterFunc = { currencyFilterFunc }> | ||
filterFunc = { customFilterFunc }> | ||
{ | ||
@@ -451,2 +491,23 @@ currencies.map(function(currency, index) { | ||
<h3>ComboBox with custom filtering, and hints enabled</h3> | ||
<ComboBox enableHint = { true } | ||
filterFunc = { customFilterFunc } | ||
placeholder = { 'Select Baby Name' }> | ||
{ | ||
babyNames.map(function(name, index) { | ||
return ( | ||
<Option value={ name } | ||
key={ index }> | ||
{ name } | ||
</Option> | ||
); | ||
}) | ||
} | ||
</ComboBox> | ||
<Code value={ dataCodeExampleThreePartOne } style={ {marginTop: 40} } /> | ||
<Code value={ dataCodeExampleThreePartTwo } style={ {marginTop: 40} } /> | ||
</div>; | ||
@@ -473,3 +534,5 @@ } | ||
const dataCodeExampleOnePartTwo = `<ComboBox placeholder = { 'Choose an Animal' }> | ||
const dataCodeExampleOnePartTwo = `<ComboBox placeholder = { 'Choose an Animal' } | ||
defaultValue = "Ant" | ||
displayCaret = { true }> | ||
{ | ||
@@ -527,3 +590,3 @@ animals.map(function(animal, index) { | ||
maxOptions = { 5 } | ||
filterFunc = { currencyFilterFunc }> | ||
filterFunc = { customFilterFunc }> | ||
{ | ||
@@ -546,3 +609,3 @@ currencies.map(function(currency, index) { | ||
const dataCodeExampleTwoPartThree = `const currencyFilterFunc = function(inputValue, optionValue) { | ||
const dataCodeExampleTwoPartThree = `const customFilterFunc = function(inputValue, optionValue) { | ||
if(inputValue && optionValue) { | ||
@@ -554,5 +617,22 @@ return optionValue.indexOf(inputValue) === 0; | ||
const dataCodeExampleThreePartOne = `const babyNames = ['Palma', 'Paloma', 'Pamella', 'Paris', 'Patti', 'Paulina', 'Pearl', 'Pearlie'];`; | ||
const dataCodeExampleThreePartTwo = `<ComboBox enableHint = { true } | ||
filterFunc = { customFilterFunc } | ||
placeholder = { 'Select Baby Name' }> | ||
{ | ||
babyNames.map(function(name, index) { | ||
return ( | ||
<Option value={ name } | ||
key={ index }> | ||
{ name } | ||
</Option> | ||
); | ||
}) | ||
} | ||
</ComboBox>`; | ||
const htmlStructure = `<div style={ wrapperStyle }> | ||
<input style={ style }> | ||
</input> | ||
<input style={ hint } /> | ||
<input style={ style } /> | ||
<ul style={ menuStyle }> | ||
@@ -559,0 +639,0 @@ <li> |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import {Button, Card} from 'belle'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import Code from './Code'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import {Option, Select} from 'belle'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import {Option, Placeholder, Select} from 'belle'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React from 'react'; | ||
@@ -254,3 +252,3 @@ import {Card, Rating} from 'belle'; | ||
<td style={ propertyNameStyle }> | ||
characterProperties | ||
wrapperProps | ||
</td> | ||
@@ -266,2 +264,22 @@ </tr> | ||
<p> | ||
This object allows to provide any kind of valid properties for a | ||
div tag. It allows to extend the div wrapping the whole rating | ||
component. | ||
</p> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td style={ propertyNameStyle }> | ||
characterProps | ||
</td> | ||
</tr> | ||
<tr> | ||
<td style={ propertyDescriptionStyle }> | ||
<p> | ||
<i>Object</i> | ||
<br /> | ||
optional | ||
</p> | ||
<p> | ||
The property can be used to specify any other properties specific to rating character apart from styling. They will be applied to the span wrapping the character. | ||
@@ -268,0 +286,0 @@ </p> |
@@ -1,5 +0,1 @@ | ||
"use strict"; | ||
/* jslint node: true */ | ||
import React from 'react'; | ||
@@ -6,0 +2,0 @@ import {Route, DefaultRoute} from 'react-router'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import {Option, Placeholder, Select, Separator, TextInput} from 'belle'; |
@@ -1,6 +0,3 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
import {Option, Select, Separator} from 'belle'; | ||
import {map} from 'underscore'; | ||
import Code from './Code'; | ||
@@ -7,0 +4,0 @@ |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
var style = { | ||
@@ -4,0 +2,0 @@ |
@@ -1,4 +0,2 @@ | ||
"use strict"; | ||
import React, {Component} from 'react/addons'; | ||
import React from 'react/addons'; | ||
import {TextInput} from 'belle'; | ||
@@ -5,0 +3,0 @@ import Code from './Code'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
import React, {Component} from 'react'; | ||
@@ -4,0 +2,0 @@ import {Choice, Toggle} from 'belle'; |
{ | ||
"name": "belleDocumentation", | ||
"version": "0.0.30", | ||
"version": "0.0.31", | ||
"description": "Docuemtation for Belle", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -11,3 +11,3 @@ 'use strict'; | ||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; | ||
var _get = function get(_x2, _x3, _x4) { var _again = true; _function: while (_again) { var object = _x2, property = _x3, receiver = _x4; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x2 = parent; _x3 = property; _x4 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; | ||
@@ -78,3 +78,3 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
function sanitizePropertiesForInput(properties) { | ||
return (0, _underscore.omit)(properties, ['ref', 'value', 'valueLink', 'defaultValue', 'placeholder', 'disabled', 'className', 'style', 'onUpdate', 'tabIndex', 'onBlur', 'onFocus', 'onKeyDown', 'aria-disabled', 'aria-autocomplete', 'children']); | ||
return (0, _underscore.omit)(properties, ['ref', 'value', 'valueLink', 'defaultValue', 'placeholder', 'disabled', 'hintStyle', 'className', 'style', 'onUpdate', 'tabIndex', 'onBlur', 'onFocus', 'onKeyDown', 'aria-disabled', 'aria-autocomplete', 'children']); | ||
} | ||
@@ -122,3 +122,3 @@ | ||
inputValue: inputValue, | ||
tempValue: undefined, | ||
hint: undefined, | ||
filteredOptions: this.filterOptions(inputValue), | ||
@@ -134,2 +134,43 @@ wrapperProperties: sanitizePropertiesForWrapper(properties.wrapperProps), | ||
_createClass(ComboBox, [{ | ||
key: '_getHint', | ||
/** | ||
* This method will calculate the hint that should be present in comboBox at some point in time. Rules: | ||
* 1. If menu is not open hint is undefined | ||
* 2. If menu is open but there are no filteredOptions hint is undefined | ||
* 3. If if some option is highlighted hint is equal to its value | ||
* 4. If no option is highlighted but some value is present in input box hint is equal to value of first filteredOptions | ||
* If user has typed some text in input box and there is a hint(according to above calculations), the starting of hint | ||
* is replaced by the text input by user ( this is to make sure that case of letters in hint is same as that in input box | ||
* value and overlap is perfect. | ||
* todo: simplify logic in method below | ||
*/ | ||
value: function _getHint() { | ||
if (this.state.isOpen) { | ||
var filteredOptions = this.state.filteredOptions; | ||
if (filteredOptions && filteredOptions.length > 0) { | ||
var hint = undefined; | ||
var focusedOptionIndex = this.state.focusedOptionIndex; | ||
var inputValue = this.state.inputValue; | ||
if (focusedOptionIndex >= 0) { | ||
hint = filteredOptions[focusedOptionIndex].props.value; | ||
} else if (inputValue && inputValue.length > 0) { | ||
hint = filteredOptions[0].props.value; | ||
} | ||
if (hint) { | ||
if (inputValue && inputValue.length > 0) { | ||
var position = hint.toLowerCase().indexOf(inputValue.toLowerCase()); | ||
if (position === 0) { | ||
return inputValue + hint.substr(inputValue.length, hint.length - inputValue.length); | ||
} else if (position === -1) { | ||
return hint; | ||
} | ||
} else { | ||
return hint; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'componentWillMount', | ||
@@ -211,3 +252,3 @@ | ||
*/ | ||
value: function _onTouchCancelAtOption(event) { | ||
value: function _onTouchCancelAtOption() { | ||
if (!this.props.disabled) { | ||
@@ -229,3 +270,3 @@ this._touchStartedAt = undefined; | ||
focusedOptionIndex: undefined, | ||
tempValue: undefined | ||
hint: undefined | ||
}); | ||
@@ -247,4 +288,3 @@ } | ||
this.setState({ | ||
isOpen: true, | ||
focusedOptionIndex: 0 | ||
isOpen: true | ||
}); | ||
@@ -267,3 +307,4 @@ } | ||
this.setState({ | ||
focusedOptionIndex: index | ||
focusedOptionIndex: index, | ||
hint: ComboBox._getHint(this.state.filteredOptions, index, this.state.inputValue, true) | ||
}); | ||
@@ -278,6 +319,7 @@ } | ||
*/ | ||
value: function _onMouseLeaveAtOption(event) { | ||
value: function _onMouseLeaveAtOption() { | ||
if (!this.props.disabled) { | ||
this.setState({ | ||
focusedOptionIndex: undefined | ||
focusedOptionIndex: undefined, | ||
hint: undefined | ||
}); | ||
@@ -303,9 +345,8 @@ } | ||
* Handle keyDown in input (when input is focused): | ||
* 1. ComboBox is closed and ArrowDown/ ArrowUp/ SpaceKey is pressed -> open the ComboBox | ||
* 1. ComboBox is closed and ArrowDown/ ArrowUp is pressed -> open the ComboBox | ||
* 2. ComboBox is opened and ArrowDown is pressed -> highlight next option | ||
* 3. ComboBox is opened and ArrowUp is pressed -> highlight previous option | ||
* 4. ComboBox is opened and Enter/ Tab is pressed -> update input value to value of option | ||
* 5. ComboBox is opened and Esc is pressed -> close ComboBox | ||
* 6. ComboBox is opened and any key is pressed immediately after pressing ArrowUp or DownKey | ||
* -> content of highlighted option will be copied over to combo-box | ||
* 4. ComboBox is opened and ArrowRight is pressed -> value of hint is copied over to inputBox | ||
* 5. ComboBox is opened and Enter/ Tab is pressed -> update input value to value of option | ||
* 6. ComboBox is opened and Esc is pressed -> close ComboBox | ||
*/ | ||
@@ -317,3 +358,5 @@ value: function _onKeyDown(event) { | ||
event.preventDefault(); | ||
this.setState({ isOpen: true, focusedOptionIndex: 0 }); | ||
this.setState({ | ||
isOpen: true | ||
}); | ||
} | ||
@@ -327,2 +370,8 @@ } else { | ||
this._onArrowUpKeyDown(); | ||
} else if (event.key === 'ArrowRight') { | ||
event.preventDefault(); | ||
var hint = this._getHint(); | ||
if (hint) { | ||
this._userUpdateValue(hint); | ||
} | ||
} else if (event.key === 'Enter') { | ||
@@ -337,12 +386,7 @@ event.preventDefault(); | ||
event.preventDefault(); | ||
this.setState({ isOpen: false, focusedOptionIndex: undefined, tempValue: undefined }); | ||
} else { | ||
var tempValue = this.state.tempValue; | ||
if (this.state.tempValue) { | ||
this.setState({ | ||
tempValue: undefined, | ||
inputValue: tempValue, | ||
filteredOptions: this.filterOptions(tempValue) | ||
}); | ||
} | ||
this.setState({ | ||
isOpen: false, | ||
focusedOptionIndex: undefined, | ||
hint: undefined | ||
}); | ||
} | ||
@@ -369,4 +413,3 @@ } | ||
this.setState({ | ||
focusedOptionIndex: index, | ||
tempValue: this.state.filteredOptions[index].props.value | ||
focusedOptionIndex: index | ||
}); | ||
@@ -388,4 +431,3 @@ } | ||
this.setState({ | ||
focusedOptionIndex: index, | ||
tempValue: this.state.filteredOptions[index].props.value | ||
focusedOptionIndex: index | ||
}); | ||
@@ -401,3 +443,5 @@ } | ||
value: function _onEnterOrTabKeyDown() { | ||
this._triggerChange(this.state.filteredOptions[this.state.focusedOptionIndex].props.value); | ||
if (this.state.focusedOptionIndex >= 0) { | ||
this._triggerChange(this.state.filteredOptions[this.state.focusedOptionIndex].props.value); | ||
} | ||
} | ||
@@ -418,3 +462,3 @@ }, { | ||
isOpen: false, | ||
tempValue: undefined, | ||
hint: undefined, | ||
focusedOptionIndex: undefined | ||
@@ -425,3 +469,3 @@ }); | ||
isOpen: false, | ||
tempValue: undefined, | ||
hint: undefined, | ||
focusedOptionIndex: undefined | ||
@@ -432,3 +476,3 @@ }); | ||
inputValue: value, | ||
tempValue: undefined, | ||
hint: undefined, | ||
isOpen: false, | ||
@@ -448,3 +492,17 @@ focusedOptionIndex: undefined, | ||
/** | ||
* The function is called when user inputs a value in the input box. Function will do following: | ||
* The function is called when user type/ paste value in the input box. | ||
*/ | ||
value: function _onChange(event) { | ||
var value = event.target.value; | ||
this._userUpdateValue(value); | ||
} | ||
}, { | ||
key: '_userUpdateValue', | ||
/** | ||
* The function is called when user inputs a value in the input box. This can be done by: | ||
* 1. typing/ pasting value into input box | ||
* 2. pressing arrowRight key when there is some hint in the input box | ||
* | ||
* Function will do following: | ||
* 1. Open the options | ||
@@ -454,5 +512,3 @@ * 2. Change value of input depending on whether its has value, defaultValue or valueLink property | ||
*/ | ||
value: function _onChange(event) { | ||
var value = event.target.value; | ||
value: function _userUpdateValue(value) { | ||
if ((0, _underscore.has)(this.props, 'valueLink')) { | ||
@@ -462,3 +518,3 @@ this.props.valueLink.requestChange(value); | ||
isOpen: true, | ||
focusedOptionIndex: 0 | ||
focusedOptionIndex: undefined | ||
}); | ||
@@ -468,10 +524,11 @@ } else if ((0, _underscore.has)(this.props, 'value')) { | ||
isOpen: true, | ||
focusedOptionIndex: 0 | ||
focusedOptionIndex: undefined | ||
}); | ||
} else { | ||
var filteredOptions = this.filterOptions(value); | ||
this.setState({ | ||
inputValue: value, | ||
isOpen: true, | ||
focusedOptionIndex: 0, | ||
filteredOptions: this.filterOptions(value) | ||
filteredOptions: filteredOptions, | ||
focusedOptionIndex: undefined | ||
}); | ||
@@ -516,4 +573,7 @@ } | ||
var hint = this.props.enableHint ? this._getHint() : undefined; | ||
var placeHolder = !hint ? this.props.placeholder : undefined; | ||
var wrapperStyle = (0, _underscore.extend)({}, _styleComboBox2['default'].wrapperStyle, this.props.wrapperStyle); | ||
var inputStyle = (0, _underscore.extend)({}, _styleComboBox2['default'].style, this.props.style); | ||
var hintStyle = (0, _underscore.extend)({}, _styleComboBox2['default'].hintStyle, this.props.hintStyle); | ||
var menuStyle = (0, _underscore.extend)({}, _styleComboBox2['default'].menuStyle, this.props.menuStyle); | ||
@@ -528,7 +588,7 @@ | ||
if (this.props.disabled) { | ||
inputStyle = (0, _underscore.extend)({}, inputStyle, _styleComboBox2['default'].disabledCaretToOpenStyle); | ||
hintStyle = (0, _underscore.extend)({}, hintStyle, _styleComboBox2['default'].disabledCaretToOpenStyle); | ||
} else if (this.state.isOpen) { | ||
inputStyle = (0, _underscore.extend)({}, inputStyle, _styleComboBox2['default'].caretToCloseStyle); | ||
hintStyle = (0, _underscore.extend)({}, hintStyle, _styleComboBox2['default'].caretToCloseStyle); | ||
} else { | ||
inputStyle = (0, _underscore.extend)({}, inputStyle, _styleComboBox2['default'].caretToOpenStyle); | ||
hintStyle = (0, _underscore.extend)({}, hintStyle, _styleComboBox2['default'].caretToOpenStyle); | ||
} | ||
@@ -547,6 +607,10 @@ } | ||
}, this.state.wrapperProperties), | ||
_react2['default'].createElement('input', { style: hintStyle, | ||
value: hint, | ||
tabIndex: -1, | ||
readOnly: true }), | ||
_react2['default'].createElement('input', _extends({ disabled: this.props.disabled, | ||
'aria-disabled': this.props.disabled, | ||
value: this.state.tempValue || this.state.inputValue, | ||
placeholder: this.props.placeholder, | ||
value: this.state.inputValue, | ||
placeholder: placeHolder, | ||
style: inputStyle, | ||
@@ -594,2 +658,23 @@ className: inputClassName, | ||
} | ||
}], [{ | ||
key: '_getHint', | ||
value: function _getHint(filteredOptions, index, inputValue) { | ||
var isOptionSelected = arguments[3] === undefined ? false : arguments[3]; | ||
var hint = ''; | ||
if (filteredOptions && filteredOptions.length > 0 && !((inputValue === undefined || inputValue === null || inputValue.length === 0) && !isOptionSelected)) { | ||
var optionValue = filteredOptions[index].props.value; | ||
if (inputValue) { | ||
var position = optionValue.toLowerCase().indexOf(inputValue.toLowerCase()); | ||
if (position === -1) { | ||
hint = optionValue; | ||
} else if (position === 0) { | ||
hint = inputValue + optionValue.substr(inputValue.length, optionValue.length - inputValue.length); | ||
} | ||
} else { | ||
hint = optionValue; | ||
} | ||
} | ||
return hint; | ||
} | ||
}]); | ||
@@ -624,2 +709,3 @@ | ||
wrapperStyle: _react2['default'].PropTypes.object, | ||
hintStyle: _react2['default'].PropTypes.object, | ||
menuStyle: _react2['default'].PropTypes.object, | ||
@@ -631,2 +717,3 @@ focusStyle: _react2['default'].PropTypes.object, | ||
displayCaret: _react2['default'].PropTypes.bool, | ||
enableHint: _react2['default'].PropTypes.bool, | ||
filterFunc: _react2['default'].PropTypes.func, | ||
@@ -638,3 +725,4 @@ 'aria-label': _react2['default'].PropTypes.string | ||
disabled: false, | ||
displayCaret: true, | ||
displayCaret: false, | ||
enableHint: false, | ||
'aria-label': 'ComboBox', | ||
@@ -641,0 +729,0 @@ filterFunc: filterFunc |
@@ -47,4 +47,4 @@ 'use strict'; | ||
*/ | ||
function sanitizeWrapperProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['className', 'onKeyDown', 'onClick', 'onMouseEnter', 'onMouseMove', 'onMouseLeave', 'onMouseUp', 'onMouseDown', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel', 'onBlur', 'onFocus', 'tabIndex', 'aria-label', 'aria-valuemax', 'aria-valuemin', 'aria-valuenow', 'aria-disabled', 'style', 'focusStyle', 'disabledStyle', 'characterStyle', 'activeCharacterStyle', 'hoverCharacterStyle', 'characterProperties']); | ||
function sanitizeWrapperProps(props) { | ||
return (0, _underscore.omit)(props, ['className', 'onKeyDown', 'onClick', 'onMouseEnter', 'onMouseMove', 'onMouseLeave', 'onMouseUp', 'onMouseDown', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel', 'onBlur', 'onFocus', 'tabIndex', 'aria-label', 'aria-valuemax', 'aria-valuemin', 'aria-valuenow', 'aria-disabled', 'style', 'focusStyle', 'disabledStyle', 'characterStyle', 'activeCharacterStyle', 'hoverCharacterStyle', 'characterProps']); | ||
} | ||
@@ -55,4 +55,4 @@ | ||
*/ | ||
function sanitizeCharacterProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['data-belle-value', 'style']); | ||
function sanitizeCharacterProps(props) { | ||
return (0, _underscore.omit)(props, ['data-belle-value', 'style']); | ||
} | ||
@@ -63,8 +63,8 @@ | ||
*/ | ||
function updatePseudoClassStyle(ratingWrapperStyleId, properties) { | ||
function updatePseudoClassStyle(ratingWrapperStyleId, props) { | ||
var ratingFocusStyle = undefined; | ||
if (properties.preventFocusStyleForTouchAndClick) { | ||
if (props.preventFocusStyleForTouchAndClick) { | ||
ratingFocusStyle = { outline: 0 }; | ||
} else { | ||
ratingFocusStyle = (0, _underscore.extend)({}, _styleRatingJs2['default'].focusStyle, properties.focusStyle); | ||
ratingFocusStyle = (0, _underscore.extend)({}, _styleRatingJs2['default'].focusStyle, props.focusStyle); | ||
} | ||
@@ -87,6 +87,6 @@ var styles = [{ | ||
var Rating = (function (_Component) { | ||
function Rating(properties) { | ||
function Rating(props) { | ||
_classCallCheck(this, Rating); | ||
_get(Object.getPrototypeOf(Rating.prototype), 'constructor', this).call(this, properties); | ||
_get(Object.getPrototypeOf(Rating.prototype), 'constructor', this).call(this, props); | ||
@@ -106,4 +106,4 @@ var value = undefined; | ||
focusedValue: undefined, | ||
generalProperties: sanitizeWrapperProperties(properties), | ||
characterProperties: sanitizeCharacterProperties(properties.characterProperties), | ||
generalProps: sanitizeWrapperProps(props), | ||
characterProps: sanitizeCharacterProps(props.characterProps), | ||
isFocus: false, | ||
@@ -129,16 +129,16 @@ isActive: false | ||
key: 'componentWillReceiveProps', | ||
value: function componentWillReceiveProps(properties) { | ||
value: function componentWillReceiveProps(props) { | ||
var newState = { | ||
wrapperProperties: sanitizeWrapperProperties(properties), | ||
characterProperties: sanitizeCharacterProperties(properties.characterProperties) | ||
wrapperProps: sanitizeWrapperProps(props), | ||
characterProps: sanitizeCharacterProps(props.characterProps) | ||
}; | ||
if (properties.valueLink) { | ||
newState.value = properties.valueLink.value; | ||
} else if (properties.value) { | ||
newState.value = properties.value; | ||
if (props.valueLink) { | ||
newState.value = props.valueLink.value; | ||
} else if (props.value) { | ||
newState.value = props.value; | ||
} | ||
this.setState(newState); | ||
updatePseudoClassStyle(this._styleId, properties); | ||
updatePseudoClassStyle(this._styleId, props); | ||
} | ||
@@ -591,3 +591,3 @@ }, { | ||
'aria-disabled': this.props.disabled | ||
}, this.state.wrapperProperties), | ||
}, this.state.wrapperProps), | ||
_react2['default'].Children.map([1, 2, 3, 4, 5], function (value) { | ||
@@ -599,3 +599,3 @@ var ratingStyle = currentValue >= value ? characterStyle : {}; | ||
style: ratingStyle | ||
}, _this.state.characterProperties), | ||
}, _this.state.characterProps), | ||
_this.props.character | ||
@@ -625,3 +625,3 @@ ); | ||
character: _react2['default'].PropTypes.string, | ||
characterProperties: _react2['default'].PropTypes.object, | ||
characterProps: _react2['default'].PropTypes.object, | ||
preventFocusStyleForTouchAndClick: _react2['default'].PropTypes.bool, | ||
@@ -628,0 +628,0 @@ 'aria-label': _react2['default'].PropTypes.string, |
@@ -47,2 +47,127 @@ 'use strict'; | ||
/** | ||
* Returns true if the provided property is a Placeholder component from Belle. | ||
*/ | ||
function isPlaceholder(reactElement) { | ||
return (0, _utilsIsComponentOfTypeJs2['default'])('Placeholder', reactElement); | ||
} | ||
/** | ||
* Returns true if the provided property is a Option component from Belle. | ||
*/ | ||
function isOption(reactElement) { | ||
return (0, _utilsIsComponentOfTypeJs2['default'])('Option', reactElement); | ||
} | ||
/** | ||
* Returns true if the provided property is a Separator component from Belle. | ||
*/ | ||
function isSeparator(reactElement) { | ||
return (0, _utilsIsComponentOfTypeJs2['default'])('Separator', reactElement); | ||
} | ||
/** | ||
* Returns the index of the entry with a certain value from the component's | ||
* children. | ||
* | ||
* The index search includes only option components. | ||
*/ | ||
var findIndexOfFocusedOption = function findIndexOfFocusedOption(component) { | ||
return (0, _underscore.findIndex)((0, _underscore.filter)(component.props.children, isOption), function (element) { | ||
return element.props.value === component.state.focusedOptionValue; | ||
}); | ||
}; | ||
/** | ||
* Verifies that the provided property is an Option or Placeholder component from Belle. | ||
*/ | ||
function optionOrPlaceholderOrSeparatorPropType(props, propName, componentName) { | ||
if (!(props[propName] && isOption(props[propName]) || isPlaceholder(props[propName]) || isSeparator(props[propName]))) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected an Option or Placeholder component from Belle.'); | ||
} | ||
} | ||
/** | ||
* Verifies that the children is an array containing only Options & at maximum | ||
* one Placeholder. | ||
*/ | ||
function validateArrayOfOptionsAndMaximumOnePlaceholder(props, propName, componentName) { | ||
var error = _react2['default'].PropTypes.arrayOf(optionOrPlaceholderOrSeparatorPropType).isRequired(props, propName, componentName); | ||
if (error) return error; | ||
var placeholders = (0, _underscore.filter)(props[propName], isPlaceholder); | ||
if ((0, _underscore.size)(placeholders) > 1) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected only one Placeholder component.'); | ||
} | ||
} | ||
/** | ||
* Update hover style for the speficied styleId. | ||
* | ||
* @param styleId {string} - a unique id that exists as class attribute in the DOM | ||
* @param properties {object} - the components properties optionally containing hoverStyle | ||
*/ | ||
function updatePseudoClassStyle(styleId, properties) { | ||
var hoverStyle = (0, _underscore.extend)({}, _styleSelect2['default'].hoverStyle, properties.hoverStyle); | ||
var disabledHoverStyle = (0, _underscore.extend)({}, _styleSelect2['default'].disabledHoverStyle, properties.disabledHoverStyle); | ||
var styles = [{ | ||
id: styleId, | ||
style: hoverStyle, | ||
pseudoClass: 'hover' | ||
}, { | ||
id: styleId, | ||
style: disabledHoverStyle, | ||
pseudoClass: 'hover', | ||
disabled: true | ||
}]; | ||
(0, _utilsInjectStyle.injectStyles)(styles); | ||
} | ||
/** | ||
* Returns true in case there one more element in the list. | ||
*/ | ||
var hasNext = function hasNext(list, currentIndex) { | ||
return currentIndex + 2 <= list.length; | ||
}; | ||
/** | ||
* Returns true in case there is one previous element in the list. | ||
*/ | ||
var hasPrevious = function hasPrevious(list, currentIndex) { | ||
return currentIndex - 1 >= 0; | ||
}; | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div of | ||
* the selected option. | ||
*/ | ||
function sanitizePropertiesForSelectedOptionWrapper(properties) { | ||
return (0, _underscore.omit)(properties, ['onClick', 'style', 'className', 'ref', 'shouldPositionOptions', 'positionOptions', 'focusStyle', 'hoverStyle', 'wrapperStyle', 'menuStyle', 'caretToOpenStyle', 'caretToCloseStyle', 'disabledCaretToOpenStyle', 'value', 'defaultValue', 'onUpdate', 'valueLink', 'role', 'aria-expanded', 'id', 'onTouchStart', 'onTouchEnd', 'onTouchCancel', 'disabledStyle', 'disabledHoverStyle']); | ||
} | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div of | ||
* the selected option. | ||
*/ | ||
function sanitizePropertiesForWrapper(wrapperProperties) { | ||
return (0, _underscore.omit)(wrapperProperties, ['style', 'ref', 'tabIndex', 'onKeyDown', 'onBlur', 'onFocus']); | ||
} | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div of | ||
* the selected option. | ||
*/ | ||
function sanitizePropertiesForMenu(menuProperties) { | ||
return (0, _underscore.omit)(menuProperties, ['style', 'ref', 'aria-labelledby', 'role']); | ||
} | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div of | ||
* the selected option. | ||
*/ | ||
function sanitizePropertiesForCaret(caretProperties) { | ||
return (0, _underscore.omit)(caretProperties, ['style', 'ref']); | ||
} | ||
/** | ||
* Select component. | ||
@@ -82,4 +207,4 @@ * | ||
var selectedValue = undefined, | ||
focusedOptionValue = undefined; | ||
var selectedValue = undefined; | ||
var focusedOptionValue = undefined; | ||
@@ -119,2 +244,15 @@ if ((0, _underscore.has)(properties, 'valueLink')) { | ||
_createClass(Select, [{ | ||
key: 'componentWillMount', | ||
/** | ||
* Generates the style-id & inject the focus & hover style. | ||
* | ||
* The style-id is based on React's unique DOM node id. | ||
*/ | ||
value: function componentWillMount() { | ||
var id = this._reactInternalInstance._rootNodeID.replace(/\./g, '-'); | ||
this._styleId = 'style-id' + id; | ||
updatePseudoClassStyle(this._styleId, this.props); | ||
} | ||
}, { | ||
key: 'componentWillReceiveProps', | ||
@@ -130,3 +268,2 @@ value: function componentWillReceiveProps(properties) { | ||
var value = undefined; | ||
if ((0, _underscore.has)(properties, 'valueLink')) { | ||
@@ -144,24 +281,2 @@ newState.selectedValue = properties.valueLink.value; | ||
}, { | ||
key: 'componentWillMount', | ||
/** | ||
* Generates the style-id & inject the focus & hover style. | ||
* | ||
* The style-id is based on React's unique DOM node id. | ||
*/ | ||
value: function componentWillMount() { | ||
var id = this._reactInternalInstance._rootNodeID.replace(/\./g, '-'); | ||
this._styleId = 'style-id' + id; | ||
updatePseudoClassStyle(this._styleId, this.props); | ||
} | ||
}, { | ||
key: 'componentWillUnmount', | ||
/** | ||
* Remove a component's associated styles whenever it gets removed from the DOM. | ||
*/ | ||
value: function componentWillUnmount() { | ||
(0, _utilsInjectStyle.removeStyle)(this._styleId); | ||
} | ||
}, { | ||
key: 'componentWillUpdate', | ||
@@ -210,2 +325,11 @@ | ||
}, { | ||
key: 'componentWillUnmount', | ||
/** | ||
* Remove a component's associated styles whenever it gets removed from the DOM. | ||
*/ | ||
value: function componentWillUnmount() { | ||
(0, _utilsInjectStyle.removeStyle)(this._styleId); | ||
} | ||
}, { | ||
key: '_onTouchStartAtOption', | ||
@@ -245,3 +369,3 @@ | ||
*/ | ||
value: function _onTouchMoveAtOption(event) { | ||
value: function _onTouchMoveAtOption() { | ||
var menuNode = _react2['default'].findDOMNode(this.refs.menu); | ||
@@ -258,3 +382,3 @@ if (menuNode.scrollTop !== this._scrollTopPosition) { | ||
*/ | ||
value: function _onTouchEndAtOption(event) { | ||
value: function _onTouchEndAtOption() { | ||
if (this._touchStartedAt && !this._scrollActive) { | ||
@@ -276,3 +400,3 @@ var entry = event.currentTarget.querySelector('[data-belle-value]'); | ||
*/ | ||
value: function _onTouchCancelAtOption(event) { | ||
value: function _onTouchCancelAtOption() { | ||
this._touchStartedAt = undefined; | ||
@@ -291,33 +415,2 @@ } | ||
}, { | ||
key: '_triggerChange', | ||
/** | ||
* After an option has been selected the menu gets closed and the | ||
* selection processed. | ||
* | ||
* Depending on the component's properties the value gets updated and the | ||
* provided change callback for onUpdate or valueLink is called. | ||
*/ | ||
value: function _triggerChange(value) { | ||
if ((0, _underscore.has)(this.props, 'valueLink')) { | ||
this.props.valueLink.requestChange(value); | ||
this.setState({ | ||
isOpen: false | ||
}); | ||
} else if ((0, _underscore.has)(this.props, 'value')) { | ||
this.setState({ | ||
isOpen: false | ||
}); | ||
} else { | ||
this.setState({ | ||
focusedOptionValue: value, | ||
selectedValue: value, | ||
isOpen: false | ||
}); | ||
} | ||
if (this.props.onUpdate) { | ||
this.props.onUpdate({ value: value }); | ||
} | ||
} | ||
}, { | ||
key: '_onBlur', | ||
@@ -336,4 +429,4 @@ | ||
if (this.props.wrapperProperties && this.props.wrapperProperties.onBlur) { | ||
this.props.wrapperProperties.onBlur(event); | ||
if (this.props.wrapperProps && this.props.wrapperProps.onBlur) { | ||
this.props.wrapperProps.onBlur(event); | ||
} | ||
@@ -354,4 +447,4 @@ } | ||
if (this.props.wrapperProperties && this.props.wrapperProperties.onFocus) { | ||
this.props.wrapperProperties.onFocus(event); | ||
if (this.props.wrapperProps && this.props.wrapperProps.onFocus) { | ||
this.props.wrapperProps.onFocus(event); | ||
} | ||
@@ -374,27 +467,8 @@ } | ||
}, { | ||
key: '_toggleMenuOnClick', | ||
key: '_onTouchStartToggleMenu', | ||
/** | ||
* Toggle the menu after a user clicked on it. | ||
*/ | ||
value: function _toggleMenuOnClick(event) { | ||
if (!this.props.disabled) { | ||
if (this.state.isOpen) { | ||
this.setState({ isOpen: false }); | ||
} else { | ||
this.setState({ isOpen: true }); | ||
} | ||
} | ||
if (this.props.onClick) { | ||
this.props.onClick(event); | ||
} | ||
} | ||
}, { | ||
key: '_initiateToggleMenuOnTouchStart', | ||
/** | ||
* Initiate the toggle for the menu. | ||
*/ | ||
value: function _initiateToggleMenuOnTouchStart(event) { | ||
value: function _onTouchStartToggleMenu(event) { | ||
if (event.touches.length === 1) { | ||
@@ -411,3 +485,3 @@ this.setState({ isTouchedToToggle: true }); | ||
}, { | ||
key: '_toggleMenuOnTouchEnd', | ||
key: '_onTouchEndToggleMenu', | ||
@@ -418,3 +492,3 @@ /** | ||
*/ | ||
value: function _toggleMenuOnTouchEnd(event) { | ||
value: function _onTouchEndToggleMenu(event) { | ||
// In case touch events are used preventDefault is applied to avoid | ||
@@ -430,3 +504,3 @@ // triggering the click event which would cause trouble for toggling. | ||
var wrapperNode = _react2['default'].findDOMNode(this.refs.wrapper); | ||
if (document.activeElement != wrapperNode) { | ||
if (document.activeElement !== wrapperNode) { | ||
wrapperNode.focus(); | ||
@@ -449,3 +523,3 @@ } | ||
}, { | ||
key: '_cancelToggleMenuOnTouchCancel', | ||
key: '_onTouchCancelToggleMenu', | ||
@@ -455,3 +529,3 @@ /** | ||
*/ | ||
value: function _cancelToggleMenuOnTouchCancel(event) { | ||
value: function _onTouchCancelToggleMenu(event) { | ||
this.setState({ isTouchedToToggle: false }); | ||
@@ -546,3 +620,2 @@ | ||
if ((0, _underscore.filter)(this.props.children, isOption).length > 0) { | ||
if (!this.state.isOpen) { | ||
@@ -576,7 +649,57 @@ if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === ' ') { | ||
if (this.props.wrapperProperties && this.props.wrapperProperties.onKeyDown) { | ||
this.props.wrapperProperties.onKeyDown(event); | ||
if (this.props.wrapperProps && this.props.wrapperProps.onKeyDown) { | ||
this.props.wrapperProps.onKeyDown(event); | ||
} | ||
} | ||
}, { | ||
key: '_onClickToggleMenu', | ||
/** | ||
* Toggle the menu after a user clicked on it. | ||
*/ | ||
value: function _onClickToggleMenu(event) { | ||
if (!this.props.disabled) { | ||
if (this.state.isOpen) { | ||
this.setState({ isOpen: false }); | ||
} else { | ||
this.setState({ isOpen: true }); | ||
} | ||
} | ||
if (this.props.onClick) { | ||
this.props.onClick(event); | ||
} | ||
} | ||
}, { | ||
key: '_triggerChange', | ||
/** | ||
* After an option has been selected the menu gets closed and the | ||
* selection processed. | ||
* | ||
* Depending on the component's properties the value gets updated and the | ||
* provided change callback for onUpdate or valueLink is called. | ||
*/ | ||
value: function _triggerChange(value) { | ||
if ((0, _underscore.has)(this.props, 'valueLink')) { | ||
this.props.valueLink.requestChange(value); | ||
this.setState({ | ||
isOpen: false | ||
}); | ||
} else if ((0, _underscore.has)(this.props, 'value')) { | ||
this.setState({ | ||
isOpen: false | ||
}); | ||
} else { | ||
this.setState({ | ||
focusedOptionValue: value, | ||
selectedValue: value, | ||
isOpen: false | ||
}); | ||
} | ||
if (this.props.onUpdate) { | ||
this.props.onUpdate({ value: value }); | ||
} | ||
} | ||
}, { | ||
key: 'render', | ||
@@ -600,3 +723,3 @@ value: function render() { | ||
var selectedEntry = (0, _underscore.find)(this.props.children, function (entry) { | ||
return entry.props.value == _this.state.selectedValue; | ||
return entry.props.value === _this.state.selectedValue; | ||
}); | ||
@@ -658,6 +781,6 @@ | ||
'div', | ||
_extends({ onClick: this._toggleMenuOnClick.bind(this), | ||
onTouchStart: this._initiateToggleMenuOnTouchStart.bind(this), | ||
onTouchEnd: this._toggleMenuOnTouchEnd.bind(this), | ||
onTouchCancel: this._cancelToggleMenuOnTouchCancel.bind(this), | ||
_extends({ onClick: this._onClickToggleMenu.bind(this), | ||
onTouchStart: this._onTouchStartToggleMenu.bind(this), | ||
onTouchEnd: this._onTouchEndToggleMenu.bind(this), | ||
onTouchCancel: this._onTouchCancelToggleMenu.bind(this), | ||
style: selectedOptionWrapperStyle, | ||
@@ -683,3 +806,3 @@ className: (0, _utilsUnionClassNames2['default'])(this.props.className, this._styleId), | ||
if (isOption(entry)) { | ||
var isHovered = entry.props.value == _this.state.focusedOptionValue; | ||
var isHovered = entry.props.value === _this.state.focusedOptionValue; | ||
var option = _react2['default'].addons.cloneWithProps(entry, { | ||
@@ -748,3 +871,7 @@ _isHovered: isHovered | ||
disabledHoverStyle: _react2['default'].PropTypes.object, | ||
disabledCaretToOpenStyle: _react2['default'].PropTypes.object | ||
disabledCaretToOpenStyle: _react2['default'].PropTypes.object, | ||
onClick: _react2['default'].PropTypes.func, | ||
onTouchCancel: _react2['default'].PropTypes.func, | ||
onTouchEnd: _react2['default'].PropTypes.func, | ||
onTouchStart: _react2['default'].PropTypes.func | ||
}; | ||
@@ -757,129 +884,3 @@ | ||
}; | ||
/** | ||
* Returns the index of the entry with a certain value from the component's | ||
* children. | ||
* | ||
* The index search includes only option components. | ||
*/ | ||
var findIndexOfFocusedOption = function findIndexOfFocusedOption(component) { | ||
return (0, _underscore.findIndex)((0, _underscore.filter)(component.props.children, isOption), function (element) { | ||
return element.props.value === component.state.focusedOptionValue; | ||
}); | ||
}; | ||
/** | ||
* Returns true if the provided property is a Placeholder component from Belle. | ||
*/ | ||
function isPlaceholder(reactElement) { | ||
return (0, _utilsIsComponentOfTypeJs2['default'])('Placeholder', reactElement); | ||
} | ||
/** | ||
* Returns true if the provided property is a Option component from Belle. | ||
*/ | ||
function isOption(reactElement) { | ||
return (0, _utilsIsComponentOfTypeJs2['default'])('Option', reactElement); | ||
} | ||
/** | ||
* Returns true if the provided property is a Separator component from Belle. | ||
*/ | ||
function isSeparator(reactElement) { | ||
return (0, _utilsIsComponentOfTypeJs2['default'])('Separator', reactElement); | ||
} | ||
/** | ||
* Verifies that the children is an array containing only Options & at maximum | ||
* one Placeholder. | ||
*/ | ||
function validateArrayOfOptionsAndMaximumOnePlaceholder(props, propName, componentName) { | ||
var error = _react2['default'].PropTypes.arrayOf(optionOrPlaceholderOrSeparatorPropType).isRequired(props, propName, componentName); | ||
if (error) return error; | ||
var placeholders = (0, _underscore.filter)(props[propName], isPlaceholder); | ||
if ((0, _underscore.size)(placeholders) > 1) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected only one Placeholder component.'); | ||
} | ||
} | ||
/** | ||
* Verifies that the provided property is an Option or Placeholder component from Belle. | ||
*/ | ||
function optionOrPlaceholderOrSeparatorPropType(props, propName, componentName) { | ||
if (!(props[propName] && isOption(props[propName]) || isPlaceholder(props[propName]) || isSeparator(props[propName]))) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected an Option or Placeholder component from Belle.'); | ||
} | ||
} | ||
/** | ||
* Update hover style for the speficied styleId. | ||
* | ||
* @param styleId {string} - a unique id that exists as class attribute in the DOM | ||
* @param properties {object} - the components properties optionally containing hoverStyle | ||
*/ | ||
function updatePseudoClassStyle(styleId, properties) { | ||
var hoverStyle = (0, _underscore.extend)({}, _styleSelect2['default'].hoverStyle, properties.hoverStyle); | ||
var disabledHoverStyle = (0, _underscore.extend)({}, _styleSelect2['default'].disabledHoverStyle, properties.disabledHoverStyle); | ||
var styles = [{ | ||
id: styleId, | ||
style: hoverStyle, | ||
pseudoClass: 'hover' | ||
}, { | ||
id: styleId, | ||
style: disabledHoverStyle, | ||
pseudoClass: 'hover', | ||
disabled: true | ||
}]; | ||
(0, _utilsInjectStyle.injectStyles)(styles); | ||
} | ||
/** | ||
* Returns true in case there one more element in the list. | ||
*/ | ||
var hasNext = function hasNext(list, currentIndex) { | ||
return currentIndex + 2 <= list.length; | ||
}; | ||
/** | ||
* Returns true in case there is one previous element in the list. | ||
*/ | ||
var hasPrevious = function hasPrevious(list, currentIndex) { | ||
return currentIndex - 1 >= 0; | ||
}; | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div of | ||
* the selected option. | ||
*/ | ||
function sanitizePropertiesForSelectedOptionWrapper(properties) { | ||
return (0, _underscore.omit)(properties, ['onClick', 'style', 'className', 'ref', 'shouldPositionOptions', 'positionOptions', 'focusStyle', 'hoverStyle', 'wrapperStyle', 'menuStyle', 'caretToOpenStyle', 'caretToCloseStyle', 'disabledCaretToOpenStyle', 'value', 'defaultValue', 'onUpdate', 'valueLink', 'role', 'aria-expanded', 'id', 'onTouchStart', 'onTouchEnd', 'onTouchCancel', 'disabledStyle', 'disabledHoverStyle']); | ||
} | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div of | ||
* the selected option. | ||
*/ | ||
function sanitizePropertiesForWrapper(wrapperProperties) { | ||
return (0, _underscore.omit)(wrapperProperties, ['style', 'ref', 'tabIndex', 'onKeyDown', 'onBlur', 'onFocus']); | ||
} | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div of | ||
* the selected option. | ||
*/ | ||
function sanitizePropertiesForMenu(menuProperties) { | ||
return (0, _underscore.omit)(menuProperties, ['style', 'ref', 'aria-labelledby', 'role']); | ||
} | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div of | ||
* the selected option. | ||
*/ | ||
function sanitizePropertiesForCaret(caretProperties) { | ||
return (0, _underscore.omit)(caretProperties, ['style', 'ref']); | ||
} | ||
module.exports = exports['default']; | ||
// filter out all non-Option Components |
@@ -30,2 +30,9 @@ 'use strict'; | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div. | ||
*/ | ||
function sanitizeChildProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['style']); | ||
} | ||
/** | ||
* Separator component. | ||
@@ -77,2 +84,3 @@ * | ||
Separator.propTypes = { | ||
children: _react2['default'].PropTypes.oneOfType([_react2['default'].PropTypes.arrayOf(_react2['default'].PropTypes.node), _react2['default'].PropTypes.node]), | ||
style: _react2['default'].PropTypes.object | ||
@@ -82,9 +90,2 @@ }; | ||
Separator.displayName = 'Belle Separator'; | ||
/** | ||
* Returns an object with properties that are relevant for the wrapping div. | ||
*/ | ||
function sanitizeChildProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['style']); | ||
} | ||
module.exports = exports['default']; |
@@ -19,4 +19,2 @@ 'use strict'; | ||
/* jslint browser: true */ | ||
var _react = require('react'); | ||
@@ -42,3 +40,47 @@ | ||
var newLineRegex = /[\r\n]/g; | ||
/** | ||
* Returns an object with properties that are relevant for the TextInput's textarea. | ||
* | ||
* As the height of the textarea needs to be calculated valueLink can not be | ||
* passed down to the textarea, but made available through this component. | ||
*/ | ||
function sanitizeChildProperties(properties) { | ||
var childProperties = (0, _underscore.omit)(properties, ['valueLink', 'onUpdate', 'onKeyDown', 'minHeight', 'maxHeight', 'className', 'style', 'hoverStyle', 'focusStyle', 'disabledStyle', 'disabledHoverStyle']); | ||
if (typeof properties.valueLink === 'object') { | ||
childProperties.value = properties.valueLink.value; | ||
} | ||
return childProperties; | ||
} | ||
/** | ||
* Update hover & focus style for the speficied styleId. | ||
* | ||
* @param styleId {string} - a unique id that exists as class attribute in the DOM | ||
* @param properties {object} - the components properties optionally containing hoverStyle & focusStyle | ||
*/ | ||
function updatePseudoClassStyle(styleId, properties) { | ||
var hoverStyle = (0, _underscore.extend)({}, _styleTextInput2['default'].hoverStyle, properties.hoverStyle); | ||
var focusStyle = (0, _underscore.extend)({}, _styleTextInput2['default'].focusStyle, properties.focusStyle); | ||
var disabledHoverStyle = (0, _underscore.extend)({}, _styleTextInput2['default'].disabledHoverStyle, properties.disabledHoverStyle); | ||
var styles = [{ | ||
id: styleId, | ||
style: hoverStyle, | ||
pseudoClass: 'hover' | ||
}, { | ||
id: styleId, | ||
style: focusStyle, | ||
pseudoClass: 'focus' | ||
}, { | ||
id: styleId, | ||
style: disabledHoverStyle, | ||
pseudoClass: 'hover', | ||
disabled: true | ||
}]; | ||
(0, _utilsInjectStyle.injectStyles)(styles); | ||
} | ||
/** | ||
* TextInput component with great UX like autogrowing & handling states | ||
@@ -92,14 +134,5 @@ * | ||
value: function componentDidMount() { | ||
this._resize(); | ||
this._triggerResize(); | ||
} | ||
}, { | ||
key: 'componentWillUnmount', | ||
/** | ||
* Remove a component's associated styles whenever it gets removed from the DOM. | ||
*/ | ||
value: function componentWillUnmount() { | ||
(0, _utilsInjectStyle.removeStyle)(this._styleId); | ||
} | ||
}, { | ||
key: 'componentWillReceiveProps', | ||
@@ -114,22 +147,12 @@ | ||
updatePseudoClassStyle(this._styleId, properties); | ||
this._resize(); | ||
this._triggerResize(); | ||
} | ||
}, { | ||
key: '_resize', | ||
key: 'componentWillUnmount', | ||
/** | ||
* Calculate the height and store the new height in the state to trigger a render. | ||
* Remove a component's associated styles whenever it gets removed from the DOM. | ||
*/ | ||
value: function _resize() { | ||
var height = (0, _utilsCalculateTextareaHeight2['default'])(_react2['default'].findDOMNode(this)); | ||
if (this.props.minHeight && this.props.minHeight > height) { | ||
height = this.props.minHeight; | ||
} | ||
if (this.props.maxHeight && this.props.maxHeight < height) { | ||
height = this.props.maxHeight; | ||
} | ||
this.setState({ height: height }); | ||
value: function componentWillUnmount() { | ||
(0, _utilsInjectStyle.removeStyle)(this._styleId); | ||
} | ||
@@ -147,3 +170,3 @@ }, { | ||
value: function _onKeyDown(event) { | ||
if (!this.props.allowNewLine && event.key == 'Enter') { | ||
if (!this.props.allowNewLine && event.key === 'Enter') { | ||
event.preventDefault(); | ||
@@ -177,3 +200,3 @@ } | ||
this.setState({ textareaProperties: { value: value } }); | ||
this.forceUpdate(this._resize); | ||
this.forceUpdate(this._triggerResize); | ||
// uncontrolled textarea must be updated with value, but then released again | ||
@@ -183,3 +206,3 @@ } else { | ||
this.forceUpdate(function () { | ||
_this._resize(); | ||
_this._triggerResize(); | ||
_this.setState({ textareaProperties: { value: undefined } }); | ||
@@ -189,7 +212,7 @@ }); | ||
} else { | ||
this._resize(); | ||
this._triggerResize(); | ||
} | ||
var valueLink = this.props.valueLink; | ||
if (typeof valueLink == 'object' && typeof valueLink.requestChange == 'function') { | ||
if (typeof valueLink === 'object' && typeof valueLink.requestChange === 'function') { | ||
valueLink.requestChange(value); | ||
@@ -203,2 +226,21 @@ } | ||
}, { | ||
key: '_triggerResize', | ||
/** | ||
* Calculate the height and store the new height in the state to trigger a render. | ||
*/ | ||
value: function _triggerResize() { | ||
var height = (0, _utilsCalculateTextareaHeight2['default'])(_react2['default'].findDOMNode(this)); | ||
if (this.props.minHeight && this.props.minHeight > height) { | ||
height = this.props.minHeight; | ||
} | ||
if (this.props.maxHeight && this.props.maxHeight < height) { | ||
height = this.props.maxHeight; | ||
} | ||
this.setState({ height: height }); | ||
} | ||
}, { | ||
key: 'render', | ||
@@ -234,2 +276,3 @@ value: function render() { | ||
TextInput.propTypes = { | ||
className: _react2['default'].PropTypes.string, | ||
minHeight: _react2['default'].PropTypes.number, | ||
@@ -245,2 +288,3 @@ maxHeight: _react2['default'].PropTypes.number, | ||
onUpdate: _react2['default'].PropTypes.func, | ||
onKeyDown: _react2['default'].PropTypes.func, | ||
valueLink: _react2['default'].PropTypes.shape({ | ||
@@ -256,46 +300,2 @@ value: _react2['default'].PropTypes.string.isRequired, | ||
}; | ||
var newLineRegex = /[\r\n]/g; | ||
/** | ||
* Returns an object with properties that are relevant for the TextInput's textarea. | ||
* | ||
* As the height of the textarea needs to be calculated valueLink can not be | ||
* passed down to the textarea, but made available through this component. | ||
*/ | ||
function sanitizeChildProperties(properties) { | ||
var childProperties = (0, _underscore.omit)(properties, ['valueLink', 'onUpdate', 'onKeyDown', 'minHeight', 'maxHeight', 'className', 'style', 'hoverStyle', 'focusStyle', 'disabledStyle', 'disabledHoverStyle']); | ||
if (typeof properties.valueLink == 'object') { | ||
childProperties.value = properties.valueLink.value; | ||
} | ||
return childProperties; | ||
} | ||
/** | ||
* Update hover & focus style for the speficied styleId. | ||
* | ||
* @param styleId {string} - a unique id that exists as class attribute in the DOM | ||
* @param properties {object} - the components properties optionally containing hoverStyle & focusStyle | ||
*/ | ||
function updatePseudoClassStyle(styleId, properties) { | ||
var hoverStyle = (0, _underscore.extend)({}, _styleTextInput2['default'].hoverStyle, properties.hoverStyle); | ||
var focusStyle = (0, _underscore.extend)({}, _styleTextInput2['default'].focusStyle, properties.focusStyle); | ||
var disabledHoverStyle = (0, _underscore.extend)({}, _styleTextInput2['default'].disabledHoverStyle, properties.disabledHoverStyle); | ||
var styles = [{ | ||
id: styleId, | ||
style: hoverStyle, | ||
pseudoClass: 'hover' | ||
}, { | ||
id: styleId, | ||
style: focusStyle, | ||
pseudoClass: 'focus' | ||
}, { | ||
id: styleId, | ||
style: disabledHoverStyle, | ||
pseudoClass: 'hover', | ||
disabled: true | ||
}]; | ||
(0, _utilsInjectStyle.injectStyles)(styles); | ||
} | ||
module.exports = exports['default']; |
@@ -19,4 +19,2 @@ 'use strict'; | ||
/* jslint browser: true */ | ||
var _react = require('react'); | ||
@@ -51,3 +49,71 @@ | ||
function sanitizeChildProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['className', 'defaultValue', 'firstChoiceProps', 'focusStyle', 'handleProps', 'onFocus', 'onBlur', 'onUpdate', 'onMouseDown', 'onMouseLeave', 'onMouseUp', 'onTouchStart', 'secondChoiceProps', 'sliderProps', 'sliderWrapperProps', 'style', 'tabIndex', 'value']); | ||
} | ||
function sanitizeSliderProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['style', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel']); | ||
} | ||
function sanitizeSliderWrapperProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['style']); | ||
} | ||
function sanitizeChoiceProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['ref', 'style']); | ||
} | ||
function sanitizeHandleProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['onMouseDown', 'onMouseMove', 'onMouseUp', 'onMouseLeave', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel', 'ref', 'style']); | ||
} | ||
/** | ||
* Verifies that the provided property is a Choice from Belle. | ||
*/ | ||
function choicePropType(props, propName, componentName) { | ||
if (!(props[propName] && (0, _utilsIsComponentOfTypeJs2['default'])('Choice', props[propName]))) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected a Choice component from Belle.'); | ||
} | ||
} | ||
/** | ||
* Verifies that the children is an array containing only two choices with a | ||
* different value. | ||
*/ | ||
function validateChoices(props, propName, componentName) { | ||
var error = _react2['default'].PropTypes.arrayOf(choicePropType)(props, propName, componentName); | ||
if (error) return error; | ||
if (props.children && props.children.length !== 2) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected exactly two Choice components.'); | ||
} | ||
if (props.children && (0, _underscore.first)(props.children).props.value === (0, _underscore.last)(props.children).props.value) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected different value properties for the provided Choice components.'); | ||
} | ||
} | ||
/** | ||
* Update focus style for the speficied styleId. | ||
* | ||
* @param styleId {string} - a unique id that exists as class attribute in the DOM | ||
* @param properties {object} - the components properties optionally containing custom styles | ||
*/ | ||
function updatePseudoClassStyle(styleId, properties) { | ||
var focusStyle = undefined; | ||
if (properties.preventFocusStyleForTouchAndClick) { | ||
focusStyle = { outline: 0 }; | ||
} else { | ||
focusStyle = (0, _underscore.extend)({}, _styleToggle2['default'].focusStyle, properties.focusStyle); | ||
} | ||
var styles = [{ | ||
id: styleId, | ||
style: focusStyle, | ||
pseudoClass: 'focus' | ||
}]; | ||
(0, _utilsInjectStyle.injectStyles)(styles); | ||
} | ||
/** | ||
* Toggle component | ||
@@ -105,2 +171,15 @@ */ | ||
_createClass(Toggle, [{ | ||
key: 'componentWillMount', | ||
/** | ||
* Generates the style-id & inject the focus style. | ||
* | ||
* The style-id is based on React's unique DOM node id. | ||
*/ | ||
value: function componentWillMount() { | ||
var id = this._reactInternalInstance._rootNodeID.replace(/\./g, '-'); | ||
this.styleId = 'style-id' + id; | ||
updatePseudoClassStyle(this.styleId, this.props); | ||
} | ||
}, { | ||
key: 'componentWillReceiveProps', | ||
@@ -127,13 +206,11 @@ value: function componentWillReceiveProps(properties) { | ||
}, { | ||
key: 'componentWillMount', | ||
key: 'componentDidUpdate', | ||
/** | ||
* Generates the style-id & inject the focus style. | ||
* | ||
* The style-id is based on React's unique DOM node id. | ||
* Deactivate the focused attribute in order to make sure the focus animation | ||
* only runs once when the component is focused on & not after re-rendering | ||
* e.g when the user clicks on the toggle. | ||
*/ | ||
value: function componentWillMount() { | ||
var id = this._reactInternalInstance._rootNodeID.replace(/\./g, '-'); | ||
this.styleId = 'style-id' + id; | ||
updatePseudoClassStyle(this.styleId, this.props); | ||
value: function componentDidUpdate() { | ||
this.isFocused = false; | ||
} | ||
@@ -150,13 +227,2 @@ }, { | ||
}, { | ||
key: 'componentDidUpdate', | ||
/** | ||
* Deactivate the focused attribute in order to make sure the focus animation | ||
* only runs once when the component is focused on & not after re-rendering | ||
* e.g when the user clicks on the toggle. | ||
*/ | ||
value: function componentDidUpdate() { | ||
this.isFocused = false; | ||
} | ||
}, { | ||
key: '_onFocus', | ||
@@ -234,31 +300,2 @@ | ||
}, { | ||
key: '_triggerChange', | ||
value: function _triggerChange(value) { | ||
if ((0, _underscore.has)(this.props, 'valueLink')) { | ||
this.props.valueLink.requestChange(value); | ||
this.setState({ | ||
isDraggingWithMouse: false, | ||
isDraggingWithTouch: false, | ||
isActive: false | ||
}); | ||
} else if ((0, _underscore.has)(this.props, 'value')) { | ||
this.setState({ | ||
isDraggingWithMouse: false, | ||
isDraggingWithTouch: false, | ||
isActive: false | ||
}); | ||
} else { | ||
this.setState({ | ||
value: value, | ||
isDraggingWithMouse: false, | ||
isDraggingWithTouch: false, | ||
isActive: false | ||
}); | ||
} | ||
if (this.props.onUpdate) { | ||
this.props.onUpdate({ value: value }); | ||
} | ||
} | ||
}, { | ||
key: '_onMouseDownOnHandle', | ||
@@ -268,3 +305,3 @@ value: function _onMouseDownOnHandle(event) { | ||
if (event.button === 0 && !this.props.disabled) { | ||
var defaultSliderOffset = this._sliderOffset(); | ||
var defaultSliderOffset = this._getSliderOffset(); | ||
this._mouseDragStart = event.pageX - (this.state.value ? defaultSliderOffset : 0); | ||
@@ -289,3 +326,3 @@ this._preventMouseSwitch = false; | ||
// see http://stackoverflow.com/a/9678166/837709 | ||
var animationFrame = _utilsAnimationFrameManagement.requestAnimationFrame.call(window, this._updateComponentOnMouseMove.bind(this, event.pageX)); | ||
var animationFrame = _utilsAnimationFrameManagement.requestAnimationFrame.call(window, this._triggerUpdateComponentOnMouseMove.bind(this, event.pageX)); | ||
@@ -305,25 +342,5 @@ if (this.previousMouseMoveFrame) { | ||
}, { | ||
key: '_updateComponentOnMouseMove', | ||
value: function _updateComponentOnMouseMove(pageX) { | ||
var difference = pageX - this._mouseDragStart; | ||
if (this.state.value && this._mouseDragEnd && difference > this._mouseDragEnd) { | ||
this._preventMouseSwitch = true; | ||
} else if (!this.state.value && this._mouseDragEnd && difference < this._mouseDragEnd) { | ||
this._preventMouseSwitch = true; | ||
} | ||
this._mouseDragEnd = difference; | ||
if (difference < 0 || difference > this._toggleWidth() - this._handleWidth()) return; | ||
this.setState({ | ||
sliderOffset: difference | ||
}); | ||
} | ||
}, { | ||
key: '_onMouseUpOnHandle', | ||
value: function _onMouseUpOnHandle(event) { | ||
if (!this.props.disabled) { | ||
if (this._mouseDragEnd) { | ||
@@ -333,3 +350,3 @@ if (!this._preventMouseSwitch) { | ||
} else if (this._preventMouseSwitch) { | ||
var value = this._mouseDragEnd > this._handleWidth() / 2; | ||
var value = this._mouseDragEnd > this._getHandleWidth() / 2; | ||
this._triggerChange(value); | ||
@@ -357,3 +374,3 @@ } | ||
} else if (this._mouseDragStart && this._preventMouseSwitch) { | ||
var value = this._mouseDragEnd > this._handleWidth() / 2; | ||
var value = this._mouseDragEnd > this._getHandleWidth() / 2; | ||
this._triggerChange(value); | ||
@@ -376,4 +393,2 @@ } else { | ||
value: function _onTouchStartAtSlider(event) { | ||
event.preventDefault(); | ||
if (event.touches.length === 1 && !this.props.disabled) { | ||
@@ -394,6 +409,5 @@ this._touchStartedAtSlider = true; | ||
if (event.touches.length === 1 && this._touchStartedAtSlider && !this.props.disabled) { | ||
// the requestAnimationFrame function must be executed in the context of window | ||
// see http://stackoverflow.com/a/9678166/837709 | ||
var animationFrame = _utilsAnimationFrameManagement.requestAnimationFrame.call(window, this._updateComponentOnTouchMoveAtSlider.bind(this, event.touches[0])); | ||
var animationFrame = _utilsAnimationFrameManagement.requestAnimationFrame.call(window, this._triggerUpdateComponentOnTouchMoveAtSlider.bind(this, event.touches[0])); | ||
@@ -413,16 +427,2 @@ if (this.previousTouchMoveAtSliderFrame) { | ||
}, { | ||
key: '_updateComponentOnTouchMoveAtSlider', | ||
value: function _updateComponentOnTouchMoveAtSlider(touch) { | ||
var touchedElement = document.elementFromPoint(touch.clientX, touch.clientY); | ||
var firstChoiceNode = _react2['default'].findDOMNode(this.refs.firstChoice); | ||
var secondChoiceNode = _react2['default'].findDOMNode(this.refs.secondChoice); | ||
this._touchEndedNotInSlider = touchedElement !== firstChoiceNode && touchedElement !== secondChoiceNode; | ||
if (this.state.isActive && this._touchEndedNotInSlider) { | ||
this.setState({ isActive: false }); | ||
} else if (!this.state.isActive && !this._touchEndedNotInSlider) { | ||
this.setState({ isActive: true }); | ||
} | ||
} | ||
}, { | ||
key: '_onTouchEndAtSlider', | ||
@@ -469,3 +469,3 @@ value: function _onTouchEndAtSlider(event) { | ||
var defaultSliderOffset = this._sliderOffset(); | ||
var defaultSliderOffset = this._getSliderOffset(); | ||
this.setState({ | ||
@@ -489,3 +489,3 @@ isDraggingWithTouch: true, | ||
// see http://stackoverflow.com/a/9678166/837709 | ||
var animationFrame = _utilsAnimationFrameManagement.requestAnimationFrame.call(window, this._updateComponentOnTouchMoveAtHandle.bind(this, event.touches[0])); | ||
var animationFrame = _utilsAnimationFrameManagement.requestAnimationFrame.call(window, this._triggerUpdateComponentOnTouchMoveAtHandle.bind(this, event.touches[0])); | ||
@@ -505,35 +505,2 @@ if (this.previousTouchMoveAtHandleFrame) { | ||
}, { | ||
key: '_updateComponentOnTouchMoveAtHandle', | ||
value: function _updateComponentOnTouchMoveAtHandle(touch) { | ||
var touchedElement = document.elementFromPoint(touch.clientX, touch.clientY); | ||
var handleNode = _react2['default'].findDOMNode(this.refs.handle); | ||
var difference = touch.pageX - this._touchDragStart; | ||
// touch left the handle | ||
if (touchedElement !== handleNode) { | ||
if (this._preventTouchSwitch) { | ||
var value = difference > this._handleWidth() / 2; | ||
this._triggerChange(value); | ||
} else { | ||
this._triggerChange(!this.state.value); | ||
} | ||
// is still dragging | ||
} else if (this.state.isDraggingWithTouch) { | ||
if (this.state.value && this._touchDragEnd && difference > this._touchDragEnd) { | ||
this._preventTouchSwitch = true; | ||
} else if (!this.state.value && this._touchDragEnd && difference < this._touchDragEnd) { | ||
this._preventTouchSwitch = true; | ||
} | ||
if (difference < 0 || difference > this._toggleWidth() - this._handleWidth()) return; | ||
this._touchDragEnd = difference; | ||
this.setState({ | ||
sliderOffset: difference | ||
}); | ||
} | ||
} | ||
}, { | ||
key: '_onTouchEndHandle', | ||
@@ -548,3 +515,3 @@ value: function _onTouchEndHandle(event) { | ||
if (this._preventTouchSwitch) { | ||
var value = this._touchDragEnd > this._handleWidth() / 2; | ||
var value = this._touchDragEnd > this._getHandleWidth() / 2; | ||
this._triggerChange(value); | ||
@@ -554,4 +521,4 @@ } else { | ||
} | ||
} else { | ||
// click like | ||
} else { | ||
this._triggerChange(!this.state.value); | ||
@@ -660,19 +627,113 @@ } | ||
}, { | ||
key: '_toggleWidth', | ||
value: function _toggleWidth() { | ||
key: '_getToggleWidth', | ||
value: function _getToggleWidth() { | ||
return (0, _underscore.has)(this.props.style, 'width') ? this.props.style.width : _styleToggle2['default'].style.width; | ||
} | ||
}, { | ||
key: '_handleWidth', | ||
value: function _handleWidth() { | ||
key: '_getHandleWidth', | ||
value: function _getHandleWidth() { | ||
return (0, _underscore.has)(this.props.handleStyle, 'width') ? this.props.handleStyle.width : _styleToggle2['default'].handleStyle.width; | ||
} | ||
}, { | ||
key: '_sliderOffset', | ||
value: function _sliderOffset() { | ||
key: '_getSliderOffset', | ||
value: function _getSliderOffset() { | ||
var firstChoiceWidth = (0, _underscore.has)(this.props.firstChoiceStyle, 'width') ? this.props.firstChoiceStyle.width : _styleToggle2['default'].firstChoiceStyle.width; | ||
return firstChoiceWidth - this._handleWidth() / 2; | ||
return firstChoiceWidth - this._getHandleWidth() / 2; | ||
} | ||
}, { | ||
key: '_triggerChange', | ||
value: function _triggerChange(value) { | ||
if ((0, _underscore.has)(this.props, 'valueLink')) { | ||
this.props.valueLink.requestChange(value); | ||
this.setState({ | ||
isDraggingWithMouse: false, | ||
isDraggingWithTouch: false, | ||
isActive: false | ||
}); | ||
} else if ((0, _underscore.has)(this.props, 'value')) { | ||
this.setState({ | ||
isDraggingWithMouse: false, | ||
isDraggingWithTouch: false, | ||
isActive: false | ||
}); | ||
} else { | ||
this.setState({ | ||
value: value, | ||
isDraggingWithMouse: false, | ||
isDraggingWithTouch: false, | ||
isActive: false | ||
}); | ||
} | ||
if (this.props.onUpdate) { | ||
this.props.onUpdate({ value: value }); | ||
} | ||
} | ||
}, { | ||
key: '_triggerUpdateComponentOnMouseMove', | ||
value: function _triggerUpdateComponentOnMouseMove(pageX) { | ||
var difference = pageX - this._mouseDragStart; | ||
if (this.state.value && this._mouseDragEnd && difference > this._mouseDragEnd) { | ||
this._preventMouseSwitch = true; | ||
} else if (!this.state.value && this._mouseDragEnd && difference < this._mouseDragEnd) { | ||
this._preventMouseSwitch = true; | ||
} | ||
this._mouseDragEnd = difference; | ||
if (difference < 0 || difference > this._getToggleWidth() - this._getHandleWidth()) return; | ||
this.setState({ | ||
sliderOffset: difference | ||
}); | ||
} | ||
}, { | ||
key: '_triggerUpdateComponentOnTouchMoveAtSlider', | ||
value: function _triggerUpdateComponentOnTouchMoveAtSlider(touch) { | ||
var touchedElement = document.elementFromPoint(touch.clientX, touch.clientY); | ||
var firstChoiceNode = _react2['default'].findDOMNode(this.refs.firstChoice); | ||
var secondChoiceNode = _react2['default'].findDOMNode(this.refs.secondChoice); | ||
this._touchEndedNotInSlider = touchedElement !== firstChoiceNode && touchedElement !== secondChoiceNode; | ||
if (this.state.isActive && this._touchEndedNotInSlider) { | ||
this.setState({ isActive: false }); | ||
} else if (!this.state.isActive && !this._touchEndedNotInSlider) { | ||
this.setState({ isActive: true }); | ||
} | ||
} | ||
}, { | ||
key: '_triggerUpdateComponentOnTouchMoveAtHandle', | ||
value: function _triggerUpdateComponentOnTouchMoveAtHandle(touch) { | ||
var touchedElement = document.elementFromPoint(touch.clientX, touch.clientY); | ||
var handleNode = _react2['default'].findDOMNode(this.refs.handle); | ||
var difference = touch.pageX - this._touchDragStart; | ||
// touch left the handle | ||
if (touchedElement !== handleNode) { | ||
if (this._preventTouchSwitch) { | ||
var value = difference > this._getHandleWidth() / 2; | ||
this._triggerChange(value); | ||
} else { | ||
this._triggerChange(!this.state.value); | ||
} | ||
} else if (this.state.isDraggingWithTouch) { | ||
// is still dragging | ||
if (this.state.value && this._touchDragEnd && difference > this._touchDragEnd) { | ||
this._preventTouchSwitch = true; | ||
} else if (!this.state.value && this._touchDragEnd && difference < this._touchDragEnd) { | ||
this._preventTouchSwitch = true; | ||
} | ||
if (difference < 0 || difference > this._getToggleWidth() - this._getHandleWidth()) return; | ||
this._touchDragEnd = difference; | ||
this.setState({ | ||
sliderOffset: difference | ||
}); | ||
} | ||
} | ||
}, { | ||
key: 'render', | ||
@@ -690,3 +751,3 @@ value: function render() { | ||
var sliderWrapperStyle = (0, _underscore.extend)({}, _styleToggle2['default'].sliderWrapperStyle, this.props.sliderWrapperStyle); | ||
var defaultSliderOffset = this._sliderOffset(); | ||
var defaultSliderOffset = this._getSliderOffset(); | ||
@@ -698,4 +759,4 @@ if (this.state.isDraggingWithMouse || this.state.isDraggingWithTouch) { | ||
}); | ||
//right now even when handle is clicked, it momentarily shows this grabbing styles | ||
//may be this.state.isDraggingWithMouse should be set to true only after mouse movement starts | ||
// right now even when handle is clicked, it momentarily shows this grabbing styles | ||
// may be this.state.isDraggingWithMouse should be set to true only after mouse movement starts | ||
handleStyle = (0, _underscore.extend)({}, _styleToggle2['default'].handleStyle, this.props.handleStyle, _styleToggle2['default'].activeHandleStyle, this.props.activeHandleStyle, { | ||
@@ -712,14 +773,11 @@ left: this.state.sliderOffset, | ||
if (this.state.isActive) { | ||
handleStyle = (0, _underscore.extend)({}, handleStyle, _styleToggle2['default'].activeHandleStyle, this.props.activeHandleStyle, { | ||
left: this.state.value ? defaultSliderOffset : 0 | ||
}); | ||
handleStyle = (0, _underscore.extend)({}, handleStyle, _styleToggle2['default'].activeHandleStyle, this.props.activeHandleStyle); | ||
} else if (this.state.isHovered) { | ||
handleStyle = (0, _underscore.extend)({}, handleStyle, _styleToggle2['default'].hoverHandleStyle, this.props.hoverHandleStyle, { | ||
left: this.state.value ? defaultSliderOffset : 0 | ||
}); | ||
} else { | ||
handleStyle = (0, _underscore.extend)({}, handleStyle, { | ||
left: this.state.value ? defaultSliderOffset : 0 | ||
}); | ||
handleStyle = (0, _underscore.extend)({}, handleStyle, _styleToggle2['default'].hoverHandleStyle, this.props.hoverHandleStyle); | ||
} | ||
var position = { | ||
left: this.state.value ? defaultSliderOffset : 0 | ||
}; | ||
handleStyle = (0, _underscore.extend)({}, handleStyle, position); | ||
} | ||
@@ -836,2 +894,3 @@ | ||
onFocus: _react2['default'].PropTypes.func, | ||
onKeyDown: _react2['default'].PropTypes.func, | ||
onMouseDown: _react2['default'].PropTypes.func, | ||
@@ -853,2 +912,3 @@ onMouseEnter: _react2['default'].PropTypes.func, | ||
sliderWrapperProps: _react2['default'].PropTypes.object, | ||
sliderWrapperStyle: _react2['default'].PropTypes.object, | ||
style: _react2['default'].PropTypes.object, | ||
@@ -859,3 +919,4 @@ value: _react2['default'].PropTypes.bool, | ||
requestChange: _react2['default'].PropTypes.func.isRequired | ||
}) | ||
}), | ||
wrapperProps: _react2['default'].PropTypes.object | ||
}; | ||
@@ -867,70 +928,2 @@ | ||
}; | ||
function sanitizeChildProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['className', 'defaultValue', 'firstChoiceProps', 'focusStyle', 'handleProps', 'onFocus', 'onBlur', 'onUpdate', 'onMouseDown', 'onMouseLeave', 'onMouseUp', 'onTouchStart', 'secondChoiceProps', 'sliderProps', 'sliderWrapperProps', 'style', 'tabIndex', 'value']); | ||
} | ||
function sanitizeSliderProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['style', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel']); | ||
} | ||
function sanitizeSliderWrapperProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['style']); | ||
} | ||
function sanitizeChoiceProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['ref', 'style']); | ||
} | ||
function sanitizeHandleProperties(properties) { | ||
return (0, _underscore.omit)(properties, ['onMouseDown', 'onMouseMove', 'onMouseUp', 'onMouseLeave', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel', 'ref', 'style']); | ||
} | ||
/** | ||
* Verifies that the children is an array containing only two choices with a | ||
* different value. | ||
*/ | ||
function validateChoices(props, propName, componentName) { | ||
var error = _react2['default'].PropTypes.arrayOf(choicePropType)(props, propName, componentName); | ||
if (error) return error; | ||
if (props.children && props.children.length !== 2) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected exactly two Choice components.'); | ||
} | ||
if (props.children && (0, _underscore.first)(props.children).props.value === (0, _underscore.last)(props.children).props.value) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected different value properties for the provided Choice components.'); | ||
} | ||
} | ||
/** | ||
* Verifies that the provided property is a Choice from Belle. | ||
*/ | ||
function choicePropType(props, propName, componentName) { | ||
if (!(props[propName] && (0, _utilsIsComponentOfTypeJs2['default'])('Choice', props[propName]))) { | ||
return new Error('Invalid children supplied to `' + componentName + '`, expected a Choice component from Belle.'); | ||
} | ||
} | ||
/** | ||
* Update focus style for the speficied styleId. | ||
* | ||
* @param styleId {string} - a unique id that exists as class attribute in the DOM | ||
* @param properties {object} - the components properties optionally containing custom styles | ||
*/ | ||
function updatePseudoClassStyle(styleId, properties) { | ||
var focusStyle = undefined; | ||
if (properties.preventFocusStyleForTouchAndClick) { | ||
focusStyle = { outline: 0 }; | ||
} else { | ||
focusStyle = (0, _underscore.extend)({}, _styleToggle2['default'].focusStyle, properties.focusStyle); | ||
} | ||
var styles = [{ | ||
id: styleId, | ||
style: focusStyle, | ||
pseudoClass: 'focus' | ||
}]; | ||
(0, _utilsInjectStyle.injectStyles)(styles); | ||
} | ||
module.exports = exports['default']; |
@@ -9,4 +9,2 @@ 'use strict'; | ||
/* jslint browser: true */ | ||
var _react = require('react'); | ||
@@ -22,2 +20,17 @@ | ||
/** | ||
* Returns the index of the entry with a certain value from the component's | ||
* children. | ||
* | ||
* The index search includes separator & option components. | ||
*/ | ||
var findIndexOfSelectedOption = function findIndexOfSelectedOption(component) { | ||
var filterFunction = function filterFunction(child) { | ||
return (0, _utilsIsComponentOfTypeJs2['default'])('Option', child) || (0, _utilsIsComponentOfTypeJs2['default'])('Separator', child); | ||
}; | ||
return (0, _underscore.findIndex)((0, _underscore.filter)(component.props.children, filterFunction), function (element) { | ||
return element.props.value === component.state.selectedValue; | ||
}); | ||
}; | ||
var selectConfig = { | ||
@@ -39,4 +52,4 @@ | ||
// In case of a placeholder no option is focused on initially | ||
var option = undefined, | ||
optionIndex = undefined; | ||
var option = undefined; | ||
var optionIndex = undefined; | ||
@@ -62,3 +75,2 @@ if (selectComponent.state.selectedValue) { | ||
var selectedOptionWrapperPaddingTop = parseFloat(selectedOptionWrapperStyle.getPropertyValue('padding-top')); | ||
var selectedOptionWrapperPaddingLeft = parseFloat(selectedOptionWrapperStyle.getPropertyValue('padding-top')); | ||
@@ -109,18 +121,3 @@ var newTop = option.offsetTop + optionPaddingTop - selectedOptionWrapperPaddingTop + menuTopBorderWidth; | ||
/** | ||
* Returns the index of the entry with a certain value from the component's | ||
* children. | ||
* | ||
* The index search includes separator & option components. | ||
*/ | ||
var findIndexOfSelectedOption = function findIndexOfSelectedOption(component) { | ||
var filterFunction = function filterFunction(child) { | ||
return (0, _utilsIsComponentOfTypeJs2['default'])('Option', child) || (0, _utilsIsComponentOfTypeJs2['default'])('Separator', child); | ||
}; | ||
return (0, _underscore.findIndex)((0, _underscore.filter)(component.props.children, filterFunction), function (element) { | ||
return element.props.value === component.state.selectedValue; | ||
}); | ||
}; | ||
exports['default'] = selectConfig; | ||
module.exports = exports['default']; |
@@ -5,4 +5,2 @@ 'use strict'; | ||
/* jslint node: true */ | ||
var _componentsButton = require('./components/Button'); | ||
@@ -100,2 +98,6 @@ | ||
var _configToggle = require('./config/toggle'); | ||
var _configToggle2 = _interopRequireDefault(_configToggle); | ||
module.exports = { | ||
@@ -127,4 +129,5 @@ Button: _componentsButton2['default'], | ||
button: _configButton2['default'], | ||
rating: _configRating2['default'] | ||
rating: _configRating2['default'], | ||
toggle: _configToggle2['default'] | ||
} | ||
}; |
@@ -1,9 +0,9 @@ | ||
"use strict"; | ||
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
var animations = ["\n@-webkit-keyframes belle-button-focus {\n0% { box-shadow: 0 0 0 0 rgba(140, 224, 255, 1); }\n99% { box-shadow: 0 0 0 8px #fff }\n100% { box-shadow: 0 0 0 0 rgba(0, 131, 180, 0); }\n}\n@-webkit-keyframes belle-toggle-focus {\n0% { box-shadow: 0 0 0 0 rgba(140, 224, 255, 1); }\n99% { box-shadow: 0 0 0 8px #fff }\n100% { box-shadow: 0 0 0 0 rgba(0, 131, 180, 0); }\n}\n@-webkit-keyframes belle-rating-focus {\n0% { background: rgba(140, 224, 255, 0); box-shadow: 0 0 0 0 rgba(140, 224, 255, 1); }\n25% { background: rgba(140, 224, 255, 0.15) }\n99% { background: transparent; box-shadow: 0 0 0 8px #fff }\n100% { background: transparent; box-shadow: 0 0 0 0 rgba(0, 131, 180, 0); }\n}\n"]; | ||
var animations = ['\n@-webkit-keyframes belle-button-focus {\n0% { box-shadow: 0 0 0 0 rgba(140, 224, 255, 1); }\n99% { box-shadow: 0 0 0 8px #fff }\n100% { box-shadow: 0 0 0 0 rgba(0, 131, 180, 0); }\n}\n@-webkit-keyframes belle-toggle-focus {\n0% { box-shadow: 0 0 0 0 rgba(140, 224, 255, 1); }\n99% { box-shadow: 0 0 0 8px #fff }\n100% { box-shadow: 0 0 0 0 rgba(0, 131, 180, 0); }\n}\n@-webkit-keyframes belle-rating-focus {\n0% { background: rgba(140, 224, 255, 0); box-shadow: 0 0 0 0 rgba(140, 224, 255, 1); }\n25% { background: rgba(140, 224, 255, 0.15) }\n99% { background: transparent; box-shadow: 0 0 0 8px #fff }\n100% { background: transparent; box-shadow: 0 0 0 0 rgba(0, 131, 180, 0); }\n}\n']; | ||
exports["default"] = animations; | ||
module.exports = exports["default"]; | ||
exports['default'] = animations; | ||
module.exports = exports['default']; |
@@ -9,2 +9,5 @@ 'use strict'; | ||
style: { | ||
background: 'transparent', | ||
/* normalize.css v3.0.1 */ | ||
@@ -196,2 +199,49 @@ font: 'inherit', | ||
backgroundRepeat: 'no-repeat' | ||
}, | ||
hintStyle: { | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
outline: 'none', | ||
color: '#ccc', | ||
/* normalize.css v3.0.1 */ | ||
font: 'inherit', | ||
margin: 0, | ||
/* Reset the default borderRadius for Mobile Safari */ | ||
borderRadius: 0, | ||
/* Belle TextInput style */ | ||
overflow: 'hidden', | ||
resize: 'none', | ||
width: '100%', | ||
fontSize: 14, | ||
paddingTop: '7px', | ||
paddingBottom: '5px', | ||
border: '0 solid #fff', | ||
borderBottom: '1px solid #ccc', | ||
display: 'block', | ||
boxSizing: 'border-box', | ||
/* | ||
To avoid any kind of flickering the user won't get feedback | ||
for selecting the button text | ||
*/ | ||
WebkitUserSelect: 'none', | ||
MozUserSelect: 'none', | ||
MsUserSelect: 'none', | ||
userSelect: 'none', | ||
/* This button can only be pressed */ | ||
MsTouchAction: 'manipulation', | ||
touchAction: 'manipulation', | ||
/* | ||
Prevent flickering while tapping on WebKit | ||
http://stackoverflow.com/a/3516243/837709 | ||
*/ | ||
WebkitTapHighlightColor: 'transparent' | ||
} | ||
@@ -198,0 +248,0 @@ }; |
@@ -50,7 +50,8 @@ 'use strict'; | ||
borderRadius: 28, | ||
backgroundColor: 'rgb(238, 238, 238)', | ||
height: 28, | ||
backgroundColor: 'rgb(243, 243, 243)', | ||
height: 27, | ||
width: 28, | ||
cursor: 'pointer', | ||
borderBottom: '1px solid rgb(189, 189, 189)', | ||
border: '1px solid rgb(220, 220, 220)', | ||
boxShadow: '0 1px 0px 0px rgb(185, 185, 185)', | ||
transition: 'left 0.1s ease-in-out', | ||
@@ -149,7 +150,9 @@ | ||
hoverHandleStyle: { | ||
backgroundColor: '#F8F8F8' | ||
backgroundColor: 'rgb(250, 250, 250)' | ||
}, | ||
activeHandleStyle: { | ||
backgroundColor: '#F8F8F8', | ||
height: 28, | ||
backgroundColor: 'rgb(246, 246, 246)', | ||
boxShadow: '0 0 0 0 rgb(189, 189, 189)', | ||
cursor: 'url(http://www.google.com/intl/en_ALL/mapfiles/closedhand.cur), move' | ||
@@ -156,0 +159,0 @@ }, |
@@ -0,1 +1,3 @@ | ||
// Inspired by https://gist.github.com/paulirish/1579671 | ||
'use strict'; | ||
@@ -6,9 +8,5 @@ | ||
}); | ||
/* jslint browser: true */ | ||
// Inspired by https://gist.github.com/paulirish/1579671 | ||
var requestAnimationFrame; | ||
var requestAnimationFrame = undefined; | ||
exports.requestAnimationFrame = requestAnimationFrame; | ||
var cancelAnimationFrame; | ||
var cancelAnimationFrame = undefined; | ||
@@ -27,3 +25,3 @@ exports.cancelAnimationFrame = cancelAnimationFrame; | ||
if (!requestAnimationFrame) { | ||
exports.requestAnimationFrame = requestAnimationFrame = function (callback, element) { | ||
exports.requestAnimationFrame = requestAnimationFrame = function (callback) { | ||
var currTime = new Date().getTime(); | ||
@@ -30,0 +28,0 @@ var timeToCall = Math.max(0, 16 - (currTime - lastTime)); |
@@ -1,39 +0,11 @@ | ||
"use strict"; | ||
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
/* jslint browser: true */ | ||
var hiddenTextarea = undefined; | ||
var computedStyleCache = {}; | ||
var hiddenTextareaStyle = 'height:0;visibility:hidden;overflow:hidden;position:absolute;z-index:-1000;top:0;right:0'; | ||
var hiddenTextarea = undefined, | ||
computedStyleCache = {}, | ||
hiddenTextareaStyle = "height:0;visibility:hidden;overflow:hidden;position:absolute;z-index:-1000;top:0;right:0"; | ||
/** | ||
* Returns the height of the textare as if all the content would be visible. | ||
* | ||
* In order to improve the performance a hidden textarea is added to the DOM | ||
* and used for further caluculations. In addition the styling of each textarea | ||
* is cached to improve performance. | ||
*/ | ||
exports["default"] = function (textareaElement) { | ||
if (!hiddenTextarea) { | ||
hiddenTextarea = document.createElement("textarea"); | ||
document.body.appendChild(hiddenTextarea); | ||
hiddenTextarea.setAttribute("class", "belle-input-helper"); | ||
} | ||
var _calculateStyling = calculateStyling(textareaElement); | ||
var style = _calculateStyling.style; | ||
var verticalPadding = _calculateStyling.verticalPadding; | ||
hiddenTextarea.setAttribute("style", style + ";" + hiddenTextareaStyle); | ||
hiddenTextarea.value = textareaElement.value; | ||
return hiddenTextarea.scrollHeight - verticalPadding; | ||
}; | ||
/** | ||
* Returns an object containing the computed style and the combined vertical padding. | ||
@@ -44,3 +16,3 @@ * | ||
function calculateStyling(node) { | ||
var reactId = node.getAttribute("data-reactid"); | ||
var reactId = node.getAttribute('data-reactid'); | ||
@@ -50,12 +22,11 @@ // calculate the computed style only once it's not in the cache | ||
(function () { | ||
// In order to work with legacy browsers the second paramter for pseudoClass | ||
// has to be provided http://caniuse.com/#feat=getcomputedstyle | ||
var computedStyle = window.getComputedStyle(node, null), | ||
verticalPadding = 0, | ||
stylesToCopy = ["line-height", "padding-top", "padding-bottom", "font-size", "font-weight", "font-family", "width", "padding-left", "padding-right", "border-width", "box-sizing"]; | ||
var computedStyle = window.getComputedStyle(node, null); | ||
var verticalPadding = 0; | ||
var stylesToCopy = ['line-height', 'padding-top', 'padding-bottom', 'font-size', 'font-weight', 'font-family', 'width', 'padding-left', 'padding-right', 'border-width', 'box-sizing']; | ||
// for a textarea with border-box, it's not necessary to subtract the padding | ||
if (computedStyle.getPropertyValue("box-sizing") !== "border-box" && computedStyle.getPropertyValue("-moz-box-sizing") !== "border-box" && computedStyle.getPropertyValue("-webkit-box-sizing") !== "border-box") { | ||
verticalPadding = parseFloat(computedStyle.getPropertyValue("padding-bottom")) + parseFloat(computedStyle.getPropertyValue("padding-top")); | ||
if (computedStyle.getPropertyValue('box-sizing') !== 'border-box' && computedStyle.getPropertyValue('-moz-box-sizing') !== 'border-box' && computedStyle.getPropertyValue('-webkit-box-sizing') !== 'border-box') { | ||
verticalPadding = parseFloat(computedStyle.getPropertyValue('padding-bottom')) + parseFloat(computedStyle.getPropertyValue('padding-top')); | ||
} | ||
@@ -66,4 +37,4 @@ | ||
style: stylesToCopy.map(function (styleName) { | ||
return styleName + ":" + computedStyle.getPropertyValue(styleName); | ||
}).join(";"), | ||
return styleName + ':' + computedStyle.getPropertyValue(styleName); | ||
}).join(';'), | ||
verticalPadding: verticalPadding | ||
@@ -76,2 +47,29 @@ }; | ||
} | ||
module.exports = exports["default"]; | ||
/** | ||
* Returns the height of the textare as if all the content would be visible. | ||
* | ||
* In order to improve the performance a hidden textarea is added to the DOM | ||
* and used for further caluculations. In addition the styling of each textarea | ||
* is cached to improve performance. | ||
*/ | ||
exports['default'] = function (textareaElement) { | ||
if (!hiddenTextarea) { | ||
hiddenTextarea = document.createElement('textarea'); | ||
document.body.appendChild(hiddenTextarea); | ||
hiddenTextarea.setAttribute('class', 'belle-input-helper'); | ||
} | ||
var _calculateStyling = calculateStyling(textareaElement); | ||
var style = _calculateStyling.style; | ||
var verticalPadding = _calculateStyling.verticalPadding; | ||
hiddenTextarea.setAttribute('style', style + ';' + hiddenTextareaStyle); | ||
hiddenTextarea.value = textareaElement.value; | ||
return hiddenTextarea.scrollHeight - verticalPadding; | ||
}; | ||
module.exports = exports['default']; |
@@ -11,4 +11,2 @@ 'use strict'; | ||
/* jslint browser: true */ | ||
var _underscore = require('underscore'); | ||
@@ -24,51 +22,6 @@ | ||
var styleElement = undefined, | ||
styleStorage = {}; | ||
var styleElement = undefined; | ||
var styleStorage = {}; | ||
/** | ||
* Injects a style tag and adds the passed style for the provided pseudoClass. | ||
*/ | ||
exports['default'] = function (styleId, style, pseudoClass, disabled) { | ||
injectStyleTag(); | ||
updateStore(styleId, style, pseudoClass, disabled); | ||
updateStyling(); | ||
}; | ||
/** | ||
* Injects a style tag and adds multiple passed styles. | ||
* | ||
* By using this function someone can make sure the DOM is updated only once. | ||
* | ||
* @example | ||
* ``` | ||
* const styles = [ | ||
* { | ||
* id: 'style-0.0.2', | ||
* style: { color: '#F00' }, | ||
* pseudoClass: 'hover' | ||
* } | ||
* ]; | ||
* injectStyles(styles); | ||
* ``` | ||
*/ | ||
function injectStyles(styles) { | ||
injectStyleTag(); | ||
(0, _underscore.each)(styles, function (style) { | ||
updateStore(style.id, style.style, style.pseudoClass, style.disabled); | ||
}); | ||
updateStyling(); | ||
} | ||
/** | ||
* Removes all pseudoClass styles based on the provided styleId. | ||
*/ | ||
function removeStyle(styleId) { | ||
delete styleStorage[styleId]; | ||
updateStyling(); | ||
} | ||
/** | ||
* Injects the provided style into the styleStore. | ||
@@ -101,3 +54,2 @@ */ | ||
*/ | ||
function createMarkupOnPseudoClass(pseudoClasses, id, disabled) { | ||
@@ -126,2 +78,47 @@ return (0, _underscore.map)(pseudoClasses, function (style, pseudoClass) { | ||
styleElement.innerHTML = (0, _underscore.flatten)([_styleAnimations2['default'], styles]).join(' '); | ||
} | ||
} | ||
/** | ||
* Injects a style tag and adds multiple passed styles. | ||
* | ||
* By using this function someone can make sure the DOM is updated only once. | ||
* | ||
* @example | ||
* ``` | ||
* const styles = [ | ||
* { | ||
* id: 'style-0.0.2', | ||
* style: { color: '#F00' }, | ||
* pseudoClass: 'hover' | ||
* } | ||
* ]; | ||
* injectStyles(styles); | ||
* ``` | ||
*/ | ||
function injectStyles(styles) { | ||
injectStyleTag(); | ||
(0, _underscore.each)(styles, function (style) { | ||
updateStore(style.id, style.style, style.pseudoClass, style.disabled); | ||
}); | ||
updateStyling(); | ||
} | ||
/** | ||
* Removes all pseudoClass styles based on the provided styleId. | ||
*/ | ||
function removeStyle(styleId) { | ||
delete styleStorage[styleId]; | ||
updateStyling(); | ||
} | ||
/** | ||
* Injects a style tag and adds the passed style for the provided pseudoClass. | ||
*/ | ||
exports['default'] = function (styleId, style, pseudoClass, disabled) { | ||
injectStyleTag(); | ||
updateStore(styleId, style, pseudoClass, disabled); | ||
updateStyling(); | ||
}; |
@@ -1,7 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports["default"] = isComponentOfType; | ||
/** | ||
@@ -17,3 +11,9 @@ * Returns true if the provided property is a component of the provided name. | ||
*/ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports["default"] = isComponentOfType; | ||
function isComponentOfType(componentName, reactElement) { | ||
@@ -20,0 +20,0 @@ return reactElement._isReactElement && reactElement.type && reactElement.type.name === componentName; |
{ | ||
"name": "belle", | ||
"version": "0.0.30", | ||
"version": "0.0.31", | ||
"description": "Configurable React Components with great UX", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -19,3 +19,3 @@ "use strict"; | ||
const combobox = TestUtils.renderIntoDocument( | ||
<ComboBox value='vienna'> | ||
<ComboBox value='vie'> | ||
<Option value='rome'>Rome</Option> | ||
@@ -26,3 +26,3 @@ <Option value='vienna'>Vienna</Option> | ||
expect(combobox.state.inputValue).toBe('vienna'); | ||
expect(combobox.state.inputValue).toBe('vie'); | ||
expect(combobox.state.filteredOptions.length).toBe(1); | ||
@@ -67,3 +67,3 @@ }); | ||
}, | ||
value: 'vienna' | ||
value: 'vie' | ||
}; | ||
@@ -90,3 +90,3 @@ | ||
const combobox = TestUtils.renderIntoDocument( | ||
<ComboBox defaultValue='vienna'> | ||
<ComboBox defaultValue='vie'> | ||
<Option value='vienna123'>Rome</Option> | ||
@@ -111,3 +111,3 @@ <Option value='vienna' className="vienna-option">Vienna</Option> | ||
const selectedAreaNode = TestUtils.scryRenderedDOMComponentsWithTag(combobox, 'input')[0]; | ||
const selectedAreaNode = TestUtils.scryRenderedDOMComponentsWithTag(combobox, 'input')[1]; | ||
expect(selectedAreaNode.props.style.cursor).toBe('cross'); | ||
@@ -245,3 +245,3 @@ }); | ||
); | ||
container.comboNode = TestUtils.scryRenderedDOMComponentsWithTag(container.combobox, 'input')[0]; | ||
container.comboNode = TestUtils.scryRenderedDOMComponentsWithTag(container.combobox, 'input')[1]; | ||
}); | ||
@@ -248,0 +248,0 @@ |
@@ -1,2 +0,2 @@ | ||
"use strict"; | ||
/*global jest, describe, it, expect*/ | ||
@@ -15,3 +15,2 @@ jest.dontMock('../lib/components/TextInput'); | ||
describe('TextInput', () => { | ||
it('should come with default styles', () => { | ||
@@ -43,6 +42,6 @@ const textInput = TestUtils.renderIntoDocument( | ||
textInput._resize = jest.genMockFunction(); | ||
textInput._triggerResize = jest.genMockFunction(); | ||
textInput.componentDidMount(); | ||
expect(textInput._resize.mock.calls.length).toBe(1); | ||
expect(textInput._triggerResize.mock.calls.length).toBe(1); | ||
}); | ||
@@ -56,3 +55,3 @@ | ||
textInput._resize = jest.genMockFunction(); | ||
textInput._triggerResize = jest.genMockFunction(); | ||
@@ -63,3 +62,3 @@ const textareaNode = TestUtils.findRenderedDOMComponentWithTag(textInput, 'textarea'); | ||
expect(textInput._resize.mock.calls.length).toBe(1); | ||
expect(textInput._triggerResize.mock.calls.length).toBe(1); | ||
}); | ||
@@ -73,3 +72,3 @@ | ||
textInput._resize = jest.genMockFunction(); | ||
textInput._triggerResize = jest.genMockFunction(); | ||
@@ -80,3 +79,3 @@ const textareaNode = TestUtils.findRenderedDOMComponentWithTag(textInput, 'textarea'); | ||
expect(textInput._resize.mock.calls.length).toBe(1); | ||
expect(textInput._triggerResize.mock.calls.length).toBe(1); | ||
}); | ||
@@ -90,3 +89,3 @@ | ||
textInput._resize = jest.genMockFunction(); | ||
textInput._triggerResize = jest.genMockFunction(); | ||
@@ -97,3 +96,3 @@ const textareaNode = TestUtils.findRenderedDOMComponentWithTag(textInput, 'textarea'); | ||
expect(textInput._resize.mock.calls.length).toBe(1); | ||
expect(textInput._triggerResize.mock.calls.length).toBe(1); | ||
}); | ||
@@ -106,3 +105,3 @@ | ||
const textInput = TestUtils.renderIntoDocument( | ||
<TextInput onKeyDown={ (event) => wasPressed = true }/> | ||
<TextInput onKeyDown={ () => wasPressed = true }/> | ||
); | ||
@@ -112,3 +111,3 @@ | ||
TestUtils.Simulate.keyDown(textareaNode, {key: "1"}); | ||
TestUtils.Simulate.keyDown(textareaNode, {key: '1'}); | ||
@@ -123,3 +122,3 @@ expect(wasPressed).toEqual(true); | ||
const textInput = TestUtils.renderIntoDocument( | ||
<TextInput onUpdate={ (event) => wasChanged = true }/> | ||
<TextInput onUpdate={ () => wasChanged = true }/> | ||
); | ||
@@ -165,3 +164,3 @@ | ||
it('should remove the custom styles from the dom when the textInput unmounts', function() { | ||
it('should remove the custom styles from the dom when the textInput unmounts', () => { | ||
injectStyle.removeStyle = jest.genMockFunction(); | ||
@@ -177,3 +176,2 @@ | ||
}); | ||
}); |
{ | ||
"name": "belle", | ||
"version": "0.0.30", | ||
"version": "0.0.31", | ||
"description": "Tests for Belle", | ||
@@ -5,0 +5,0 @@ "author": { |
Sorry, the diff of this file is not supported yet
6931575
27360
285