react-selectize
Advanced tools
Comparing version 0.0.9 to 0.0.10
{ | ||
"name": "react-selectize", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"description": "react implementation of selectize", | ||
"main": "src/ReactSelectize.js", | ||
"main": "src/index.js", | ||
"scripts": { | ||
@@ -12,4 +12,3 @@ "test": "echo \"Error: no test specified\" && exit 1" | ||
"dependencies": { | ||
"jquery-browserify": "^1.8.1", | ||
"prelude-extension": "0.0.4", | ||
"prelude-extension": "0.0.5", | ||
"prelude-ls": "^1.1.1", | ||
@@ -19,2 +18,5 @@ "react": "^0.13.1" | ||
"devDependencies": { | ||
"async-ls": "0.0.3", | ||
"brace": "git+https://github.com/furqanZafar/brace.git", | ||
"brfs": "^1.4.1", | ||
"browserify": "^9.0.3", | ||
@@ -24,10 +26,21 @@ "gulp": "^3.8.11", | ||
"gulp-connect": "^2.2.0", | ||
"gulp-if": "^1.2.5", | ||
"gulp-livescript": "^2.4.0", | ||
"gulp-streamify": "^1.0.2", | ||
"gulp-stylus": "^2.0.1", | ||
"gulp-uglify": "^1.4.1", | ||
"gulp-util": "^3.0.4", | ||
"jquery-browserify": "^1.8.1", | ||
"liveify": "^2.0.0", | ||
"livescript": "^1.4.0", | ||
"nib": "^1.1.0", | ||
"react-tools": "^0.13.3", | ||
"underscore": "^1.8.3", | ||
"vinyl-source-stream": "^1.0.0", | ||
"watchify": "^2.4.0" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/furqanZafar/react-selectize.git" | ||
} | ||
} | ||
} |
131
README.md
@@ -1,3 +0,9 @@ | ||
# MultiSelect component for React | ||
# React Selecitze | ||
A flexible & stateless select component for ReactJS built with livescript and love. | ||
ReactSelectize comes in 3 favours SimpleSelect (or single select), MultiSelect & ReactSelectize. Both the SimpleSelect & the MultiSelect components are built on top of the stateless ReactSelectize component. | ||
LIVE DEMO: [furqanZafar.github.io/react-selectize](http://furqanZafar.github.io/react-selectize/) | ||
[![](http://i.imgur.com/nk2BSGp.gif)](http://furqanZafar.github.io/react-selectize/) | ||
## Install | ||
@@ -7,13 +13,116 @@ | ||
## Usage | ||
## Usage (livescript) | ||
``` | ||
... | ||
ReactSelectize do | ||
placeholder: 'Select countries' | ||
values: @state.selected-countries | ||
options: @state.countries | ||
on-change: (selected-countries) ~> @set-state {selected-countries} | ||
on-options-change: (countries) ~> @set-state {countries} | ||
... | ||
``` | ||
{create-factory}:React = require \react | ||
{SimpleSelect, MultiSelect, ReactSelectize} = require \ReactSelectize | ||
SimpleSelect = create-factory SimpleSelect | ||
MultiSelect = create-factory MultiSelect | ||
. | ||
. | ||
. | ||
SimpleSelect do | ||
placeholder: 'Select a fruit' | ||
options: <[apple mango orange banana]> |> map ~> label: it, value: it | ||
on-value-change: (value, callback) ~> | ||
alert value | ||
callback! | ||
. | ||
. | ||
. | ||
MultiSelect do | ||
placeholder: 'Select fruits' | ||
options: <[apple mango orange banana]> |> map ~> label: it, value: it | ||
on-values-change: (values, callback) ~> | ||
alert values | ||
callback! | ||
``` | ||
## Usage (jsx) | ||
``` | ||
React = require("react"); | ||
ReactSelectize = require("ReactSelectize"); | ||
SimpleSelect = React.createFactory(ReactSelectize.SimpleSelect); | ||
MultiSelect = React.createFactory(ReactSelectize.MultiSelect); | ||
. | ||
. | ||
. | ||
<SimpleSelect | ||
placeholder = "Select a fruit" | ||
options = ["apple", "mango", "orange", "banana"].map(function(fruit){ | ||
return {label: fruit, value: fruit}; | ||
}); | ||
onValueChange = {function(value, callback){ | ||
alert(value); | ||
callback(); | ||
}} | ||
/> | ||
. | ||
. | ||
. | ||
<MultiSelect | ||
placeholder = "Select fruits" | ||
options = ["apple", "mango", "orange", "banana"].map(function(fruit){ | ||
return {label: fruit, value: fruit}; | ||
}); | ||
onValuesChange = {function(values, callback){ | ||
alert(values); | ||
callback(); | ||
}} | ||
/> | ||
``` | ||
## Usage (stylus) | ||
to include the default styles when using SimpleSelect component, add the following import statement to your stylus file: | ||
`@import 'node_modules/react-selectize/src/SimpleSelect.css'` | ||
to include the default styles when using MultiSelect component, add the following import statement to your stylus file: | ||
`@import 'node_modules/react-selectize/src/MultiSelect.css'` | ||
## SimpleSelect Props | ||
Property | Type | Description | ||
:---------------------------|:-----------------------------------|:-------------------------------- | ||
className | String | class name for the outer element, in addition to "simple-select" | ||
disabled | Boolean | disables interaction with the Select control | ||
createFromSearch | [Item] -> String -> Item? | implement this function to create new items on the fly, function(options, search){return {label: search, value: search}}, return null to avoid option creation for the given parameters | ||
filterOptions | [Item] -> Item -> String -> [Item] | implement this function for custom filtering logic, function(options, value, search) {return options} | ||
onBlur | Item -> String -> Void | function(value, reason){} reason can be either "click" (loss of focus because the user clicked elsewhere), "tab" or "blur" (invoked refs.simpleSelect.blur()) | ||
onFocus | Item -> String -> Void | function(value, reason){} reason can be either "event" (when the control gains focus outside) or "focus" (when the user invokes refs.simpleSelect.focus()) | ||
onSearchChange | String -> (a -> Void) -> Void | function(search, callback){self.setState({search: search}, callback);} or function(search,callback){callback();} i.e. callback MUST always be invoked | ||
onValueChange | Item -> (a -> Void) -> Void | function(selectedValue, callback){self.setState({selectedValue: selectedValue}, callback)} or function(value, callback){callback()} i.e. callback MUST always be invoked | ||
options | [Item] | list of items by default each option object MUST have label & value property, otherwise you must implement the render* & filterOptions methods | ||
placeholder: | String | displayed when there is no value | ||
renderNoResultsFound | Item -> String -> ReactElement | function(item, search){return React.DOM.div(null);} returns a custom way for rendering the "No results found" error | ||
renderOption | Int -> Item -> ReactElement | function(index, item){return React.DOM.div(null);} returns a custom way for rendering each option | ||
renderValue | Int -> Item -> ReactElement | function(index, item){return React.DOM.div(null);} returns a custom way for rendering the selected value | ||
restoreOnBackspace | Item -> String | function(item){return item.label;} implement this method if you want to go back to editing the item when the user hits the [backspace] key instead of getting removed | ||
search | String | the text displayed in the search box | ||
style | Object | the CSS styles for the outer element | ||
value | Item | the selected value, i.e. one of the objects in the options array | ||
## MultiSelect Props | ||
In addition to the props above | ||
Property | Type | Description | ||
:---------------------------|:-------------------------------------|:-------------------------------- | ||
createFromSearch | [Item] -> [Item] -> String -> Item? | function(options, values, search){return {label: search, value: search}} | ||
filterOptions | [Item] -> [Item] -> String -> [Item] | function(options, values, search){return options} | ||
onBlur | [Item] -> String -> Void | function(values, reason){} | ||
onFocus | [Item] -> String -> Void | function(values, reason){} | ||
onValuesChange | [Item] -> (a -> Void) -> Void | function(values, callback){callback();} | ||
## Development | ||
* `npm install` | ||
* copy the following to `config.ls` | ||
``` | ||
module.exports = | ||
minify: true | ||
``` | ||
* `gulp` | ||
* visit `localhost:8000` | ||
(function(){ | ||
var ref$, filter, find, last, map, partition, reject, reverse, sortBy, clamp, findAll, partitionString, React, div, input, span, SimpleOption, SimpleValue; | ||
ref$ = require('prelude-ls'), filter = ref$.filter, find = ref$.find, last = ref$.last, map = ref$.map, partition = ref$.partition, reject = ref$.reject, reverse = ref$.reverse, sortBy = ref$.sortBy; | ||
ref$ = require('prelude-extension'), clamp = ref$.clamp, findAll = ref$.findAll, partitionString = ref$.partitionString; | ||
var ref$, filter, find, findIndex, initial, last, map, partition, reject, reverse, sortBy, clamp, isEqualToObject, React, div, input, span, cancelEvent; | ||
ref$ = require('prelude-ls'), filter = ref$.filter, find = ref$.find, findIndex = ref$.findIndex, initial = ref$.initial, last = ref$.last, map = ref$.map, partition = ref$.partition, reject = ref$.reject, reverse = ref$.reverse, sortBy = ref$.sortBy; | ||
ref$ = require('prelude-extension'), clamp = ref$.clamp, isEqualToObject = ref$.isEqualToObject; | ||
React = require('react'), ref$ = React.DOM, div = ref$.div, input = ref$.input, span = ref$.span; | ||
SimpleOption = require('./SimpleOption'); | ||
SimpleValue = require('./SimpleValue'); | ||
cancelEvent = function(e){ | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
}; | ||
module.exports = React.createClass({ | ||
displayName: 'ReactSelectize', | ||
highlightedOption: -1, | ||
focusLock: false, | ||
scrollLock: false, | ||
getDefaultProps: function(){ | ||
return { | ||
addOptions: false, | ||
anchor: null, | ||
className: '', | ||
disabled: false, | ||
onBlur: function(values){}, | ||
onChange: function(values){}, | ||
onOptionsChange: function(options){}, | ||
optionClass: SimpleOption, | ||
firstOptionIndexToHighlight: function(options){ | ||
return 0; | ||
}, | ||
onAnchorChange: function(anchor){}, | ||
onBlur: function(values, reason){}, | ||
onFocus: function(values, reason){}, | ||
onOpenChange: function(open, callback){}, | ||
onSearchChange: function(search, callback){}, | ||
onValuesChange: function(values, callback){}, | ||
open: false, | ||
options: [], | ||
restoreOnBackspace: false, | ||
renderNoResultsFound: function(){ | ||
return div({ | ||
className: 'no-results-found' | ||
}, "No results found"); | ||
}, | ||
renderOption: function(index, arg$){ | ||
var label, newOption, selectable, isSelectable; | ||
if (arg$ != null) { | ||
label = arg$.label, newOption = arg$.newOption, selectable = arg$.selectable; | ||
} | ||
isSelectable = typeof selectable === 'undefined' || selectable; | ||
return div({ | ||
className: "simple-option " + (isSelectable ? '' : 'not-selectable'), | ||
key: index | ||
}, span(null, !!newOption ? "Add " + label + " ..." : label)); | ||
}, | ||
renderValue: function(index, arg$){ | ||
var label; | ||
label = arg$.label; | ||
return div({ | ||
className: 'simple-value', | ||
key: index | ||
}, span(null, label)); | ||
}, | ||
search: "", | ||
style: {}, | ||
valueClass: SimpleValue, | ||
values: [] | ||
@@ -26,24 +61,25 @@ }; | ||
render: function(){ | ||
var outOfOptions, showOptions, this$ = this; | ||
outOfOptions = !this.props.addOptions && this.props.values.length === this.props.options.length; | ||
showOptions = (function(){ | ||
var anchorIndex, this$ = this; | ||
anchorIndex = (function(){ | ||
var ref$; | ||
switch (false) { | ||
case !this.props.disabled: | ||
return false; | ||
case !!this.isBelowLimit(): | ||
return false; | ||
case !outOfOptions: | ||
return false; | ||
case !(typeof this.props.anchor === 'undefined' || this.props.anchor === null): | ||
return -1; | ||
default: | ||
return this.state.open; | ||
return (ref$ = findIndex(function(it){ | ||
return isEqualToObject(it, this$.props.anchor); | ||
}, this.props.values)) != null | ||
? ref$ | ||
: this.props.values.length - 1; | ||
} | ||
}.call(this)); | ||
return div({ | ||
className: "multi-select " + (this.props.disabled ? 'disabled' : '') + " " + (showOptions ? 'open' : ''), | ||
className: "react-selectize " + this.props.className + " " + (this.props.disabled ? 'disabled' : '') + " " + (this.props.open ? 'open' : ''), | ||
style: this.props.style, | ||
onClick: function(){ | ||
this$.setState({ | ||
open: true | ||
return this$.props.onAnchorChange(last(this$.props.values), function(){ | ||
return this$.props.onOpenChange(true, function(){ | ||
return this$.focus(); | ||
}); | ||
}); | ||
return this$.focus(); | ||
} | ||
@@ -53,96 +89,147 @@ }, div({ | ||
key: 'control' | ||
}, this.state.search.length === 0 && this.props.values.length === 0 ? div({ | ||
}, this.props.search.length === 0 && this.props.values.length === 0 ? div({ | ||
className: 'placeholder' | ||
}, this.props.placeholder) : void 8, map(function(value){ | ||
return React.createElement(this$.props.valueClass, import$({ | ||
key: value, | ||
onRemoveClick: function(e){ | ||
this$.removeValue(value); | ||
this$.clearAndFoucs(); | ||
e.preventDefault(); | ||
return e.stopPropagation(); | ||
} | ||
}, find(function(it){ | ||
return it.value === value; | ||
})( | ||
this$.props.options)) || {}); | ||
}, this.props.placeholder) : void 8, map(function(index){ | ||
return this$.props.renderValue(index, this$.props.values[index]); | ||
})( | ||
this.props.values), input({ | ||
(function(){ | ||
var i$, to$, results$ = []; | ||
for (i$ = 0, to$ = anchorIndex; i$ <= to$; ++i$) { | ||
results$.push(i$); | ||
} | ||
return results$; | ||
}())), input({ | ||
disabled: this.props.disabled, | ||
ref: 'search', | ||
type: 'text', | ||
value: this.state.search, | ||
onChange: (function(){ | ||
switch (false) { | ||
case !(this.isBelowLimit() && !outOfOptions): | ||
return function(arg$){ | ||
var value, filteredOptions; | ||
value = arg$.currentTarget.value; | ||
filteredOptions = this$.filterOptions(value); | ||
return this$.setState({ | ||
focusedOption: 0, | ||
open: filteredOptions.length > 0, | ||
search: value | ||
}); | ||
value: this.props.search, | ||
onChange: function(arg$){ | ||
var value; | ||
value = arg$.currentTarget.value; | ||
return this$.props.onSearchChange(value, function(){ | ||
if (!this$.highlightAndScrollToSelectableOption(this$.props.firstOptionIndexToHighlight(this$.props.options), 1)) { | ||
return this$.lowlightOption(); | ||
} | ||
}); | ||
}, | ||
onFocus: function(){ | ||
(function(){ | ||
return function(callback){ | ||
if (!!this$.focusLock) { | ||
return callback(this$.focusLock = false); | ||
} else { | ||
return this$.props.onOpenChange(true, function(){ | ||
return callback(true); | ||
}); | ||
} | ||
}; | ||
default: | ||
return function(){}; | ||
} | ||
}.call(this)), | ||
})()(function(result){ | ||
return this$.props.onFocus(this$.props.values, !!result ? 'event' : 'focus'); | ||
}); | ||
}, | ||
onKeyDown: function(e){ | ||
var ref$, label; | ||
switch (e.which) { | ||
case 9: | ||
this$.setState({ | ||
open: false | ||
}, function(){ | ||
return this$.props.onBlur(this$.props.values); | ||
this$.props.onOpenChange(false, function(){ | ||
return this$.props.onAnchorChange(last(this$.props.values), function(){ | ||
return this$.props.onBlur(this$.props.values, 'tab'); | ||
}); | ||
}); | ||
break; | ||
case 8: | ||
if (this$.state.search.length > 0) { | ||
if (this$.props.search.length > 0 || anchorIndex === -1) { | ||
return; | ||
} | ||
if ((ref$ = this$.removeValue(last(this$.props.values))) != null) { | ||
label = ref$.label; | ||
} | ||
if (!!label && !!this$.props.restoreOnBackspace) { | ||
this$.setState({ | ||
focusedOption: 0, | ||
open: true, | ||
search: label | ||
(function(){ | ||
var anchorIndexOnRemove, nextAnchor, valueToRemove, ref$; | ||
anchorIndexOnRemove = anchorIndex; | ||
nextAnchor = anchorIndex - 1 < 0 | ||
? undefined | ||
: this$.props.values[anchorIndex - 1]; | ||
valueToRemove = this$.props.values[anchorIndex]; | ||
return this$.props.onValuesChange((ref$ = reject(function(it){ | ||
return isEqualToObject(it, valueToRemove); | ||
}, this$.props.values)) != null | ||
? ref$ | ||
: [], function(){ | ||
return function(){ | ||
return function(callback){ | ||
if (typeof find(function(it){ | ||
return isEqualToObject(it, valueToRemove); | ||
}, this$.props.values === 'undefined')) { | ||
if (!!this$.props.restoreOnBackspace) { | ||
return this$.props.onSearchChange(this$.props.restoreOnBackspace(valueToRemove), function(){ | ||
return callback(true); | ||
}); | ||
} else { | ||
return callback(true); | ||
} | ||
} else { | ||
return callback(false); | ||
} | ||
}; | ||
}()(function(result){ | ||
if (!!result) { | ||
this$.highlightAndScrollToSelectableOption(this$.props.firstOptionIndexToHighlight(this$.props.options), 1); | ||
} | ||
if (!!result && anchorIndex === anchorIndexOnRemove && (typeof nextAnchor === 'undefined' || !!find(function(it){ | ||
return isEqualToObject(it, nextAnchor); | ||
}, this$.props.values))) { | ||
return this$.props.onAnchorChange(nextAnchor, function(){}); | ||
} | ||
}); | ||
}); | ||
} else { | ||
this$.setState({ | ||
open: false | ||
})(); | ||
cancelEvent(e); | ||
break; | ||
case 27: | ||
(function(){ | ||
if (this$.props.open) { | ||
return function(it){ | ||
return this$.props.onOpenChange(false, it); | ||
}; | ||
} else { | ||
return function(it){ | ||
return this$.props.onValuesChange([], it); | ||
}; | ||
} | ||
})()(function(){ | ||
return this$.props.onSearchChange("", function(){ | ||
return this$.focus(); | ||
}); | ||
} | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
}); | ||
} | ||
if (outOfOptions) {} else { | ||
if (this$.props.search.length === 0) { | ||
switch (e.which) { | ||
case 13: | ||
this$.selectOption(this$.state.focusedOption); | ||
this$.setState({ | ||
focusedOption: -1, | ||
open: false, | ||
search: '' | ||
}); | ||
case 37: | ||
this$.props.onAnchorChange(anchorIndex - 1 < 0 || e.metaKey | ||
? undefined | ||
: this$.props.values[clamp(anchorIndex - 1, 0, this$.props.values.length - 1)], function(){}); | ||
break; | ||
case 27: | ||
if (this$.state.open) { | ||
this$.setState({ | ||
open: false | ||
}); | ||
} else { | ||
this$.reset(); | ||
case 39: | ||
this$.props.onAnchorChange(e.metaKey | ||
? last(this$.props.values) | ||
: this$.props.values[clamp(anchorIndex + 1, 0, this$.props.values.length - 1)], function(){}); | ||
} | ||
} | ||
if (this$.props.options.length === 0) { | ||
return; | ||
} | ||
if (e.which === 13 && this$.props.open) { | ||
this$.selectHighlightedOption(anchorIndex, function(){ | ||
if (this$.props.open && !this$.highlightAndScrollToSelectableOption(this$.highlightedOption, 1)) { | ||
if (!this$.highlightAndScrollToSelectableOption(0, 1)) { | ||
return this$.lowlightOption(); | ||
} | ||
} | ||
this$.clearAndFoucs(); | ||
break; | ||
}); | ||
} else { | ||
switch (e.which) { | ||
case 38: | ||
this$.focusAdjacentOption(-1); | ||
this$.scrollLock = true; | ||
this$.highlightAndScrollToSelectableOption(this$.highlightedOption - 1, -1); | ||
break; | ||
case 40: | ||
this$.focusAdjacentOption(1); | ||
this$.scrollLock = true; | ||
this$.highlightAndScrollToSelectableOption(this$.highlightedOption + 1, 1); | ||
break; | ||
@@ -152,156 +239,230 @@ default: | ||
} | ||
e.preventDefault(); | ||
return e.stopPropagation(); | ||
} | ||
}, | ||
style: { | ||
width: Math.max(16, this.state.search.length * 16) | ||
return cancelEvent(e); | ||
} | ||
}), div({ | ||
}), map(function(index){ | ||
return this$.props.renderValue(index, this$.props.values[index]); | ||
})( | ||
(function(){ | ||
var i$, to$, results$ = []; | ||
for (i$ = anchorIndex + 1, to$ = this.props.values.length; i$ < to$; ++i$) { | ||
results$.push(i$); | ||
} | ||
return results$; | ||
}.call(this))), div({ | ||
className: 'reset', | ||
onClick: function(e){ | ||
this$.reset(); | ||
this$.clearAndFoucs(); | ||
e.preventDefault(); | ||
return e.stopPropagation(); | ||
(function(){ | ||
return this$.props.onValuesChange([], function(){ | ||
return this$.props.onSearchChange("", function(){ | ||
return this$.focus(); | ||
}); | ||
}); | ||
})(); | ||
return cancelEvent(e); | ||
} | ||
}, '×'), div({ | ||
className: 'arrow' | ||
}, null)), showOptions ? div({ | ||
}, null)), this.props.open ? div({ | ||
className: 'options' | ||
}, map(function(optionObject){ | ||
var index, value, ref$; | ||
index = optionObject.index, value = optionObject.value; | ||
return div({ | ||
ref: "option-" + index, | ||
key: value + "", | ||
onClick: function(e){ | ||
this$.setState({ | ||
open: false | ||
}, function(){ | ||
this$.selectOption(index); | ||
return this$.clearAndFoucs(); | ||
}); | ||
e.preventDefault(); | ||
return e.stopPropagation(); | ||
}, | ||
onMouseOver: function(){ | ||
return this$.setState({ | ||
focusedOption: index | ||
}); | ||
}, | ||
onMouseOut: function(){ | ||
return this$.setState({ | ||
focusedOption: -1 | ||
}); | ||
}, this.props.options.length === 0 | ||
? this.props.renderNoResultsFound() | ||
: map(function(index){ | ||
var option; | ||
option = this$.props.options[index]; | ||
return div(import$({ | ||
className: 'option-wrapper', | ||
ref: "option-" + index, | ||
key: index + "", | ||
onMouseMove: function(arg$){ | ||
var currentTarget; | ||
currentTarget = arg$.currentTarget; | ||
if (this$.scrollLock) { | ||
this$.scrollLock = false; | ||
} | ||
}, | ||
onMouseOut: function(){ | ||
if (!this$.scrollLock) { | ||
this$.lowlightOption(); | ||
} | ||
} | ||
}, (function(){ | ||
switch (false) { | ||
case !(typeof (option != null ? option.selectable : void 8) === 'boolean' && !option.selectable): | ||
return { | ||
onClick: cancelEvent | ||
}; | ||
default: | ||
return { | ||
onClick: function(e){ | ||
this$.selectHighlightedOption(anchorIndex, function(){}); | ||
}, | ||
onMouseOver: function(arg$){ | ||
var currentTarget; | ||
currentTarget = arg$.currentTarget; | ||
if (!this$.scrollLock) { | ||
this$.highlightOption(index); | ||
} | ||
} | ||
}; | ||
} | ||
}())), this$.props.renderOption(index, option)); | ||
})( | ||
(function(){ | ||
var i$, to$, results$ = []; | ||
for (i$ = 0, to$ = this.props.options.length; i$ < to$; ++i$) { | ||
results$.push(i$); | ||
} | ||
}, React.createElement(this$.props.optionClass, (ref$ = import$({}, optionObject), ref$.addOptions = this$.props.addOptions, ref$.focused = index === this$.state.focusedOption, ref$))); | ||
})( | ||
this.filterOptions(this.state.search))) : void 8); | ||
return results$; | ||
}.call(this)))) : void 8); | ||
}, | ||
getInitialState: function(){ | ||
return { | ||
focusedOption: 0, | ||
open: false, | ||
search: '' | ||
componentDidMount: function(){ | ||
var this$ = this; | ||
this.externalClickListener = function(arg$){ | ||
var target, domNodeContains; | ||
target = arg$.target; | ||
domNodeContains = function(element){ | ||
if (typeof element === 'undefined' || element === null) { | ||
return false; | ||
} | ||
if (element === this$.getDOMNode()) { | ||
return true; | ||
} | ||
return domNodeContains(element.parentElement); | ||
}; | ||
if (!domNodeContains(target)) { | ||
this$.props.onOpenChange(false); | ||
return this$.props.onBlur(this$.props.values, 'click'); | ||
} | ||
}; | ||
document.addEventListener('click', this.externalClickListener, true); | ||
}, | ||
componentDidUpdate: function(){ | ||
var optionElement, ref$, ref1$, parentElement, optionHeight; | ||
if (this.state.focusedOption === -1) { | ||
return; | ||
componentWillUnmount: function(){ | ||
document.removeEventListener('click', this.externalClickListener, true); | ||
}, | ||
componentDidUpdate: function(prevProps, prevState){ | ||
var x$, $search; | ||
if (this.props.open && !prevProps.open && (this.highlightedOption = -1)) { | ||
this.highlightAndScrollToSelectableOption(this.props.firstOptionIndexToHighlight(this.props.options), 1); | ||
this.focus(); | ||
} | ||
if ((optionElement = this != null ? (ref$ = this.refs) != null ? (ref1$ = ref$["option-" + this.state.focusedOption]) != null ? ref1$.getDOMNode() : void 8 : void 8 : void 8) != null) { | ||
parentElement = optionElement.parentElement; | ||
if (!this.props.open && prevProps.open) { | ||
this.highlightedOption = -1; | ||
} | ||
if (!optionElement) { | ||
return; | ||
x$ = $search = this.refs.search.getDOMNode(); | ||
x$.style.width = 0; | ||
x$.style.width = $search.scrollWidth; | ||
return x$; | ||
}, | ||
componentWillReceiveProps: function(props){ | ||
if ((typeof this.props.disabled === 'undefined' || this.props.disabled === false) && (typeof props.disabled !== 'undefined' && props.disabled === true)) { | ||
this.props.onOpenChange(false); | ||
} | ||
optionHeight = optionElement.offsetHeight - 1; | ||
if (optionElement.offsetTop - parentElement.scrollTop > parentElement.offsetHeight) { | ||
parentElement.scrollTop = optionElement.offsetTop - parentElement.offsetHeight + optionHeight; | ||
} else if (optionElement.offsetTop - parentElement.scrollTop + optionHeight < 0) { | ||
parentElement.scrollTop = optionElement.offsetTop; | ||
} | ||
}, | ||
clearAndFoucs: function(){ | ||
this.setState({ | ||
search: '' | ||
}); | ||
this.focus(); | ||
}, | ||
filterOptions: function(search){ | ||
var ref$, addOptions, optionClass, options, values, result; | ||
ref$ = this.props, addOptions = ref$.addOptions, optionClass = ref$.optionClass, options = ref$.options, values = ref$.values; | ||
result = optionClass.filter(filter(function(arg$){ | ||
var value; | ||
value = arg$.value; | ||
return !in$(value, values); | ||
})( | ||
options), search, { | ||
addOptions: addOptions | ||
}); | ||
return map(function(index){ | ||
var ref$; | ||
return ref$ = result[index], ref$.index = index, ref$; | ||
})( | ||
(function(){ | ||
var i$, to$, results$ = []; | ||
for (i$ = 0, to$ = result.length; i$ < to$; ++i$) { | ||
results$.push(i$); | ||
} | ||
return results$; | ||
}())); | ||
}, | ||
focus: function(){ | ||
this.refs.search.getDOMNode().focus(); | ||
if (this.refs.search.getDOMNode() !== document.activeElement) { | ||
this.focusLock = true; | ||
this.refs.search.getDOMNode().focus(); | ||
} | ||
}, | ||
focusAdjacentOption: function(direction){ | ||
this.setState({ | ||
focusedOption: clamp(this.state.focusedOption + direction, 0, this.filterOptions(this.state.search).length - 1), | ||
open: true | ||
}); | ||
blur: function(){ | ||
this.refs.search.getDOMNode().blur(); | ||
this.props.onBlur(this.props.values, 'blur'); | ||
}, | ||
isBelowLimit: function(props){ | ||
var ref$, maxItems, values; | ||
if ((ref$ = props || this.props) != null) { | ||
maxItems = ref$.maxItems, values = ref$.values; | ||
highlightOption: function(index){ | ||
var x$, optionElement, ref$, ref1$; | ||
this.lowlightOption(); | ||
this.highlightedOption = index; | ||
x$ = optionElement = (ref$ = this.refs) != null ? (ref1$ = ref$["option-" + index]) != null ? ref1$.getDOMNode() : void 8 : void 8; | ||
if (x$ != null) { | ||
x$.className = "option-wrapper focused"; | ||
} | ||
return typeof maxItems === 'undefined' || values.length < maxItems; | ||
return optionElement; | ||
}, | ||
removeValue: function(value){ | ||
var option, newOption; | ||
if ((option = find(function(it){ | ||
return it.value === value; | ||
})( | ||
this.props.options)) != null) { | ||
newOption = option.newOption; | ||
lowlightOption: function(){ | ||
var ref$, ref1$, ref2$; | ||
if ((ref$ = this.refs) != null) { | ||
if ((ref1$ = ref$["option-" + this.highlightedOption]) != null) { | ||
if ((ref2$ = ref1$.getDOMNode()) != null) { | ||
ref2$.className = 'option-wrapper'; | ||
} | ||
} | ||
} | ||
if (!!newOption) { | ||
this.props.onOptionsChange(reject(function(it){ | ||
return it.value === value; | ||
})( | ||
this.props.options)); | ||
this.highlightedOption = -1; | ||
}, | ||
highlightAndScrollToOption: function(index){ | ||
var optionElement, parentElement, optionHeight; | ||
if ((optionElement = this.highlightOption(index)) != null) { | ||
parentElement = optionElement.parentElement; | ||
} | ||
this.props.onChange(reject((function(it){ | ||
return it === value; | ||
}))( | ||
this.props.values)); | ||
return option; | ||
if (!!optionElement) { | ||
optionHeight = optionElement.offsetHeight - 1; | ||
if (optionElement.offsetTop - parentElement.scrollTop >= parentElement.offsetHeight) { | ||
parentElement.scrollTop = optionElement.offsetTop - parentElement.offsetHeight + optionHeight; | ||
} else if (optionElement.offsetTop - parentElement.scrollTop + optionHeight <= 0) { | ||
parentElement.scrollTop = optionElement.offsetTop; | ||
} | ||
} | ||
}, | ||
reset: function(){ | ||
this.props.onChange([]); | ||
highlightAndScrollToSelectableOption: function(index, direction){ | ||
var this$ = this; | ||
return function(){ | ||
if (!this$.props.open) { | ||
return function(it){ | ||
return this$.props.onOpenChange(true, it); | ||
}; | ||
} else { | ||
return function(it){ | ||
return it(); | ||
}; | ||
} | ||
}()(function(){ | ||
var option, ref$, ref1$; | ||
if (index < 0 || index >= this$.props.options.length) { | ||
return false; | ||
} else { | ||
option = (ref$ = this$.props) != null ? (ref1$ = ref$.options) != null ? ref1$[index] : void 8 : void 8; | ||
if (typeof (option != null ? option.selectable : void 8) === 'boolean' && !option.selectable) { | ||
return this$.highlightAndScrollToSelectableOption(index + direction, direction); | ||
} else { | ||
this$.highlightAndScrollToOption(index); | ||
return true; | ||
} | ||
} | ||
}); | ||
}, | ||
selectOption: function(index){ | ||
var filteredOptions, option, newOption, value; | ||
filteredOptions = this.filterOptions(this.state.search); | ||
if ((option = filteredOptions != null ? filteredOptions[index] : void 8) != null) { | ||
newOption = option.newOption, value = option.value; | ||
selectHighlightedOption: function(anchorIndex, callback){ | ||
var option, ref$, this$ = this; | ||
if (this.highlightedOption !== -1) { | ||
option = (ref$ = this.props.options) != null ? ref$[this.highlightedOption] : void 8; | ||
this.props.onValuesChange(map(function(it){ | ||
return this$.props.values[it]; | ||
}, (function(){ | ||
var i$, to$, results$ = []; | ||
for (i$ = 0, to$ = anchorIndex; i$ <= to$; ++i$) { | ||
results$.push(i$); | ||
} | ||
return results$; | ||
}())).concat([option], map(function(it){ | ||
return this$.props.values[it]; | ||
}, (function(){ | ||
var i$, to$, results$ = []; | ||
for (i$ = anchorIndex + 1, to$ = this.props.values.length; i$ < to$; ++i$) { | ||
results$.push(i$); | ||
} | ||
return results$; | ||
}.call(this)))), function(){ | ||
var value; | ||
value = find(function(it){ | ||
return isEqualToObject(it, option); | ||
}, this$.props.values); | ||
if (!!value) { | ||
return this$.props.onSearchChange("", function(){ | ||
return this$.props.onAnchorChange(value, callback); | ||
}); | ||
} else { | ||
return callback(); | ||
} | ||
}); | ||
} | ||
if (!!newOption) { | ||
this.props.onOptionsChange([option].concat(this.props.options)); | ||
} | ||
if (!!value) { | ||
this.props.onChange(this.props.values.concat(value)); | ||
} | ||
} | ||
@@ -314,7 +475,2 @@ }); | ||
} | ||
function in$(x, xs){ | ||
var i = -1, l = xs.length >>> 0; | ||
while (++i < l) if (x === xs[i]) return true; | ||
return false; | ||
} | ||
}).call(this); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
63181
3
11
1331
128
0
21
1
1
+ Addedprelude-extension@0.0.5(transitive)
- Removedjquery-browserify@^1.8.1
- Removedjquery-browserify@1.8.1(transitive)
- Removedprelude-extension@0.0.4(transitive)
Updatedprelude-extension@0.0.5