ldx-widgets
Version:
widgets
277 lines (247 loc) • 9.39 kB
JavaScript
(function() {
var CircleXButton, DOWN_ARROW, ENTER, ESCAPE, FormValidation, LEFT_ARROW, PropTypes, RIGHT_ARROW, React, SPACE, SelectInputCustom, SelectInputCustomOptions, TAB, UP_ARROW, _, alphaNumericKeyCode, createClass, div, option, ref, ref1, select;
React = require('react');
createClass = require('create-react-class');
PropTypes = require('prop-types');
_ = require('lodash');
ref = require('../constants/keyboard'), DOWN_ARROW = ref.DOWN_ARROW, RIGHT_ARROW = ref.RIGHT_ARROW, LEFT_ARROW = ref.LEFT_ARROW, UP_ARROW = ref.UP_ARROW, ENTER = ref.ENTER, SPACE = ref.SPACE, ESCAPE = ref.ESCAPE, TAB = ref.TAB;
alphaNumericKeyCode = require('../utils').alphaNumericKeyCode;
FormValidation = require('../mixins/form_validation');
CircleXButton = React.createFactory(require('./circle_x_button'));
SelectInputCustomOptions = React.createFactory(require('./select_input_custom_options'));
ref1 = React.DOM, div = ref1.div, select = ref1.select, option = ref1.option;
/*&
@general
Filterable select menu. This component lives on the overlay layer, and requires integrated context methods closeOverlay and openOverlay within the application.
@props.options - [Array] - Required
Full list of options to display on component
@props.value - [String|Object] - Optional
The value that corresponds to the option object with the matching value
@props.selectText - [String] - Optional
Text displayed as the default value
@props.onChange - [Function] - Required
Function fired when a change is made to the selection
@props.tabIndex - [Number] - Optional
Tab order index
@props.disabled - [Boolean] - Optional
Disabled state of the component
@props.isFilter - [Boolean] - Optional
Show/hide the filter typeahead input. Default is no
@props.returnFullObjects - [Boolean] - Optional
Determine whether `getValue` returns the full option object, or just the default value string
@props.placeholder - [String] - Optional
Placeholder text for the filter input
@props.valueField - [String] - Optional
The name of the key used to reference the value on the option object
@props.labelField - [String] - Optional
The name of the key used to reference the label on the option object
@props.width - [Number] - Optional
The width of the menu popover
@props.height - [Number] - Optional
The height of the menu popover
@props.optionHeight - [Number] - Optional
The fixed height of each menu option
&
*/
SelectInputCustom = createClass({
displayName: 'SelectInputCustom',
mixins: [FormValidation],
contextTypes: {
openOverlay: PropTypes.func,
closeOverlay: PropTypes.func
},
propTypes: {
options: PropTypes.array.isRequired,
selectText: PropTypes.string,
onChange: PropTypes.func.isRequired,
tabIndex: PropTypes.number,
disabled: PropTypes.bool,
isFilter: PropTypes.bool,
returnFullObjects: PropTypes.bool,
placeholder: PropTypes.string,
valueField: PropTypes.string,
labelField: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
optionHeight: PropTypes.number,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
nibColor: PropTypes.string
},
getDefaultProps: function() {
return {
options: [],
selectText: 'Select from list...',
placeholder: 'Filter options',
valueField: 'value',
labelField: 'title',
width: 250,
height: 400,
isFilter: false,
nibColor: 'white',
optionHeight: 20
};
},
getInitialState: function() {
var ref2, val, value, valueField;
ref2 = this.props, value = ref2.value, valueField = ref2.valueField;
val = '';
if (typeof value === 'object') {
val = value[valueField];
} else {
val = value;
}
return {
value: val
};
},
render: function() {
var disabled, id, isFilter, labelField, optionItems, options, ref2, roomForCircleXStyle, selectText, tabIndex, value, valueField;
ref2 = this.props, options = ref2.options, id = ref2.id, selectText = ref2.selectText, valueField = ref2.valueField, labelField = ref2.labelField, tabIndex = ref2.tabIndex, disabled = ref2.disabled, isFilter = ref2.isFilter;
value = this.state.value;
optionItems = [];
optionItems.push(option({
key: "none",
value: ""
}, selectText));
options.forEach((function(_this) {
return function(o, i) {
return optionItems.push(option({
key: i,
value: o[valueField]
}, o[labelField]));
};
})(this));
this.getErrors();
roomForCircleXStyle = value && !disabled ? "x-room" : "";
return div({
className: "field-wrap filter-select " + this.invalidClass + " " + roomForCircleXStyle
}, [
select({
key: 'select',
ref: (function(_this) {
return function(control) {
return _this.control = control;
};
})(this),
tabIndex: tabIndex,
id: id,
disabled: disabled,
value: value,
onMouseDown: this.handleNativeEvent,
onKeyDown: this.handleNativeEvent
}, optionItems), value && !disabled ? CircleXButton({
key: 'clear',
tabIndex: tabIndex,
ref: (function(_this) {
return function(clearBtn) {
return _this.clearBtn = clearBtn;
};
})(this),
onClick: this.clear
}) : void 0, this.validationErrors.length ? div({
className: 'field-errors-show',
key: 'errors'
}, [
div({
className: 'field-errors',
key: 'err'
}, ul({
className: 'field-errors-list'
}, this.validationErrors))
]) : void 0
]);
},
handleNativeEvent: function(e) {
var alphaNum, closeKeys, height, isCloseKey, isFilter, isOpenKey, keyCode, labelField, nibColor, openKeys, optionHeight, options, overlay, placeholder, ref2, selectText, value, valueField, width;
keyCode = e.keyCode;
ref2 = this.props, options = ref2.options, selectText = ref2.selectText, labelField = ref2.labelField, valueField = ref2.valueField, height = ref2.height, width = ref2.width, placeholder = ref2.placeholder, isFilter = ref2.isFilter, nibColor = ref2.nibColor, optionHeight = ref2.optionHeight;
value = this.state.value;
openKeys = [DOWN_ARROW, RIGHT_ARROW, LEFT_ARROW, UP_ARROW, ENTER, SPACE];
closeKeys = [ESCAPE, TAB];
if (((options.length + 1) * optionHeight) < height) {
height = (options.length + 2) * optionHeight;
}
overlay = {
activeComponent: 'pvr',
close: this.context.closeOverlay,
direction: 'below',
element: {
key: 'fso',
options: options,
onChange: this.handleChange,
labelField: labelField,
valueField: valueField,
placeholder: placeholder,
value: value,
SelectEl: this,
isFilter: isFilter
},
width: width,
height: height,
anchor: e.currentTarget,
noBackdrop: true,
nibColor: nibColor,
optionHeight: optionHeight
};
if (keyCode != null) {
isOpenKey = openKeys.indexOf(keyCode) > -1;
isCloseKey = closeKeys.indexOf(keyCode) > -1;
alphaNum = alphaNumericKeyCode(keyCode);
if (isOpenKey || alphaNum) {
e.preventDefault();
e.stopPropagation();
if (alphaNum) {
overlay.element.filter = e.key;
}
overlay.element = SelectInputCustomOptions(overlay.element);
this.context.openOverlay(overlay);
} else if (isCloseKey) {
if (keyCode !== TAB) {
e.preventDefault();
}
this.context.closeOverlay();
}
return;
}
overlay.element = SelectInputCustomOptions(overlay.element);
e.preventDefault();
return this.context.openOverlay(overlay);
},
handleChange: function(value, cb) {
return this.setState({
value: value
}, (function(_this) {
return function() {
_this.props.onChange(value);
_this.focus();
return typeof cb === "function" ? cb() : void 0;
};
})(this));
},
clear: function() {
return this.handleChange('');
},
focus: function() {
return this.control.focus();
},
getValue: function() {
var ref2, returnFullObjects, valueField;
ref2 = this.props, returnFullObjects = ref2.returnFullObjects, valueField = ref2.valueField;
if (returnFullObjects) {
return _.find(this.props.options, (function(_this) {
return function(o) {
var v;
v = o[valueField];
if (typeof v === 'number') {
v = v.toString();
}
return v === _this.control.value;
};
})(this));
} else {
return this.control.value;
}
}
});
module.exports = SelectInputCustom;
}).call(this);