react-widgets
Advanced tools
Comparing version
@@ -80,3 +80,3 @@ 'use strict'; | ||
<div style={{ maxWidth: 600 }}> | ||
{/* <section className="example" style={{ height: '400px', overflow: 'auto' }}> | ||
<section className="example" style={{ height: '400px', overflow: 'auto' }}> | ||
<div style={{ height: 150 }}> | ||
@@ -91,9 +91,9 @@ sgsdgsdg sdgdg<br/>assdgsdgsdg<br/>asdasdasdasdasd | ||
disabled={[1 ,6]} | ||
multiple | ||
busy={false} | ||
name="super_name" | ||
onChange={change.bind(null, 'selectValues')}/> | ||
</section>*/} | ||
</section> | ||
<section className="example" style={{ marginBottom: 20 }}> | ||
{/*<section className="example" style={{ marginBottom: 20 }}> | ||
<DropdownList | ||
@@ -106,2 +106,3 @@ isRtl={false} | ||
busy={false} | ||
groupBy='surname' | ||
value={this.state.dropdownValue} | ||
@@ -114,3 +115,2 @@ onChange={change.bind(null, 'dropdownValue')}/> | ||
min={new Date(2014, 9, 15)} | ||
max={new Date(2025, 0, 15)} | ||
onChange={change.bind(null, 'calValue')}/> | ||
@@ -142,3 +142,2 @@ </section> | ||
onCreate={create} | ||
open={true} | ||
tagComponent={ListItem} | ||
@@ -152,3 +151,2 @@ itemComponent={ListItem} | ||
id='swweeeeet' | ||
time={true} | ||
format='f' | ||
@@ -163,3 +161,3 @@ min={new Date(2013,5,1,0,0,0)}/> | ||
onChange={change.bind(null, 'numberValue')}/> | ||
</section> | ||
</section>*/} | ||
</div> | ||
@@ -183,4 +181,6 @@ </div> | ||
for(var i = 0; i < arr.length; i++) | ||
arr[i] = { id: i + 1, name: chance.name() } | ||
for(var i = 0; i < arr.length; i++){ | ||
var first = chance.first(), last = chance.last() | ||
arr[i] = { id: i + 1, name: `${first} ${last}`, first, surname: last } | ||
} | ||
@@ -187,0 +187,0 @@ return arr |
'use strict'; | ||
var gulp = require('gulp') | ||
, docs = require('./tasks/docs') | ||
, dev = require('./tasks/development') | ||
, assets = require('./tasks/assets') | ||
, browser = require('./tasks/browser'); | ||
, configs = require('./tasks/webpack.configs') | ||
, clean = require('gulp-clean') | ||
, webpack = require('gulp-webpack'); | ||
gulp.task('dev-server', dev.devServer) | ||
gulp.task('doc-watch', function(){ | ||
gulp.watch(['./src/**/*', './docs/**/*.jsx'], ['docs']) | ||
}) | ||
gulp.task('assets-less', assets.less) | ||
@@ -21,14 +19,31 @@ gulp.task('assets-fonts', assets.fonts) | ||
gulp.task('browser-clean', browser.clean) | ||
gulp.task('browser-build', ['lib', 'browser-clean'], browser.build) | ||
gulp.task('browser-clean', function(){ | ||
return gulp | ||
.src('./browser/*.js', { read: false }) | ||
.pipe(clean()) | ||
}) | ||
gulp.task('browser-build', ['lib', 'browser-clean'], function() { | ||
return webpack(configs.browser) | ||
.pipe(gulp.dest('./browser/')); | ||
}) | ||
gulp.task('browser', [ 'browser-clean', 'browser-build']) | ||
gulp.task('lib', [ 'lib-clean', 'lib-compile']) | ||
gulp.task('assets', [ 'assets-fonts', 'assets-less']) | ||
gulp.task('docs', [ 'lib', 'assets'], docs.build) | ||
gulp.task('docs', [ 'lib', 'assets'], function() { | ||
return webpack(configs.docs) | ||
.pipe(gulp.dest('./docs')); | ||
}) | ||
gulp.task('doc-server', ['docs', 'doc-watch']) | ||
gulp.task('doc-watch', function(){ | ||
gulp.watch(['./src/**/*', './docs/**/*.jsx'], ['docs']) | ||
}) | ||
gulp.task('browser', [ 'browser-clean', 'browser-build']) | ||
gulp.task('dev', dev.devServer) | ||
gulp.task('dev-docs', ['docs', 'doc-watch']) | ||
gulp.task('release', [ 'lib', 'assets', 'docs', 'browser']); |
@@ -5,2 +5,4 @@ 'use strict'; | ||
console.log(process.env.TRAVIS_CI) | ||
config.set({ | ||
@@ -15,20 +17,19 @@ | ||
'./vendor/sinon-1.10.3.js', | ||
'test/*.js', 'test/*.jsx' | ||
'test.js', | ||
], | ||
reporters: ['progress'], | ||
reporters: ['mocha'], | ||
port: 9876, | ||
colors: true, | ||
autoWatch: true, | ||
singleRun: false, | ||
autoWatch: process.env.TRAVIS_CI ? false : true, | ||
singleRun: process.env.TRAVIS_CI ? true : false, | ||
// level of logging | ||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG | ||
logLevel: config.LOG_INFO, | ||
browsers: ['Chrome'], //'PhantomJS', | ||
browsers: [ 'PhantomJS'], | ||
preprocessors: { | ||
'test/*.js*': ['webpack'] | ||
'test.js': ['webpack'] | ||
}, | ||
@@ -42,2 +43,3 @@ | ||
plugins: [ | ||
require("karma-mocha-reporter"), | ||
require("karma-phantomjs-launcher"), | ||
@@ -44,0 +46,0 @@ require("karma-chrome-launcher"), |
@@ -121,4 +121,5 @@ 'use strict'; | ||
render: function(){ | ||
var $__0= | ||
_.omit(this.props, ['value', 'min', 'max']),className=$__0.className,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1}) | ||
var $__0= | ||
_.omit(this.props, ['value', 'min', 'max']),className=$__0.className,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1}) | ||
, View = VIEW[this.state.view] | ||
@@ -135,3 +136,4 @@ , unit = this.state.view | ||
React.createElement("div", React.__spread({}, props , | ||
{className: cx(className, { | ||
{onKeyDown: this._keyDown, | ||
className: cx(className, { | ||
'rw-calendar': true, | ||
@@ -156,2 +158,3 @@ 'rw-widget': true, | ||
ref: "animation", | ||
duration: this.props.duration, | ||
direction: this.state.slideDirection, | ||
@@ -180,3 +183,3 @@ onAnimate: finished.bind(this)}, | ||
function finished(){ | ||
this._focus(true, 'stop'); | ||
this._focus(true); | ||
} | ||
@@ -213,3 +216,3 @@ }, | ||
_focus: function(val, e){ | ||
_focus: function(val){ | ||
if ( this.props.maintainFocus) | ||
@@ -261,2 +264,4 @@ val && this.refs.currentView.getDOMNode().focus() | ||
} | ||
this.notify('onKeyDown', [e]) | ||
}, | ||
@@ -263,0 +268,0 @@ |
'use strict'; | ||
var React = require('react') | ||
, cx = require('./util/cx') | ||
, _ = require('./util/_') | ||
, $ = require('./util/dom') | ||
, filter = require('./util/filter') | ||
, controlledInput = require('./util/controlledInput') | ||
, CustomPropTypes = require('./util/propTypes') | ||
, Popup = require('./Popup') | ||
, List = require('./List') | ||
, Btn = require('./WidgetButton') | ||
, Input = require('./ComboboxInput'); | ||
var React = require('react') | ||
, cx = require('./util/cx') | ||
, _ = require('./util/_') | ||
, $ = require('./util/dom') | ||
, filter = require('./util/filter') | ||
, Popup = require('./Popup') | ||
, Btn = require('./WidgetButton') | ||
, Input = require('./ComboboxInput') | ||
, controlledInput = require('./util/controlledInput') | ||
, CustomPropTypes = require('./util/propTypes') | ||
, PlainList = require('./List') | ||
, GroupableList = require('./ListGroupable') | ||
, validateList = require('./util/validateListInterface'); | ||
var propTypes = { | ||
@@ -24,3 +26,10 @@ //-- controlled props ----------- | ||
itemComponent: CustomPropTypes.elementType, | ||
listComponent: CustomPropTypes.elementType, | ||
groupComponent: CustomPropTypes.elementType, | ||
groupBy: React.PropTypes.oneOfType([ | ||
React.PropTypes.func, | ||
React.PropTypes.string | ||
]), | ||
data: React.PropTypes.array, | ||
@@ -65,5 +74,3 @@ valueField: React.PropTypes.string, | ||
require('./mixins/DataHelpersMixin'), | ||
require('./mixins/RtlParentContextMixin'), | ||
require('./mixins/DataIndexStateMixin')('focusedIndex'), | ||
require('./mixins/DataIndexStateMixin')('selectedIndex') | ||
require('./mixins/RtlParentContextMixin') | ||
], | ||
@@ -78,4 +85,4 @@ | ||
return { | ||
selectedIndex: idx, | ||
focusedIndex: idx === -1 ? 0 : idx, | ||
selectedItem: items[idx], | ||
focusedItem: items[!~idx ? 0 : idx], | ||
processedData: items, | ||
@@ -103,2 +110,6 @@ open: false | ||
componentDidMount: function() { | ||
validateList(this.refs.list) | ||
}, | ||
shouldComponentUpdate: function(nextProps, nextState){ | ||
@@ -128,6 +139,6 @@ var isSuggesting = this.refs.input && this.refs.input.isSuggesting() | ||
processedData: items, | ||
selectedIndex: idx, | ||
focusedIndex: idx === -1 | ||
selectedItem: items[idx], | ||
focusedItem: items[idx === -1 | ||
? focused !== -1 ? focused : 0 // focus the closest match | ||
: idx | ||
: idx] | ||
}) | ||
@@ -142,2 +153,3 @@ }, | ||
, optID = this._id( '_option') | ||
, List = this.props.listComponent || (this.props.groupBy && GroupableList) || PlainList | ||
, completeType = this.props.suggest | ||
@@ -194,16 +206,12 @@ ? this.props.filter ? 'both' : 'inline' | ||
React.createElement("div", null, | ||
React.createElement(List, {ref: "list", | ||
id: listID, | ||
React.createElement(List, React.__spread({ref: "list"}, | ||
_.pick(this.props, Object.keys(List.type.propTypes)), | ||
{id: listID, | ||
optID: optID, | ||
'aria-hidden': !this.props.open, | ||
'aria-live': completeType && 'polite', | ||
style: { maxHeight: 200, height: 'auto'}, | ||
data: items, | ||
selectedIndex: this.state.selectedIndex, | ||
focusedIndex: this.state.focusedIndex, | ||
textField: this.props.textField, | ||
valueField: this.props.valueField, | ||
selected: this.state.selectedItem, | ||
focused: this.state.focusedItem, | ||
onSelect: this._maybeHandle(this._onSelect), | ||
listItem: this.props.itemComponent, | ||
messages: { | ||
@@ -213,3 +221,3 @@ emptyList: this.props.data.length | ||
: this.props.messages.emptyList | ||
}}) | ||
}})) | ||
) | ||
@@ -229,3 +237,3 @@ ) | ||
_onSelect: function(data, idx, elem){ | ||
_onSelect: function(data){ | ||
this.close() | ||
@@ -264,14 +272,14 @@ this.notify('onSelect', data) | ||
_focus: function(focused, e){ | ||
var self = this; | ||
clearTimeout(this.timer) | ||
!focused && this.refs.input.accept() //not suggesting anymore | ||
clearTimeout(self.timer) | ||
!focused && self.refs.input.accept() //not suggesting anymore | ||
this.timer = setTimeout(function() { | ||
if(focused) this.refs.input.focus() | ||
else this.close() | ||
self.timer = setTimeout(function(){ | ||
if(focused) self.refs.input.focus() | ||
else self.close() | ||
if( focused !== self.state.focused) | ||
self.setState({ focused: focused }) | ||
}, 0) | ||
if( focused !== this.state.focused){ | ||
this.notify(focused ? 'onFocus' : 'onBlur', e) | ||
this.setState({ focused:focused }) | ||
} | ||
}.bind(this), 0) | ||
}, | ||
@@ -283,10 +291,14 @@ | ||
, alt = e.altKey | ||
, focusedIdx = this.state.focusedIndex | ||
, isOpen = this.props.open; | ||
, list = this.refs.list | ||
, focusedItem = this.state.focusedItem | ||
, selectedItem = this.state.selectedItem | ||
, isOpen = this.props.open; | ||
if ( key === 'End' ) | ||
select(this._data().length - 1) | ||
if ( isOpen ) this.setState({ focusedItem: list.last() }) | ||
else select(list.last(), true) | ||
else if ( key === 'Home' ) | ||
select(0) | ||
if ( isOpen ) this.setState({ focusedItem: list.first() }) | ||
else select(list.first(), true) | ||
@@ -298,3 +310,3 @@ else if ( key === 'Escape' && isOpen ) | ||
this.close() | ||
select(focusedIdx, true) | ||
select(this.state.focusedItem, true) | ||
} | ||
@@ -306,4 +318,4 @@ | ||
else { | ||
if ( isOpen ) this.setFocusedIndex(this.nextFocusedIndex()) | ||
else select(this.nextSelectedIndex()) | ||
if ( isOpen ) this.setState({ focusedItem: list.next(focusedItem) }) | ||
else select(list.next(selectedItem), true) | ||
} | ||
@@ -315,11 +327,11 @@ } | ||
else { | ||
if ( isOpen ) this.setFocusedIndex(this.prevFocusedIndex()) | ||
else select(this.prevSelectedIndex()) | ||
if ( isOpen ) this.setState({ focusedItem: list.prev(focusedItem) }) | ||
else select(list.prev(selectedItem), true) | ||
} | ||
} | ||
function select(idx, fromList) { | ||
var item = self._data()[idx] | ||
if( idx === -1 || self._data().length === 0) | ||
this.notify('onKeyDown', [e]) | ||
function select(item, fromList) { | ||
if(!item) | ||
return self.change(self.refs.input.getDOMNode().value, false) | ||
@@ -326,0 +338,0 @@ |
@@ -28,2 +28,4 @@ 'use strict'; | ||
onSelect: React.PropTypes.func, | ||
min: React.PropTypes.instanceOf(Date), | ||
@@ -78,4 +80,3 @@ max: React.PropTypes.instanceOf(Date), | ||
return { | ||
selectedIndex: 0, | ||
open: false | ||
focused: false, | ||
} | ||
@@ -85,4 +86,4 @@ }, | ||
getDefaultProps: function(){ | ||
var cal = _.has(this.props, 'calendar') ? this.props.calendar : true | ||
, time = _.has(this.props, 'time') ? this.props.time : true | ||
var cal = _.has(this.props, popups.CALENDAR) ? this.props.calendar : true | ||
, time = _.has(this.props, popups.TIME) ? this.props.time : true | ||
, both = cal && time | ||
@@ -100,2 +101,3 @@ , neither = !cal && !time; | ||
time: true, | ||
open: false, | ||
messages: { | ||
@@ -135,2 +137,3 @@ calendarButton: 'Select Date', | ||
'rw-has-both': this.props.calendar && this.props.time, | ||
'rw-has-neither': !this.props.calendar && !this.props.time, | ||
'rw-rtl': this.isRtl() | ||
@@ -142,3 +145,3 @@ })}), | ||
: undefined, | ||
'aria-expanded': this.props.open, | ||
'aria-expanded': !!this.props.open, | ||
'aria-busy': !!this.props.busy, | ||
@@ -159,6 +162,7 @@ 'aria-owns': owns, | ||
onChange: this._change}), | ||
(this.props.calendar || this.props.time) && | ||
React.createElement("span", {className: "rw-select"}, | ||
this.props.calendar && | ||
React.createElement(Btn, {tabIndex: "-1", | ||
className: "rw-btn-calendar", | ||
disabled: this.isDisabled() || this.isReadOnly(), | ||
@@ -172,2 +176,3 @@ 'aria-disabled': this.isDisabled() || this.isReadOnly(), | ||
React.createElement(Btn, {tabIndex: "-1", | ||
className: "rw-btn-time", | ||
disabled: this.isDisabled() || this.isReadOnly(), | ||
@@ -180,3 +185,3 @@ 'aria-disabled': this.isDisabled() || this.isReadOnly(), | ||
), | ||
this.props.time && | ||
React.createElement(Popup, { | ||
@@ -200,19 +205,16 @@ open: this.props.open === popups.TIME, | ||
), | ||
this.props.calendar && | ||
React.createElement(Popup, { | ||
className: "rw-calendar-popup", | ||
open: this.props.open === popups.CALENDAR, | ||
duration: this.props.duration, | ||
onRequestClose: this.close}, | ||
React.createElement(Popup, { | ||
className: "rw-calendar-popup", | ||
open: this.props.open === popups.CALENDAR, | ||
duration: this.props.duration, | ||
onRequestClose: this.close}, | ||
React.createElement(Calendar, React.__spread({}, calProps , | ||
{ref: "calPopup", | ||
id: dateListID, | ||
value: this.props.value || new Date, | ||
maintainFocus: false, | ||
'aria-hidden': !this.props.open, | ||
onChange: this._maybeHandle(this._selectDate)})) | ||
) | ||
React.createElement(Calendar, React.__spread({}, calProps , | ||
{ref: "calPopup", | ||
id: dateListID, | ||
value: this.props.value || new Date, | ||
maintainFocus: false, | ||
'aria-hidden': !this.props.open, | ||
onChange: this._maybeHandle(this._selectDate)})) | ||
) | ||
) | ||
@@ -262,2 +264,4 @@ ) | ||
} | ||
this.notify('onKeyDown', [e]) | ||
}, | ||
@@ -267,32 +271,34 @@ | ||
_focus: function(focused, e){ | ||
var self = this | ||
, input = this.refs.valueInput; | ||
var input = this.refs.valueInput; | ||
clearTimeout(self.timer) | ||
clearTimeout(this.timer) | ||
self.timer = setTimeout(function(){ | ||
this.timer = setTimeout(function() { | ||
if(focused) input.getDOMNode().focus() | ||
else self.close() | ||
else this.close() | ||
if( focused !== self.state.focused) | ||
self.setState({ focused: focused }) | ||
}, 0) | ||
if( focused !== this.state.focused){ | ||
this.notify(focused ? 'onFocus' : 'onBlur', e) | ||
this.setState({ focused: focused }) | ||
} | ||
}.bind(this)) | ||
}, | ||
_selectDate: function(date){ | ||
var dateTime = dates.merge(date, this.props.value) | ||
, dateStr = formatDate(date, this.props.format) | ||
this.close() | ||
this._change( | ||
dates.merge(date, this.props.value) | ||
, formatDate(date, this.props.format) | ||
, true) | ||
this.notify('onSelect', [dateTime, dateStr]) | ||
this._change(dateTime, dateStr, true) | ||
}, | ||
_selectTime: function(datum){ | ||
var dateTime = dates.merge(this.props.value, datum.date) | ||
, dateStr = formatDate(datum.date, this.props.format) | ||
this.close() | ||
this._change( | ||
dates.merge(this.props.value, datum.date) | ||
, formatDate(datum.date, this.props.format) | ||
, true) | ||
this.notify('onSelect', [dateTime, dateStr]) | ||
this._change(dateTime, dateStr, true) | ||
}, | ||
@@ -323,3 +329,3 @@ | ||
open: function(view){ | ||
if ( this.props.open !== view ) | ||
if ( this.props.open !== view && this.props[view] === true ) | ||
this.notify('onToggle', view) | ||
@@ -329,3 +335,3 @@ }, | ||
close: function(){ | ||
if ( this.props.open) | ||
if ( this.props.open ) | ||
this.notify('onToggle', false) | ||
@@ -370,3 +376,2 @@ }, | ||
return null | ||
} | ||
} |
'use strict'; | ||
var React = require('react') | ||
, _ = require('./util/_') | ||
, $ = require('./util/dom') | ||
, cx = require('./util/cx') | ||
, setter = require('./util/stateSetter') | ||
, controlledInput = require('./util/controlledInput') | ||
, CustomPropTypes = require('./util/propTypes') | ||
, Popup = require('./Popup') | ||
, List = require('./List'); | ||
var React = require('react') | ||
, _ = require('./util/_') | ||
, cx = require('./util/cx') | ||
, controlledInput = require('./util/controlledInput') | ||
, CustomPropTypes = require('./util/propTypes') | ||
, Popup = require('./Popup') | ||
, PlainList = require('./List') | ||
, GroupableList = require('./ListGroupable') | ||
, validateList = require('./util/validateListInterface'); | ||
@@ -26,3 +27,10 @@ var propTypes = { | ||
itemComponent: CustomPropTypes.elementType, | ||
listComponent: CustomPropTypes.elementType, | ||
groupComponent: CustomPropTypes.elementType, | ||
groupBy: React.PropTypes.oneOfType([ | ||
React.PropTypes.func, | ||
React.PropTypes.string | ||
]), | ||
onSelect: React.PropTypes.func, | ||
@@ -57,7 +65,4 @@ | ||
require('./mixins/PureRenderMixin'), | ||
require('./mixins/TextSearchMixin'), | ||
require('./mixins/DataHelpersMixin'), | ||
require('./mixins/RtlParentContextMixin'), | ||
require('./mixins/DataIndexStateMixin')('focusedIndex'), | ||
require('./mixins/DataIndexStateMixin')('selectedIndex') | ||
require('./mixins/RtlParentContextMixin') | ||
], | ||
@@ -71,4 +76,4 @@ | ||
return { | ||
selectedIndex: initialIdx, | ||
focusedIndex: initialIdx === -1 ? 0 : initialIdx, | ||
selectedItem: this.props.data[initialIdx], | ||
focusedItem: this.props.data[initialIdx] || this.props.data[0], | ||
} | ||
@@ -89,4 +94,8 @@ }, | ||
componentDidMount: function() { | ||
validateList(this.refs.list) | ||
}, | ||
componentWillReceiveProps: function(props){ | ||
if ( _.isShallowEqual(props.value, this.props.value) ) | ||
if ( _.isShallowEqual(props.value, this.props.value) && props.data === this.props.data) | ||
return | ||
@@ -96,11 +105,17 @@ | ||
this.setSelectedIndex(idx) | ||
this.setFocusedIndex(idx === -1 ? 0 : idx) | ||
this.setState({ | ||
selectedItem: props.data[idx], | ||
focusedItem: props.data[!~idx ? 0 : idx] | ||
}) | ||
}, | ||
render: function(){ | ||
var $__0= _.omit(this.props, Object.keys(propTypes)),className=$__0.className,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1}) | ||
var $__0= | ||
_.omit(this.props, Object.keys(propTypes)),className=$__0.className,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1}) | ||
, ValueComponent = this.props.valueComponent | ||
, valueItem = this._dataItem( this._data(), this.props.value ) | ||
, optID = this._id('_option'); | ||
, optID = this._id('_option') | ||
, List = this.props.listComponent || (this.props.groupBy && GroupableList) || PlainList | ||
; | ||
@@ -144,15 +159,9 @@ return ( | ||
React.createElement("div", null, | ||
React.createElement(List, {ref: "list", | ||
optID: optID, | ||
'aria-hidden': !this.props.open, | ||
style: { maxHeight: 200, height: 'auto'}, | ||
data: this.props.data, | ||
initialVisibleItems: this.props.initialBufferSize, | ||
itemHeight: 18, | ||
selectedIndex: this.state.selectedIndex, | ||
focusedIndex: this.state.focusedIndex, | ||
textField: this.props.textField, | ||
valueField: this.props.valueField, | ||
listItem: this.props.itemComponent, | ||
onSelect: this._maybeHandle(this._onSelect)}) | ||
React.createElement(List, React.__spread({ref: "list"}, | ||
_.pick(this.props, Object.keys(List.type.propTypes)), | ||
{optID: optID, | ||
'aria-hidden': !this.props.open, | ||
selected: this.state.selectedItem, | ||
focused: this.props.open ? this.state.focusedItem : null, | ||
onSelect: this._maybeHandle(this._onSelect)})) | ||
) | ||
@@ -164,11 +173,3 @@ ) | ||
setWidth: function() { | ||
var width = $.width(this.getDOMNode()) | ||
, changed = width !== this.state.width; | ||
if ( changed ) | ||
this.setState({ width: width }) | ||
}, | ||
_focus: function(focused){ | ||
_focus: function(focused, e){ | ||
var self = this; | ||
@@ -182,4 +183,6 @@ | ||
if( focused !== self.state.focused) | ||
if( focused !== self.state.focused){ | ||
self.notify(focused ? 'onFocus' : 'onBlur', e) | ||
self.setState({ focused: focused }) | ||
} | ||
@@ -189,3 +192,3 @@ }, 0) | ||
_onSelect: function(data, idx, elem){ | ||
_onSelect: function(data){ | ||
this.close() | ||
@@ -200,12 +203,16 @@ this.notify('onSelect', data) | ||
, alt = e.altKey | ||
, list = this.refs.list | ||
, focusedItem = this.state.focusedItem | ||
, selectedItem = this.state.selectedItem | ||
, isOpen = this.props.open; | ||
if ( key === 'End' ) { | ||
if ( isOpen) this.setFocusedIndex(this._data().length - 1) | ||
else change(this._data().length - 1) | ||
if ( isOpen) this.setState({ focusedItem: list.last() }) | ||
else change(list.last()) | ||
e.preventDefault() | ||
} | ||
else if ( key === 'Home' ) { | ||
if ( isOpen) this.setFocusedIndex(0) | ||
else change(0) | ||
if ( isOpen) this.setState({ focusedItem: list.first() }) | ||
else change(list.first()) | ||
e.preventDefault() | ||
@@ -217,8 +224,8 @@ } | ||
else if ( (key === 'Enter' || key === ' ') && isOpen ) { | ||
change(this.state.focusedIndex, true) | ||
change(this.state.focusedItem, true) | ||
} | ||
else if ( key === 'ArrowDown' ) { | ||
if ( alt ) this.open() | ||
else if ( isOpen ) this.setFocusedIndex(this.nextFocusedIndex()) | ||
else change(this.nextSelectedIndex()) | ||
else if ( isOpen ) this.setState({ focusedItem: list.next(focusedItem) }) | ||
else change(list.next(selectedItem)) | ||
e.preventDefault() | ||
@@ -228,21 +235,20 @@ } | ||
if ( alt ) this.close() | ||
else if ( isOpen ) this.setFocusedIndex(this.prevFocusedIndex()) | ||
else change(this.prevSelectedIndex()) | ||
else if ( isOpen ) this.setState({ focusedItem: list.prev(focusedItem) }) | ||
else change(list.prev(selectedItem)) | ||
e.preventDefault() | ||
} | ||
else | ||
this.search( | ||
String.fromCharCode(e.keyCode) | ||
, this._locate) | ||
this.search(String.fromCharCode(e.keyCode), function(item) { | ||
isOpen | ||
? this.setState({ focusedItem: item }) | ||
: change(item) | ||
}.bind(this)) | ||
function change(idx, fromList){ | ||
var item = self._data()[idx]; | ||
if (idx === -1 || self._data().length === 0) | ||
return | ||
this.notify('onKeyDown', [e]) | ||
function change(item, fromList){ | ||
if(!item) return | ||
if(fromList) self.notify('onSelect', item) | ||
if(fromList) | ||
self.notify('onSelect', item) | ||
self.change(item) | ||
@@ -259,11 +265,2 @@ } | ||
_locate: function(word){ | ||
var key = this.props.open ? 'focusedIndex' : 'selectedIndex' | ||
, idx = this.findNextWordIndex(word, this.state[key]) | ||
, setIndex = setter(key).bind(this); | ||
if ( idx !== -1) | ||
setIndex(idx) | ||
}, | ||
_data: function(){ | ||
@@ -273,2 +270,19 @@ return this.props.data | ||
search: function(character, cb){ | ||
var word = ((this._searchTerm || '') + character).toLowerCase(); | ||
clearTimeout(this._timer) | ||
this._searchTerm = word | ||
this._timer = setTimeout(function() { | ||
var list = this.refs.list | ||
, key = this.props.open ? 'focusedItem' : 'selectedItem' | ||
, item = list.next(this.state[key], word); | ||
this._searchTerm = '' | ||
if ( item) cb(item) | ||
}.bind(this), this.props.delay) | ||
}, | ||
open: function(){ | ||
@@ -275,0 +289,0 @@ this.notify('onToggle', true) |
107
lib/List.js
@@ -5,3 +5,4 @@ 'use strict'; | ||
, cx = require('./util/cx') | ||
, _ = require('./util/_'); | ||
, _ = require('./util/_') | ||
, scrollTo = require('./util/scroll'); | ||
@@ -14,3 +15,4 @@ | ||
mixins: [ | ||
require('./mixins/DataHelpersMixin') | ||
require('./mixins/DataHelpersMixin'), | ||
require('./mixins/ListMovementMixin') | ||
], | ||
@@ -21,3 +23,5 @@ | ||
onSelect: React.PropTypes.func, | ||
listItem: CustomPropTypes.elementType, | ||
onMove: React.PropTypes.func, | ||
itemComponent: CustomPropTypes.elementType, | ||
selectedIndex: React.PropTypes.number, | ||
@@ -38,3 +42,2 @@ focusedIndex: React.PropTypes.number, | ||
return { | ||
delay: 500, | ||
optID: '', | ||
@@ -49,48 +52,51 @@ onSelect: function(){}, | ||
componentDidMount: function(prevProps, prevState){ | ||
getInitialState:function(){ | ||
return {} | ||
}, | ||
componentDidMount:function(prevProps, prevState){ | ||
this._setScrollPosition() | ||
}, | ||
componentDidUpdate: function(prevProps, prevState){ | ||
if ( prevProps.focusedIndex !== this.props.focusedIndex) | ||
componentDidUpdate:function(prevProps, prevState){ | ||
if ( prevState.focused !== this.props.focused) | ||
this._setScrollPosition() | ||
}, | ||
render: function(){ | ||
var $__0= _.omit(this.props, ['data', 'selectedIndex']),className=$__0.className,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1}) | ||
, ItemComponent = this.props.listItem | ||
, emptyList = React.createElement("li", null, this.props.messages.emptyList) | ||
render:function(){ | ||
var $__0= _.omit(this.props, ['data']),className=$__0.className,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1}) | ||
, ItemComponent = this.props.itemComponent | ||
, items; | ||
items = this.props.data.map(function(item, idx){ | ||
var focused = this.props.focusedIndex === idx; | ||
items = !this.props.data.length | ||
? React.createElement("li", null, this.props.messages.emptyList) | ||
: this.props.data.map(function(item, idx) { | ||
var focused = item === this.props.focused | ||
, selected = item === this.props.selected; | ||
return (React.createElement("li", { | ||
key: 'item_' + idx, | ||
role: "option", | ||
id: focused ? this.props.optID : undefined, | ||
'aria-selected': idx === this.props.selectedIndex, | ||
className: cx({ | ||
'rw-state-focus': focused, | ||
'rw-state-selected': idx === this.props.selectedIndex, | ||
}), | ||
onClick: this.props.onSelect.bind(null, item, idx)}, | ||
ItemComponent | ||
? React.createElement(ItemComponent, {item: item}) | ||
: this._dataText(item) | ||
)) | ||
}, this); | ||
return (React.createElement("li", { | ||
key: 'item_' + idx, | ||
role: "option", | ||
id: focused ? this.props.optID : undefined, | ||
'aria-selected': selected, | ||
className: cx({ | ||
'rw-list-option': true, | ||
'rw-state-focus': focused, | ||
'rw-state-selected': selected, | ||
}), | ||
onClick: this.props.onSelect.bind(null, item)}, | ||
ItemComponent | ||
? React.createElement(ItemComponent, {item: item}) | ||
: this._dataText(item) | ||
)) | ||
}.bind(this)); | ||
return ( | ||
React.createElement("ul", React.__spread({}, props , | ||
{className: className + ' rw-list', | ||
{className: (className + '') + ' rw-list', | ||
ref: "scrollable", | ||
role: "listbox", | ||
tabIndex: "-1", | ||
onKeyDown: this._keyDown, | ||
onKeyPress: this.search}), | ||
!this.props.data.length | ||
? emptyList | ||
: items | ||
role: "listbox"}), | ||
items | ||
) | ||
@@ -100,24 +106,19 @@ ) | ||
_data:function(){ | ||
return this.props.data | ||
}, | ||
_setScrollPosition: function(){ | ||
var list = this.getDOMNode() | ||
, selected = list.children[this.props.focusedIndex] | ||
, scrollTop, listHeight, selectedTop, selectedHeight, bottom; | ||
, idx = this._data().indexOf(this.props.focused) | ||
, selected = list.children[idx] | ||
, handler = this.props.onMove || scrollTo; | ||
if( !selected ) return | ||
scrollTop = list.scrollTop | ||
listHeight = list.clientHeight | ||
selectedTop = selected.offsetTop | ||
selectedHeight = selected.offsetHeight | ||
bottom = selectedTop + selectedHeight | ||
list.scrollTop = scrollTop > selectedTop | ||
? selectedTop | ||
: bottom > (scrollTop + listHeight) | ||
? (bottom - listHeight) | ||
: scrollTop | ||
// timeout allows for element to become visible | ||
setTimeout(function() {return handler(selected);}) | ||
} | ||
}) | ||
}) |
@@ -9,3 +9,3 @@ 'use strict'; | ||
valueField: React.PropTypes.string, | ||
textField: React.PropTypes.string | ||
textField: React.PropTypes.string, | ||
}, | ||
@@ -12,0 +12,0 @@ |
'use strict'; | ||
var React = require('react') | ||
, cx = require('./util/cx') | ||
, _ = require('./util/_') | ||
, controlledInput = require('./util/controlledInput') | ||
, CustomPropTypes = require('./util/propTypes') | ||
, SelectInput = require('./MultiselectInput') | ||
, TagList = require('./MultiselectTagList') | ||
, Popup = require('./Popup') | ||
, List = require('./List'); | ||
var React = require('react') | ||
, cx = require('./util/cx') | ||
, _ = require('./util/_') | ||
, SelectInput = require('./MultiselectInput') | ||
, TagList = require('./MultiselectTagList') | ||
, Popup = require('./Popup') | ||
, PlainList = require('./List') | ||
, GroupableList = require('./ListGroupable') | ||
, validateList = require('./util/validateListInterface') | ||
, controlledInput = require('./util/controlledInput') | ||
, CustomPropTypes = require('./util/propTypes'); | ||
@@ -31,3 +32,10 @@ var propTypes = { | ||
itemComponent: CustomPropTypes.elementType, | ||
listComponent: CustomPropTypes.elementType, | ||
groupComponent: CustomPropTypes.elementType, | ||
groupBy: React.PropTypes.oneOfType([ | ||
React.PropTypes.func, | ||
React.PropTypes.string | ||
]), | ||
onSelect: React.PropTypes.func, | ||
@@ -67,4 +75,3 @@ onCreate: React.PropTypes.func, | ||
require('./mixins/DataHelpersMixin'), | ||
require('./mixins/RtlParentContextMixin'), | ||
require('./mixins/DataIndexStateMixin')('focusedIndex') | ||
require('./mixins/RtlParentContextMixin') | ||
], | ||
@@ -91,12 +98,18 @@ | ||
var values = _.splat(this.props.value) | ||
, data = this.process(this.props.data, values, this.props.searchTerm) | ||
return { | ||
focusedIndex: 0, | ||
processedData: this.process(this.props.data, values, this.props.searchTerm), | ||
dataItems: values.map( function(item) {return this._dataItem(this.props.data, item);}.bind(this)) | ||
focusedItem: data[0], | ||
processedData: data, | ||
dataItems: values.map( function(item) {return this._dataItem(this.props.data, item);}.bind(this)) | ||
} | ||
}, | ||
componentDidMount: function() { | ||
validateList(this.refs.list) | ||
}, | ||
componentWillReceiveProps: function(nextProps) { | ||
var values = _.splat(nextProps.value) | ||
, current = this.state.focusedItem | ||
, items = this.process(nextProps.data, values, nextProps.searchTerm) | ||
@@ -106,2 +119,3 @@ | ||
processedData: items, | ||
focusedItem: items.indexOf(current) === -1 ? items[0]: current, | ||
dataItems: values.map( function(item) {return this._dataItem(nextProps.data, item);}.bind(this)) | ||
@@ -112,7 +126,11 @@ }) | ||
render: function(){ | ||
var $__0= _.omit(this.props, Object.keys(propTypes)),className=$__0.className,children=$__0.children,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1,children:1}) | ||
, listID = this._id('_listbox') | ||
, optID = this._id('_option') | ||
, items = this._data() | ||
, values = this.state.dataItems; | ||
var $__0= | ||
_.omit(this.props, Object.keys(propTypes)),className=$__0.className,children=$__0.children,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1,children:1}) | ||
, listID = this._id('_listbox') | ||
, optID = this._id('_option') | ||
, items = this._data() | ||
, values = this.state.dataItems | ||
, List = this.props.listComponent || (this.props.groupBy && GroupableList) || PlainList; | ||
@@ -161,2 +179,4 @@ return ( | ||
placeholder: this._placeholder(), | ||
onKeyDown: this._searchKeyDown, | ||
onKeyUp: this._searchgKeyUp, | ||
onChange: this._typing}) | ||
@@ -166,14 +186,11 @@ ), | ||
React.createElement("div", null, | ||
React.createElement(List, {ref: "list", | ||
id: listID, | ||
React.createElement(List, React.__spread({ref: "list"}, | ||
_.pick(this.props, Object.keys(List.type.propTypes)), | ||
{id: listID, | ||
optID: optID, | ||
'aria-autocomplete': "list", | ||
'aria-hidden': !this.props.open, | ||
style: { maxHeight: 200, height: 'auto'}, | ||
'aria-hidden': !this.props.open, | ||
data: items, | ||
textField: this.props.textField, | ||
valueField: this.props.valueField, | ||
focusedIndex: this.state.focusedIndex, | ||
focused: this.state.focusedItem, | ||
onSelect: this._maybeHandle(this._onSelect), | ||
listItem: this.props.itemComponent, | ||
messages: { | ||
@@ -183,7 +200,10 @@ emptyList: this.props.data.length | ||
: this.props.messages.emptyList | ||
}}), | ||
}})), | ||
this._shouldShowCreate() && | ||
React.createElement("ul", {className: "rw-list rw-multiselect-create-tag"}, | ||
React.createElement("li", {onClick: this._onCreate.bind(null, this.props.searchTerm), | ||
className: cx({'rw-state-focus': !this._data().length || this.state.focusedIndex === null })}, | ||
className: cx({ | ||
'rw-list-option': true, | ||
'rw-state-focus': !this._data().length || this.state.focusedItem === null | ||
})}, | ||
React.createElement("strong", null, ("\"" + this.props.searchTerm + "\"")), " ", this.props.messages.createNew | ||
@@ -199,7 +219,7 @@ ) | ||
_data: function(){ | ||
_data:function(){ | ||
return this.state.processedData | ||
}, | ||
_delete: function(value){ | ||
_delete:function(value){ | ||
this._focus(true) | ||
@@ -210,3 +230,3 @@ this.change( | ||
_click: function(e){ | ||
_click:function(e){ | ||
this._focus(true) | ||
@@ -216,22 +236,32 @@ !this.props.open && this.open() | ||
_focus: function(focused, e){ | ||
var self = this; | ||
_focus:function(focused, e){ | ||
if (this.props.disabled === true ) | ||
return | ||
clearTimeout(self.timer) | ||
clearTimeout(this.timer) | ||
self.timer = setTimeout(function(){ | ||
if(focused) self.refs.input.focus() | ||
this.timer = setTimeout(function() { | ||
if(focused) this.refs.input.focus() | ||
else { | ||
self.close() | ||
self.refs.tagList && self.refs.tagList.clear() | ||
this.close() | ||
this.refs.tagList && this.refs.tagList.clear() | ||
} | ||
if( focused !== this.state.focused){ | ||
this.notify(focused ? 'onFocus' : 'onBlur', e) | ||
this.setState({ focused: focused }) | ||
} | ||
}.bind(this)) | ||
}, | ||
if( focused !== self.state.focused) | ||
self.setState({ focused: focused }) | ||
}, 0) | ||
_searchKeyDown:function(e){ | ||
if (e.key === 'Backspace' && e.target.value && !this._deletingText) | ||
this._deletingText = true | ||
}, | ||
_searchgKeyUp:function(e){ | ||
if (e.key === 'Backspace' && this._deletingText) | ||
this._deletingText = false | ||
}, | ||
_typing: function(e){ | ||
@@ -266,29 +296,34 @@ this.notify('onSearch', [ e.target.value ]) | ||
, ctrl = e.ctrlKey | ||
, searching = !!this.props.searchTerm | ||
, noSearch = !this.props.searchTerm && !this._deletingText | ||
, isOpen = this.props.open | ||
, current = this.state.focusedIndex | ||
, focusedItem = this.state.focusedItem | ||
, tagList = this.refs.tagList | ||
, isLast; | ||
, list = this.refs.list; | ||
if ( key === 'ArrowDown') { | ||
var nextIdx = this.nextFocusedIndex() | ||
var next = list.next('focused') | ||
, creating = (this._shouldShowCreate() && focusedItem === next) || focusedItem === null; | ||
next = creating ? null : list.next(focusedItem) | ||
e.preventDefault() | ||
if ( isOpen ) this.setFocusedIndex(current === nextIdx || current === null ? null : nextIdx) | ||
if ( isOpen ) this.setState({ focusedItem: next }) | ||
else this.open() | ||
} | ||
else if ( key === 'ArrowUp') { | ||
var prev = focusedItem === null | ||
? list.last() | ||
: list.prev(focusedItem) | ||
e.preventDefault() | ||
if ( alt) this.close() | ||
else if ( isOpen ) this.setFocusedIndex(current === null | ||
? this._data().length - 1 | ||
: this.prevFocusedIndex()) | ||
else if ( isOpen ) this.setState({ focusedItem: prev }) | ||
} | ||
else if ( key === 'End'){ | ||
if ( isOpen ) this.setFocusedIndex(this._data().length - 1) | ||
if ( isOpen ) this.setState({ focusedItem: list.last() }) | ||
else tagList && tagList.last() | ||
} | ||
else if ( key === 'Home'){ | ||
if ( isOpen ) this.setFocusedIndex(0) | ||
if ( isOpen ) this.setState({ focusedItem: list.first() }) | ||
else tagList && tagList.first() | ||
@@ -299,19 +334,20 @@ } | ||
? this._onCreate(this.props.searchTerm) | ||
: this._onSelect(this._data()[this.state.focusedIndex]) | ||
: this._onSelect(this.state.focusedItem) | ||
else if ( key === 'Escape') | ||
isOpen ? this.close() : this.refs.tagList.clear() | ||
else if ( !searching && key === 'ArrowLeft') | ||
else if ( noSearch && key === 'ArrowLeft') | ||
tagList && tagList.prev() | ||
else if ( !searching && key === 'ArrowRight') | ||
else if ( noSearch && key === 'ArrowRight') | ||
tagList && tagList.next() | ||
else if ( !searching && key === 'Delete') | ||
else if ( noSearch && key === 'Delete') | ||
tagList && tagList.removeCurrent() | ||
else if ( !searching && key === 'Backspace') | ||
else if ( noSearch && key === 'Backspace') | ||
tagList && tagList.removeNext() | ||
this.notify('onKeyDown', [e]) | ||
}, | ||
@@ -353,3 +389,3 @@ | ||
//if there is an exact match | ||
// if there is an exact match on textFields: "john" => { name: "john" }, don't show | ||
return !this._data().some( function(v) {return this._dataText(v) === text;}.bind(this)) | ||
@@ -356,0 +392,0 @@ && !this.state.dataItems.some( function(v) {return this._dataText(v) === text;}.bind(this)) |
@@ -56,3 +56,2 @@ 'use strict'; | ||
className: "rw-input", | ||
onKeyDown: this.props.onKeyDown, | ||
onChange: this._change, | ||
@@ -59,0 +58,0 @@ onBlur: this._finish, |
@@ -87,7 +87,10 @@ 'use strict'; | ||
render: function(){ | ||
var $__0= _.omit(this.props, Object.keys(propTypes)),className=$__0.className,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1}) | ||
var $__0= | ||
_.omit(this.props, Object.keys(propTypes)),className=$__0.className,onKeyDown=$__0.onKeyDown,onKeyPress=$__0.onKeyPress,onKeyUp=$__0.onKeyUp,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1,onKeyDown:1,onKeyPress:1,onKeyUp:1}) | ||
, val = this.inRangeValue(this.props.value) | ||
//console.log('render', this.state.focused) | ||
return ( | ||
@@ -148,3 +151,5 @@ React.createElement("div", React.__spread({}, props , | ||
onChange: this.change, | ||
onKeyDown: this.props.onKeyDown}) | ||
onKeyDown: onKeyDown, | ||
onKeyPress: onKeyPress, | ||
onKeyUp: onKeyUp}) | ||
) | ||
@@ -182,15 +187,15 @@ ) | ||
_focus: function(focused, e){ | ||
var self = this; | ||
clearTimeout(this.timer) | ||
clearTimeout(self.timer) | ||
this.timer = setTimeout(function() { | ||
var el = this.refs.input.getDOMNode() | ||
self.timer = setTimeout(function(){ | ||
var el = self.refs.input.getDOMNode() | ||
focused && el.focus() | ||
if( focused !== self.state.focused) | ||
self.setState({ focused: focused }) | ||
if( focused !== this.state.focused){ | ||
this.notify(focused ? 'onFocus' : 'onBlur', e) | ||
this.setState({ focused: focused }) | ||
} | ||
}, 0) | ||
}.bind(this), 0) | ||
}, | ||
@@ -215,3 +220,2 @@ | ||
} | ||
}, | ||
@@ -218,0 +222,0 @@ |
@@ -7,3 +7,5 @@ 'use strict'; | ||
, CustomPropTypes = require('./util/propTypes') | ||
, scrollTo = require('./util/scroll'); | ||
, PlainList = require('./List') | ||
, GroupableList = require('./ListGroupable') | ||
, validateList = require('./util/validateListInterface'); | ||
@@ -23,3 +25,4 @@ var propTypes = { | ||
itemComponent: CustomPropTypes.elementType, | ||
listComponent: CustomPropTypes.elementType, | ||
valueField: React.PropTypes.string, | ||
@@ -58,7 +61,6 @@ textField: React.PropTypes.string, | ||
require('./mixins/DataHelpersMixin'), | ||
require('./mixins/RtlParentContextMixin'), | ||
require('./mixins/DataIndexStateMixin')('focusedIndex', 'isDisabledItem') | ||
require('./mixins/RtlParentContextMixin') | ||
], | ||
getDefaultProps: function(){ | ||
getDefaultProps:function(){ | ||
return { | ||
@@ -74,35 +76,43 @@ delay: 250, | ||
getDefaultState: function(props){ | ||
getDefaultState:function(props){ | ||
var isRadio = !props.multiple | ||
, values = _.splat(props.value) | ||
, idx = isRadio && this._dataIndexOf(props.data, values[0]) | ||
, first = isRadio && this._dataItem(props.data, values[0]) | ||
idx = isRadio && idx !== -1 | ||
? this.nextFocusedIndex(idx - 1) | ||
: ((this.state || {}).focusedIndex || -1) | ||
first = isRadio && first | ||
? first | ||
: ((this.state || {}).focusedItem || null) | ||
return { | ||
focusedIndex: idx, | ||
dataItems: !isRadio && values.map(function(item) {return this._dataItem(props.data, item);}.bind(this)) | ||
focusedItem: first, | ||
dataItems: !isRadio && values.map(function(item) {return this._dataItem(props.data, item);}.bind(this)) | ||
} | ||
}, | ||
getInitialState: function(){ | ||
return this.getDefaultState(this.props) | ||
getInitialState:function(){ | ||
var state = this.getDefaultState(this.props) | ||
state.ListItem = getListItem(this) | ||
return state | ||
}, | ||
componentWillReceiveProps: function(nextProps) { | ||
componentWillReceiveProps:function(nextProps) { | ||
return this.setState(this.getDefaultState(nextProps)) | ||
}, | ||
componentDidUpdate: function(prevProps, prevState){ | ||
if ( prevState.focusedIndex !== this.state.focusedIndex) | ||
this._setScrollPosition() | ||
componentDidMount: function() { | ||
validateList(this.refs.list) | ||
}, | ||
render: function() { | ||
render:function() { | ||
var $__0= _.omit(this.props, Object.keys(propTypes)),className=$__0.className,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{className:1}) | ||
, focus = this._maybeHandle(this._focus.bind(null, true), true) | ||
, optID = this._id('_selected_option') | ||
, blur = this._focus.bind(null, false); | ||
, blur = this._focus.bind(null, false) | ||
, List = this.props.listComponent || (this.props.groupBy && GroupableList) || PlainList | ||
, focusedItem = this.state.focused | ||
&& !this.isDisabled() | ||
&& !this.isReadOnly() | ||
&& this.state.focusedItem; | ||
@@ -123,3 +133,3 @@ return ( | ||
'rw-widget': true, | ||
'rw-selectlist': true, | ||
'rw-selectlist': true, | ||
'rw-state-focus': this.state.focused, | ||
@@ -132,3 +142,7 @@ 'rw-state-disabled': this.isDisabled(), | ||
React.createElement("ul", {className: "rw-list", ref: "list"}, this._rows(optID)) | ||
React.createElement(List, {ref: "list", | ||
data: this._data(), | ||
focused: focusedItem, | ||
optID: optID, | ||
itemComponent: this.state.ListItem}) | ||
) | ||
@@ -138,38 +152,9 @@ ); | ||
_rows: function(optID){ | ||
var Component = this.props.itemComponent | ||
, name = this._id('_name') | ||
, type = this.props.multiple ? 'checkbox' : 'radio'; | ||
return this._data().map( function(item, idx) { | ||
var focused = this.state.focused && this.state.focusedIndex === idx | ||
, checked = this._contains(item, this._values()) | ||
, change = this._change.bind(null, item) | ||
, disabled = this.isDisabledItem(item) | ||
, readonly = this.isReadOnlyItem(item); | ||
return (React.createElement("li", { | ||
key: 'item_' + idx, | ||
role: "option", | ||
id: focused ? optID : undefined, | ||
className: cx({ 'rw-state-focus': focused, 'rw-selectlist-item': true })}, | ||
React.createElement(SelectListItem, { | ||
type: type, | ||
name: name, | ||
onChange: change, | ||
checked: checked, | ||
readOnly: readonly, | ||
disabled: disabled || readonly}, | ||
Component ? React.createElement(Component, {item: item}) : this._dataText(item) | ||
) | ||
)) | ||
}.bind(this)) | ||
}, | ||
_keyDown: function(e){ | ||
var self = this | ||
, key = e.key | ||
, data = this._data() | ||
, multiple = !!this.props.multiple | ||
, last = data.length; | ||
, list = this.refs.list | ||
, focusedItem = this.state.focusedItem; | ||
@@ -179,4 +164,4 @@ if ( key === 'End' ) { | ||
if ( multiple ) this.setFocusedIndex(this.prevFocusedIndex(last)) | ||
else change(this.prevFocusedIndex(last)) | ||
if ( multiple ) this.setState({ focusedItem: move('prev', null) }) | ||
else change(move('prev', null)) | ||
} | ||
@@ -186,8 +171,8 @@ else if ( key === 'Home' ) { | ||
if ( multiple ) this.setFocusedIndex(this.nextFocusedIndex(-1)) | ||
else change(this.nextFocusedIndex(-1)) | ||
if ( multiple ) this.setState({ focusedItem: move('next', null) }) | ||
else change(move('next', null)) | ||
} | ||
else if ( key === 'Enter' || key === ' ' ) { | ||
e.preventDefault() | ||
change(this.state.focusedIndex) | ||
change(focusedItem) | ||
} | ||
@@ -197,10 +182,10 @@ else if ( key === 'ArrowDown' || key === 'ArrowRight' ) { | ||
if ( multiple ) this.setFocusedIndex(this.nextFocusedIndex()) | ||
else change(this.nextFocusedIndex()) | ||
if ( multiple ) this.setState({ focusedItem: move('next', focusedItem) }) | ||
else change(move('next', focusedItem)) | ||
} | ||
else if ( key === 'ArrowUp' || key === 'A rrowLeft' ) { | ||
else if ( key === 'ArrowUp' || key === 'ArrowLeft' ) { | ||
e.preventDefault() | ||
if ( multiple ) this.setFocusedIndex(this.prevFocusedIndex()) | ||
else change(this.prevFocusedIndex()) | ||
if ( multiple ) this.setState({ focusedItem: move('prev', focusedItem) }) | ||
else change(move('prev', focusedItem)) | ||
} | ||
@@ -216,14 +201,19 @@ else if (this.props.multiple && e.keyCode === 65 && e.ctrlKey ) { | ||
function change(idx, cked){ | ||
var item = data[idx]; | ||
if( idx > -1 && idx < last){ | ||
self._change(item, cked !== undefined | ||
? cked | ||
: multiple | ||
function change(item, cked){ | ||
if( item ){ | ||
self._change(item, multiple | ||
? !self._contains(item, self._values()) // toggle value | ||
: true) | ||
} | ||
} | ||
} | ||
function move(dir, item){ | ||
var stop = dir === 'next' ? list.last() : list.first() | ||
, next = list[dir](item); | ||
while( next !== stop && self.isDisabledItem(next) ) | ||
next = list[dir](next) | ||
return self.isDisabledItem(next) ? item : next | ||
} | ||
}, | ||
@@ -312,11 +302,2 @@ | ||
: this.props.value | ||
}, | ||
_setScrollPosition: function(){ | ||
var list = this.refs.list.getDOMNode() | ||
, selected = list.children[this.state.focusedIndex] | ||
, handler = this.props.onMove || scrollTo; | ||
if ( this.state.focusedIndex !== -1 ) | ||
handler(selected) | ||
} | ||
@@ -326,31 +307,47 @@ | ||
var SelectListItem = React.createClass({displayName: 'SelectListItem', | ||
function getListItem(parent){ | ||
render: function() { | ||
var $__0= this.props,children=$__0.children,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{children:1}); | ||
return React.createClass({ | ||
return ( | ||
React.createElement("label", { | ||
className: cx({ | ||
'rw-state-disabled': props.disabled, | ||
'rw-state-readonly': props.readOnly | ||
})}, | ||
React.createElement("input", React.__spread({}, props, | ||
{tabIndex: "-1", | ||
onChange: change, | ||
disabled: props.disabled || props.readOnly, | ||
'aria-disabled': props.disabled ||props.readOnly})), | ||
children | ||
) | ||
); | ||
render: function() { | ||
var $__0= | ||
this.props,props=(function(source, exclusion) {var rest = {};var hasOwn = Object.prototype.hasOwnProperty;if (source == null) {throw new TypeError();}for (var key in source) {if (hasOwn.call(source, key) && !hasOwn.call(exclusion, key)) {rest[key] = source[key];}}return rest;})($__0,{}) | ||
, item = this.props.item | ||
, checked = parent._contains(item, parent._values()) | ||
, change = parent._change.bind(null, item) | ||
, disabled = parent.isDisabledItem(item) | ||
, readonly = parent.isReadOnlyItem(item) | ||
, Component = parent.props.itemComponent | ||
, name = parent.props.name || parent._id('_name'); | ||
function change(e){ | ||
if( !props.disabled && !props.readOnly) | ||
props.onChange(e.target.checked) | ||
return ( | ||
React.createElement("label", { | ||
className: cx({ | ||
'rw-state-disabled': disabled, | ||
'rw-state-readonly': readonly | ||
})}, | ||
React.createElement("input", React.__spread({}, props, | ||
{tabIndex: "-1", | ||
name: name, | ||
type: parent.props.multiple ? 'checkbox' : 'radio', | ||
onChange: onChange, | ||
checked: checked, | ||
disabled: disabled || readonly, | ||
'aria-disabled': disabled || readonly})), | ||
Component | ||
? React.createElement(Component, {item: item}) | ||
: parent._dataText(item) | ||
) | ||
); | ||
function onChange(e){ | ||
if( !disabled && !readonly) | ||
change(e.target.checked) | ||
} | ||
} | ||
}, | ||
}) | ||
} | ||
}) | ||
module.exports = SelectList; | ||
@@ -357,0 +354,0 @@ |
@@ -13,8 +13,2 @@ 'use strict'; | ||
mixins: [ | ||
require('./mixins/TextSearchMixin'), | ||
require('./mixins/DataIndexStateMixin')('selectedIndex'), | ||
require('./mixins/DataIndexStateMixin')('focusedIndex') | ||
], | ||
propTypes: { | ||
@@ -36,2 +30,3 @@ value: React.PropTypes.instanceOf(Date), | ||
preserveDate: true, | ||
delay: 300 | ||
} | ||
@@ -41,10 +36,25 @@ }, | ||
getInitialState: function(){ | ||
var idx = this._selectedIndex(this._data(), this.props.value) | ||
var data = this._dates(this.props) | ||
, focusedItem = this._closestDate(data, this.props.value); | ||
return { focusedIndex: idx === -1 ? 0 : idx} | ||
return { | ||
focusedItem: focusedItem || data[0], | ||
dates: data | ||
} | ||
}, | ||
componentWillReceiveProps: function(nextProps) { | ||
var data = this._dates(nextProps) | ||
, focusedItem = this._closestDate(data, this.props.value); | ||
if ( nextProps.value !== this.props.value) | ||
this.setState({ | ||
focusedItem: focusedItem || data[0], | ||
dates: data | ||
}) | ||
}, | ||
render: function(){ | ||
var times = this._data() | ||
, idx = this._selectedIndex(times, this.props.value); | ||
var times = this.state.dates | ||
, date = this._closestDate(times, this.props.value); | ||
@@ -57,15 +67,15 @@ return ( | ||
valueField: "date", | ||
selectedIndex: idx, | ||
focusedIndex: this.state.focusedIndex, | ||
listItem: this.props.itemComponent, | ||
selected: date, | ||
focused: this.state.focusedItem, | ||
itemComponent: this.props.itemComponent, | ||
onSelect: this.props.onSelect})) | ||
) | ||
}, | ||
_selectedIndex: function(times, date){ | ||
_closestDate: function(times, date){ | ||
var roundTo = 1000 * 60 * this.props.step | ||
, idx = -1, label; | ||
, inst = null | ||
, label; | ||
if( !date) return 0 | ||
if( !date) return null | ||
@@ -75,13 +85,17 @@ date = new Date(Math.floor(date.getTime() / roundTo) * roundTo) | ||
times.every( function(time, i) { | ||
if( time.label === label ) return (idx = i), false | ||
return true | ||
times.some( function(time) { | ||
if( time.label === label ) | ||
return (inst = time) | ||
}) | ||
return idx | ||
return inst | ||
}, | ||
_data: function(){ | ||
_data:function(){ | ||
return this.state.dates | ||
}, | ||
_dates: function(props){ | ||
var times = [], i = 0 | ||
, values = this._dateValues() | ||
, values = this._dateValues(props) | ||
, start = values.min | ||
@@ -93,4 +107,4 @@ , startDay = dates.date(start); | ||
i++ | ||
times.push({ date: start, label: dates.format(start, this.props.format) }) | ||
start = dates.add(start, this.props.step || 30, 'minutes') | ||
times.push({ date: start, label: dates.format(start, props.format) }) | ||
start = dates.add(start, props.step || 30, 'minutes') | ||
} | ||
@@ -100,7 +114,7 @@ return times | ||
_dateValues: function(){ | ||
var value = this.props.value || dates.today() | ||
, useDate = this.props.preserveDate | ||
, min = this.props.min | ||
, max = this.props.max | ||
_dateValues: function(props){ | ||
var value = props.value || dates.today() | ||
, useDate = props.preserveDate | ||
, min = props.min | ||
, max = props.max | ||
, start, end; | ||
@@ -129,36 +143,51 @@ | ||
}, | ||
_keyDown: function(e){ | ||
var self = this | ||
, key = e.key | ||
, character = String.fromCharCode(e.keyCode); | ||
var key = e.key | ||
, character = String.fromCharCode(e.keyCode) | ||
, focusedItem = this.state.focusedItem | ||
, list = this.refs.list; | ||
if ( key === 'End' ) | ||
this.setFocusedIndex( | ||
this._data().length - 1) | ||
this.setState({ focusedItem: list.last() }) | ||
else if ( key === 'Home' ) | ||
this.setFocusedIndex(0) | ||
this.setState({ focusedItem: list.first() }) | ||
else if ( key === 'Enter' ) | ||
this.props.onSelect(this._data()[this.state.focusedIndex]) | ||
this.props.onSelect(focusedItem) | ||
else if ( key === 'ArrowDown' ) { | ||
e.preventDefault() | ||
this.setFocusedIndex( | ||
this.nextFocusedIndex()) | ||
this.setState({ focusedItem: list.next(focusedItem) }) | ||
} | ||
else if ( key === 'ArrowUp' ) { | ||
e.preventDefault() | ||
this.setFocusedIndex( | ||
this.prevFocusedIndex()) | ||
this.setState({ focusedItem: list.prev(focusedItem) }) | ||
} | ||
else { | ||
e.preventDefault() | ||
this.search(character, function(word){ | ||
self.setFocusedIndex( | ||
this.findNextWordIndex(word, self.state.focusedIndex)) | ||
}) | ||
this.search(character, function(item) { | ||
this.setState({ focusedItem: item }) | ||
}.bind(this)) | ||
} | ||
} | ||
}, | ||
search: function(character, cb){ | ||
var word = ((this._searchTerm || '') + character).toLowerCase(); | ||
clearTimeout(this._timer) | ||
this._searchTerm = word | ||
this._timer = setTimeout(function() { | ||
var list = this.refs.list | ||
, item = list.next(this.state.focusedItem, word); | ||
this._searchTerm = '' | ||
if (item) cb(item) | ||
}.bind(this), this.props.delay) | ||
}, | ||
}); |
@@ -5,11 +5,52 @@ 'use strict'; | ||
if ( start === undefined){ | ||
return { | ||
start: el.selectionStart, | ||
end: el.selectionEnd | ||
if ( start === undefined) | ||
return get(el) | ||
set(el, start, end) | ||
} | ||
function get(el){ | ||
var start, end, rangeEl, clone; | ||
if( el.selectionStart !== undefined){ | ||
start = el.selectionStart | ||
end = el.selectionEnd | ||
} | ||
else { | ||
try { | ||
el.focus() | ||
rangeEl = el.createTextRange() | ||
clone = rangeEl.duplicate() | ||
rangeEl.moveToBookmark(document.selection.createRange().getBookmark()); | ||
clone.setEndPoint('EndToStart', rangeEl); | ||
start = clone.text.length; | ||
end = start + rangeEl.text.length | ||
} | ||
catch(e) { /* not focused or not visible */ } | ||
} | ||
return { start:start, end:end } | ||
} | ||
el.focus(); | ||
el.setSelectionRange(start, end) | ||
function set(el, start, end){ | ||
var rangeEl; | ||
try { | ||
if( el.selectionStart !== undefined){ | ||
el.focus() | ||
el.setSelectionRange(start, end) | ||
} | ||
else { | ||
el.focus(); | ||
rangeEl = el.createTextRange(); | ||
rangeEl.collapse(true); | ||
rangeEl.moveStart("character", start); | ||
rangeEl.moveEnd("character", end - start); | ||
rangeEl.select(); | ||
} | ||
} | ||
catch(e) { /* not focused or not visible */ } | ||
} |
@@ -18,3 +18,3 @@ 'use strict'; | ||
if( ver[0] === 0 && ver[1] < 11 ) | ||
return console.warn(err instanceof Error ? err.message : err) | ||
return void 0 | ||
@@ -21,0 +21,0 @@ return err |
@@ -9,2 +9,3 @@ "use strict"; | ||
, reset = {} | ||
, transform ='transform' | ||
, transitions = { | ||
@@ -16,2 +17,6 @@ O:'otransitionend', | ||
var TRANSLATION_MAP = { | ||
left: 'translateX', right: 'translateX' | ||
, top: 'translateY', bottom: 'translateY'} | ||
for(var vendor in transitions) if( has.call(transitions, vendor) ) | ||
@@ -31,2 +36,4 @@ { | ||
transform = prefix + transform | ||
reset[transitionProperty = prefix + 'transition-property'] = | ||
@@ -134,3 +141,3 @@ reset[transitionDuration = prefix + 'transition-duration'] = | ||
return node.ownerDocument || document | ||
return (node && node.ownerDocument) || document | ||
}, | ||
@@ -190,2 +197,3 @@ | ||
, cssValues = {} | ||
, transforms ='' | ||
, fired; | ||
@@ -200,6 +208,15 @@ | ||
for(var key in properties) if ( has.call(properties, key) ) { | ||
cssValues[key] = properties[key] | ||
cssProperties.push(dasherize(key)) | ||
if( /(top|bottom)/.test(key) ) | ||
transforms += TRANSLATION_MAP[key] +'(' + properties[key] + ') ' | ||
else{ | ||
cssValues[key] = properties[key] | ||
cssProperties.push(dasherize(key)) | ||
} | ||
} | ||
if (transforms) { | ||
cssValues[transform] = transforms | ||
cssProperties.push(transform) | ||
} | ||
if (duration > 0 ) { | ||
@@ -238,2 +255,3 @@ cssValues[transitionProperty] = cssProperties.join(', ') | ||
function getWindow( node ) { | ||
@@ -255,5 +273,25 @@ return node === node.window | ||
function getComputedStyle(node) { | ||
return node.ownerDocument.defaultView.opener | ||
? node.ownerDocument.defaultView.getComputedStyle( node, null ) | ||
: window.getComputedStyle(node, null); | ||
if( !node) throw new Error() | ||
var doc = node.ownerDocument; | ||
return "defaultView" in doc | ||
? doc.defaultView.opener | ||
? node.ownerDocument.defaultView.getComputedStyle( node, null ) | ||
: window.getComputedStyle(node, null) | ||
: ie8(node) | ||
} | ||
function ie8(el) { | ||
return { | ||
getPropertyValue:function(prop) { | ||
var re = /(\-([a-z]){1})/g; | ||
if (prop == 'float') prop = 'styleFloat'; | ||
if (re.test(prop)) { | ||
prop = prop.replace(re, function () { | ||
return arguments[2].toUpperCase(); | ||
}); | ||
} | ||
return el.currentStyle[prop] ? el.currentStyle[prop] : null; | ||
} | ||
} | ||
} |
'use strict'; | ||
var $ = require('./dom') | ||
module.exports = function scrollTo( selected ) { | ||
module.exports = function scrollTo( selected, scrollParent ) { | ||
var offset = $.offset(selected) | ||
@@ -12,3 +12,3 @@ , poff = { top: 0, left: 0 } | ||
list = $.scrollParent(selected) | ||
list = scrollParent || $.scrollParent(selected) // if we know the parent skip this step for perf (maybe) | ||
scrollTop = $.scrollTop(list) | ||
@@ -15,0 +15,0 @@ listHeight = $.height(list, true) |
@@ -10,3 +10,3 @@ 'use strict'; | ||
return ( | ||
React.createElement("button", React.__spread({}, props, {type: "button", className: className + ' rw-btn'}), | ||
React.createElement("button", React.__spread({}, props, {type: "button", className: (className || '') + ' rw-btn'}), | ||
this.props.children | ||
@@ -13,0 +13,0 @@ ) |
{ | ||
"name": "react-widgets", | ||
"version": "2.1.0", | ||
"version": "2.2.0", | ||
"description": "React widgets", | ||
@@ -26,2 +26,5 @@ "main": "index.js", | ||
], | ||
"scripts": { | ||
"test": "node ./node_modules/karma/bin/karma start karma.conf.js" | ||
}, | ||
"homepage": "http://jquense.github.io/react-widgets/docs/", | ||
@@ -33,3 +36,3 @@ "repository": { | ||
"dependencies": { | ||
"date-arithmetic": "~1.0.0", | ||
"date-arithmetic": "^2.0.0", | ||
"globalize": "~0.1.1", | ||
@@ -39,3 +42,4 @@ "xtend": "^4.0.0" | ||
"devDependencies": { | ||
"chance": "^0.5.9", | ||
"chance": "^0.7.1", | ||
"codemirror": "^4.10.0", | ||
"concat-map": "0.0.1", | ||
@@ -56,2 +60,3 @@ "convert-source-map": "^0.4.1", | ||
"gulp-replace": "~0.4.0", | ||
"gulp-strip-debug": "^1.0.2", | ||
"gulp-uglify": "^0.3.0", | ||
@@ -63,7 +68,12 @@ "gulp-webpack": "^0.3.0", | ||
"karma": "~0.12.23", | ||
"karma-chrome-launcher": "^0.1.5", | ||
"karma-expect": "~1.1.0", | ||
"karma-mocha": "~0.1.9", | ||
"karma-mocha-reporter": "^0.3.1", | ||
"karma-phantomjs-launcher": "~0.1.4", | ||
"karma-webpack": "~1.2.2", | ||
"karma-sourcemap-loader": "^0.3.2", | ||
"karma-webpack": "~1.3.0", | ||
"karma-sauce-launcher": "^0.2.3", | ||
"karma-chrome-launcher": "^0.1.5", | ||
"karma-firefox-launcher": "^0.1.3", | ||
"karma-safari-launcher": "^0.1.1", | ||
"less": "^1.7.4", | ||
@@ -77,3 +87,3 @@ "less-loader": "^0.7.7", | ||
"react": "^0.12.0", | ||
"react-bootstrap": "git://github.com/jquense/react-bootstrap.git", | ||
"react-bootstrap": "^0.13.0", | ||
"sinon": "~1.10.3", | ||
@@ -83,5 +93,5 @@ "sinon-chai": "~2.5.0", | ||
"url-loader": "^0.5.5", | ||
"webpack": "^1.3.3", | ||
"webpack-dev-server": "~1.4.10" | ||
"webpack": "^1.4.0", | ||
"webpack-dev-server": "^1.6.0" | ||
} | ||
} |
@@ -7,3 +7,4 @@ 'use strict'; | ||
, gulpReact = require('gulp-react') | ||
, plumber = require('gulp-plumber'); | ||
, plumber = require('gulp-plumber') | ||
, stripDebug = require('gulp-strip-debug'); | ||
@@ -37,5 +38,7 @@ module.exports = { | ||
.pipe(replace(/\.jsx/g, '')) | ||
.pipe(stripDebug()) | ||
.pipe(gulp.dest('./lib')); | ||
} | ||
}, | ||
} |
'use strict'; | ||
var gulp = require('gulp') | ||
, xtend = require('xtend') | ||
, configs = require('./webpack.configs') | ||
, clean = require('gulp-clean') | ||
, webpack = require('webpack') | ||
, WebpackDevServer = require("webpack-dev-server"); | ||
var docs = require('./docs') | ||
, assets = require('./assets'); | ||
var assets = require('./assets'); | ||
@@ -25,20 +22,4 @@ gulp.task('watch-less', assets.less) | ||
}, | ||
docServer: function() { | ||
var config = xtend(configs.docs); | ||
config.devtool = 'source-map' | ||
config.plugins = []; | ||
gulp.watch('./src/less/**/*.less', ['watch-less']); | ||
gulp.src('./docs/*.js', { read: false }).pipe(clean()) | ||
new WebpackDevServer(webpack(config), { | ||
publicPath: "/docs", | ||
stats: { colors: true } | ||
}).listen(8081, "localhost"); | ||
} | ||
} | ||
@@ -106,3 +106,3 @@ var path = require('path') | ||
test: { | ||
devtool: 'source-map', | ||
devtool: 'inline-source-map', | ||
cache: true, | ||
@@ -119,3 +119,4 @@ module: { | ||
}, | ||
//plugins: [ ProdDefine ] | ||
} | ||
} |
@@ -9,3 +9,2 @@ 'use strict'; | ||
var TestUtils = React.addons.TestUtils | ||
@@ -15,6 +14,3 @@ , render = TestUtils.renderIntoDocument | ||
, findClass = TestUtils.findRenderedDOMComponentWithClass | ||
, findAllTag = TestUtils.scryRenderedDOMComponentsWithTag | ||
, findAllClass = TestUtils.scryRenderedDOMComponentsWithClass | ||
, findType = TestUtils.findRenderedComponentWithType | ||
, findAllType = TestUtils.scryRenderedComponentWithType | ||
, trigger = TestUtils.Simulate; | ||
@@ -82,2 +78,37 @@ | ||
it('should trigger focus/blur events', function(done){ | ||
var blur = sinon.spy() | ||
, focus = sinon.spy() | ||
, picker = render(<ComboBox onBlur={blur} onFocus={focus}/>); | ||
expect(focus.calledOnce).to.be(false) | ||
expect(blur.calledOnce).to.be(false) | ||
trigger.focus(picker.getDOMNode()) | ||
setTimeout(() => { | ||
expect(focus.calledOnce).to.be(true) | ||
trigger.blur(picker.getDOMNode()) | ||
setTimeout(() => { | ||
expect(blur.calledOnce).to.be(true) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('should trigger key events', function(){ | ||
var kp = sinon.spy(), kd = sinon.spy(), ku = sinon.spy() | ||
, comboBox = render(<ComboBox onKeyPress={kp} onKeyUp={ku} onKeyDown={kd}/>) | ||
, input = findClass(comboBox, 'rw-input').getDOMNode(); | ||
trigger.keyPress(input) | ||
trigger.keyDown(input) | ||
trigger.keyUp(input) | ||
expect(kp.calledOnce).to.be(true) | ||
expect(kd.calledOnce).to.be(true) | ||
expect(ku.calledOnce).to.be(true) | ||
}) | ||
it('should do nothing when disabled', function(done){ | ||
@@ -115,3 +146,3 @@ var comboBox = render(<ComboBox defaultValue={'jimmy'} data={dataList} duration={0} disabled={true}/>) | ||
var change = sinon.spy(), select = sinon.spy() | ||
, comboBox = render(<ComboBox open={true} value={dataList[1]} data={dataList} duration={0} onChange={change} onSelect={select}/>) | ||
, comboBox = render(<ComboBox open={true} value={dataList[1]} data={dataList} duration={0} onChange={change} onSelect={select} onToggle={()=>{}}/>) | ||
, list = findClass(comboBox, 'rw-list'); | ||
@@ -129,3 +160,3 @@ | ||
select.reset() | ||
trigger.keyDown(comboBox.getDOMNode(), { key: 'ArrowDown'}) //move to different value so change fires | ||
comboBox.setProps({ value: [] }) | ||
trigger.keyDown(comboBox.getDOMNode(), { key: 'Enter'}) | ||
@@ -135,2 +166,3 @@ | ||
expect(change.calledAfter(select)).to.be(true) | ||
done() | ||
@@ -171,2 +203,3 @@ }) | ||
}) |
'use strict'; | ||
/*global it, describe, expect, beforeEach */ | ||
require('../vendor/phantomjs-shim'); | ||
var React = require('react/addons') | ||
@@ -7,0 +4,0 @@ , helper = require('../src/mixins/DataHelpersMixin'); |
@@ -83,2 +83,37 @@ /* global it, describe, expect, sinon */ | ||
it('should trigger focus/blur events', function(done){ | ||
var blur = sinon.spy() | ||
, focus = sinon.spy() | ||
, picker = render(<Dropdown onBlur={blur} onFocus={focus}/>); | ||
expect(focus.calledOnce).to.be(false) | ||
expect(blur.calledOnce).to.be(false) | ||
trigger.focus(picker.getDOMNode()) | ||
setTimeout(() => { | ||
expect(focus.calledOnce).to.be(true) | ||
trigger.blur(picker.getDOMNode()) | ||
setTimeout(() => { | ||
expect(blur.calledOnce).to.be(true) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('should trigger key events', function(){ | ||
var kp = sinon.spy(), kd = sinon.spy(), ku = sinon.spy() | ||
, picker = render(<Dropdown onKeyPress={kp} onKeyUp={ku} onKeyDown={kd}/>) | ||
, input = picker.getDOMNode(); | ||
trigger.keyPress(input) | ||
trigger.keyDown(input) | ||
trigger.keyUp(input) | ||
expect(kp.calledOnce).to.be(true) | ||
expect(kd.calledOnce).to.be(true) | ||
expect(ku.calledOnce).to.be(true) | ||
}) | ||
it('should do nothing when disabled', function(done){ | ||
@@ -120,3 +155,3 @@ var dropdown = render(<Dropdown defaultValue={'jimmy'} data={data} duration={0} disabled={true}/>) | ||
var change = sinon.spy(), select = sinon.spy() | ||
, dropdown = render(<Dropdown open={true} value={data[1]} data={data} duration={0} onChange={change} onSelect={select}/>) | ||
, dropdown = render(<Dropdown value={data[1]} data={data} duration={0} onChange={change} onSelect={select}/>) | ||
, list = findClass(dropdown, 'rw-list'); | ||
@@ -176,2 +211,21 @@ | ||
it('should search values on typing', function(done){ | ||
var change = sinon.spy() | ||
, dropdown = render(<Dropdown.BaseDropdownList value={data[0]} data={data} duration={0} delay={0} onChange={change} textField='label' />); | ||
trigger.keyDown(dropdown.getDOMNode(), { keyCode: 80, key: 'p' }) | ||
setTimeout(() => { | ||
expect(change.calledOnce).to.be(true) | ||
expect(change.calledWith(data[2])).to.be(true) | ||
dropdown.setProps({ value: data[0], open: true, onToggle: ()=>{} }) | ||
trigger.keyDown(dropdown.getDOMNode(), { keyCode: 80, key: 'p' }) | ||
setTimeout(() => { | ||
expect(dropdown.state.focusedItem).to.be(data[2]) | ||
done() | ||
}) | ||
}) | ||
}) | ||
}) |
@@ -24,3 +24,5 @@ /* global it, describe, expect */ | ||
{ label: 'sally', id: 1 }, | ||
{ label: 'pat', id: 2 } | ||
{ label: 'pat', id: 2 }, | ||
{ label: 'jason', id: 3 }, | ||
{ label: 'natalie', id: 4 } | ||
]; | ||
@@ -31,5 +33,4 @@ | ||
<List data={data} onChange={_.noop} />); | ||
var input = findClass(list, 'rw-list').getDOMNode() | ||
//console.log(input) | ||
expect( input.children.length).to.be(3); | ||
expect( list.getDOMNode().children.length).to.be(5); | ||
}) | ||
@@ -41,8 +42,15 @@ | ||
expect(findClass(list, 'rw-list').getDOMNode().children[0].textContent) | ||
expect(list.getDOMNode().children[0].textContent) | ||
.to.be('jimmy'); | ||
}) | ||
it('should render an empty list message', function(){ | ||
var list = render(<List data={[]} textField='label' valueField='id' />); | ||
expect(findTag(list, 'li').getDOMNode().textContent) | ||
.to.be('There are no items in this list'); | ||
}) | ||
it('should use a Item template', function(){ | ||
var templ = React.createClass({ | ||
var Templ = React.createClass({ | ||
render: function() { | ||
@@ -53,8 +61,45 @@ return (<span>{"hello - " + this.props.item.label}</span>); | ||
var list = render(<List data={data} listItem={templ} />); | ||
var input = findClass(list, 'rw-list').getDOMNode() | ||
var list = render(<List data={data} itemComponent={Templ} />); | ||
expect( input.children[0].textContent).to.be('hello - jimmy'); | ||
expect( list.getDOMNode().children[0].textContent).to.be('hello - jimmy'); | ||
}) | ||
it('should implement first()', function(){ | ||
var focused = data[2] | ||
, selected = data[1] | ||
, list = render(<List data={data} selected={selected} focused={focused} />); | ||
expect(list.first(focused)).to.be(data[0]); | ||
}) | ||
it('should implement prev()', function(){ | ||
var focused = data[4] | ||
, selected = data[3] | ||
, list = render(<List data={data} selected={selected} focused={focused} textField='label' />); | ||
expect(list.prev(selected)).to.be(data[2]); | ||
expect(list.prev(selected, 'sa')).to.be(data[1]); | ||
expect(list.prev(focused)).to.be(data[3]); | ||
expect(list.prev(focused, 'ji')).to.be(data[0]); | ||
}) | ||
it('should implement next()', function(){ | ||
var focused = data[2] | ||
, selected = data[1] | ||
, list = render(<List data={data} selected={selected} focused={focused} textField='label'/>); | ||
expect(list.next(selected)).to.be(data[2]); | ||
expect(list.next(selected, 'ja')).to.be(data[3]); | ||
expect(list.next(focused, 'na')).to.be(data[4]); | ||
expect(list.next(focused, 'na')).to.be(data[4]); | ||
}) | ||
it('should implement last()', function(){ | ||
var focused = data[2] | ||
, list = render(<List data={data} focused={focused} />); | ||
expect(list.last(focused)).to.be(data[4]); | ||
}) | ||
}) |
@@ -21,8 +21,4 @@ 'use strict'; | ||
describe('Numberpicker', function(){ | ||
var data = [ | ||
{ label: 'jimmy', id: 0 }, | ||
{ label: 'sally', id: 1 }, | ||
{ label: 'pat', id: 2 } | ||
]; | ||
it('should set values correctly', function(done){ | ||
@@ -109,2 +105,37 @@ var picker = render(<NumberPicker value={15} format='D' onChange={_.noop} />) | ||
it('should trigger focus/blur events', function(done){ | ||
var blur = sinon.spy() | ||
, focus = sinon.spy() | ||
, picker = render(<NumberPicker onBlur={blur} onFocus={focus}/>); | ||
expect(focus.calledOnce).to.be(false) | ||
expect(blur.calledOnce).to.be(false) | ||
trigger.focus(picker.getDOMNode()) | ||
setTimeout(() => { | ||
expect(focus.calledOnce).to.be(true) | ||
trigger.blur(picker.getDOMNode()) | ||
setTimeout(() => { | ||
expect(blur.calledOnce).to.be(true) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('should trigger key events', function(){ | ||
var kp = sinon.spy(), kd = sinon.spy(), ku = sinon.spy() | ||
, picker = render(<NumberPicker onKeyPress={kp} onKeyUp={ku} onKeyDown={kd}/>) | ||
, input = findClass(picker, 'rw-input').getDOMNode(); | ||
trigger.keyPress(input) | ||
trigger.keyDown(input) | ||
trigger.keyUp(input) | ||
expect(kp.calledOnce).to.be(true) | ||
expect(kd.calledOnce).to.be(true) | ||
expect(ku.calledOnce).to.be(true) | ||
}) | ||
it('should do nothing when disabled', function(){ | ||
@@ -111,0 +142,0 @@ var change = sinon.spy() |
@@ -6,2 +6,4 @@ 'use strict'; | ||
delete require.cache[require.resolve('../src/util/_')] | ||
var React = require('react') | ||
@@ -11,4 +13,6 @@ , filters = require('../src/util/filter') | ||
, _ = require('../src/util/_') | ||
, propTypes = require('../src/util/propTypes'); | ||
, propTypes = require('../src/util/propTypes') | ||
, validateList = require('../src/util/validateListInterface'); | ||
describe('when using Class Set', function(){ | ||
@@ -125,19 +129,18 @@ | ||
describe('when using date helpers', function(){ | ||
describe('when validating Lists', function(){ | ||
it('should match correctly', function(){ | ||
it('should throw when methods are not implemented', function(){ | ||
var List = { prev: ()=>{}, next: ()=>{}, last: ()=>{}, first: 'wrong type' } | ||
expect(filters.eq(1, 1)).to.equal(true) | ||
expect(filters.neq(2, 1)).to.equal(true) | ||
expect(filters.lt(1, 2)).to.equal(true) | ||
expect(filters.lte(1, 1)).to.equal(true) | ||
expect(filters.gt(2, 1)).to.equal(true) | ||
expect(filters.gte(1, 1)).to.equal(true) | ||
expect(filters.contains([1,2], 1)).to.equal(true) | ||
expect(filters.contains('hello', 'll')).to.equal(true) | ||
expect(()=> validateList(List)).to.throwException(/first()/) | ||
}) | ||
expect(filters.startsWith('hello', 'hel')).to.equal(true) | ||
expect(filters.endsWith('hello', 'llo')).to.equal(true) | ||
it('should fail quietly in production', function(){ | ||
var List = { prev: ()=>{}, next: ()=>{}, last: ()=>{}, first: 'wrong type' } | ||
process.env.NODE_ENV = "production" | ||
expect(()=> validateList(List)).to.not.throwException() | ||
process.env.NODE_ENV = "test" | ||
}) | ||
}) | ||
@@ -144,0 +147,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
629130
12.55%108
12.5%11177
10.48%49
16.67%11
450%+ Added
- Removed
Updated