ldx-widgets
Version:
widgets
223 lines (199 loc) • 8.05 kB
JavaScript
(function() {
var PropTypes, Pvr, React, SelectPvr, SelectPvrOption, _, animationMixin, createClass, div;
React = require('react');
PropTypes = require('prop-types');
createClass = require('create-react-class');
_ = require('lodash');
animationMixin = require('../mixins/animation_mixin');
Pvr = React.createFactory(require('./pvr'));
SelectPvrOption = React.createFactory(require('./select_pvr_option'));
div = React.DOM.div;
/*&
@general
Select popover menu with sub-option capability
@props.options - [Array] - Required
array of objects containing at minimum a label and value attribute
optionally a subLabel property can be passed
@props.defaultSelected - [Object|String] - Optional
value of the option selected by default
@props.close - [Function] - Required
func that closes the popover
@props.styleMixin - [Object] - Optional
object containing any style properties to mixin with and/or overrride the defaults
note that width height are passed separately so they can have defaults and auto settings
passing widt/height in this object could cause issues
@props.onChange - [Function] - Required
method to call when the non selected option is clicked
@props.hideSelected - [Boolean] - Optional
when on, the defaultSelected option will be removed from the list
@props.headerTitle - [String] - Optional
optional title String for popover header
@props.headerClass - [String] - Optional
optional class for popover header
@props.maxHeight - [Number] - Optional
the maximum height the popover should be. used to set height on the pvr if this is
lower than the computed height.
@props.pvrProps - [Object] - Optional
properties germane to PVR wrapper: width, height, anchor, hAdjust, vAdjust, direction
&
*/
SelectPvr = createClass({
displayName: 'SelectPvr',
mixins: [animationMixin],
enterStateStart: {
scale: .9
},
enterStateEnd: {
scale: 1
},
enterEasing: 'easeOutElastic',
enterDuration: 600,
propTypes: {
options: PropTypes.array.isRequired,
styleMixin: PropTypes.object,
headerClass: PropTypes.string,
close: PropTypes.func.isRequired,
optionHeight: PropTypes.number,
onChange: PropTypes.func.isRequired,
maxHeight: PropTypes.number,
pvrProps: PropTypes.object,
canDeselect: PropTypes.bool,
noWrapOptions: PropTypes.bool,
defaultSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
},
getInitialState: function() {
var defaultSelected, optionHeight, options, ref;
ref = this.props, defaultSelected = ref.defaultSelected, options = ref.options, optionHeight = ref.optionHeight;
return {
selectedOption: defaultSelected || null,
aggregateOptionsHeight: options.length * optionHeight + options.length * 1,
openSubOptions: null
};
},
getDefaultProps: function() {
return {
options: [],
styleMixin: {},
headerTitle: null,
headerClass: '',
hideSelected: false,
optionHeight: 36,
noWrapOptions: false,
pvrProps: {},
canDeselect: false
};
},
render: function() {
var aggregateOptionsHeight, canDeselect, childItems, children, chld, className, close, disabled, headerClass, headerTitle, hideSelected, i, id, j, label, len, len1, maxHeight, noWrapOptions, openSubOptions, opth, option, optionEls, optionHeight, options, optionsEqual, pvrProps, ref, ref1, ref2, scale, selectedOption, style, styleMixin, subLabel, subOptionsHeight, value;
ref = this.props, styleMixin = ref.styleMixin, options = ref.options, hideSelected = ref.hideSelected, optionHeight = ref.optionHeight, headerTitle = ref.headerTitle, headerClass = ref.headerClass, noWrapOptions = ref.noWrapOptions, disabled = ref.disabled, className = ref.className, maxHeight = ref.maxHeight, close = ref.close, canDeselect = ref.canDeselect;
ref1 = this.state, selectedOption = ref1.selectedOption, scale = ref1.scale, aggregateOptionsHeight = ref1.aggregateOptionsHeight, openSubOptions = ref1.openSubOptions;
style = {};
pvrProps = _.cloneDeep(this.props.pvrProps);
this.hasHeader = headerTitle != null;
if (pvrProps.height == null) {
pvrProps.height = aggregateOptionsHeight - (hideSelected ? optionHeight : 0);
}
if (this.hasHeader) {
pvrProps.height += 34;
}
if ((maxHeight != null) && pvrProps.height > maxHeight) {
pvrProps.height = maxHeight;
}
_.assign(style, styleMixin);
if (((ref2 = pvrProps.styleMixin) != null ? ref2.maxHeight : void 0) != null) {
style.maxHeight = pvrProps.styleMixin.maxHeight;
}
style.height = pvrProps.height;
if (pvrProps.width) {
style.width = pvrProps.width;
}
optionEls = [];
for (i = 0, len = options.length; i < len; i++) {
option = options[i];
children = option.children, label = option.label, id = option.id, value = option.value, subLabel = option.subLabel;
optionsEqual = this.compareOptions(option);
if (hideSelected && optionsEqual) {
continue;
}
childItems = [];
subOptionsHeight = 0;
if (children != null) {
for (j = 0, len1 = children.length; j < len1; j++) {
chld = children[j];
if (!(chld != null)) {
continue;
}
opth = chld.optionHeight || optionHeight;
subOptionsHeight += opth;
childItems.push(SelectPvrOption({
key: chld.id || chld.value,
hasSubLabel: chld.subLabel != null,
option: chld,
optionHeight: opth,
isSelected: this.compareOptions(chld),
canDeselect: chld.canDeselect,
handleChange: chld.handleChange || this.handleChange,
noWrapOptions: chld.noWrapOptions,
customClass: chld.customClass
}));
}
}
optionEls.push(SelectPvrOption({
hasSubLabel: subLabel != null,
option: option,
optionHeight: optionHeight,
key: id || value,
isSelected: optionsEqual,
canDeselect: canDeselect,
handleChange: this.handleChange,
noWrapOptions: noWrapOptions,
subOptionsHeight: subOptionsHeight,
setOpenSubOptions: this.setOpenSubOptions,
isOpen: childItems.length && openSubOptions === option
}, childItems));
}
pvrProps.scale = scale;
pvrProps.close = close;
pvrProps.element = div({
key: 'select-pvr',
className: 'select-pvr',
style: style
}, [
this.hasHeader ? div({
key: 'header',
className: "header plain-pvr-content-item " + headerClass
}, headerTitle) : void 0, div({
key: 'inner-rows'
}, optionEls)
]);
return Pvr(pvrProps);
},
handleChange: function(option) {
this.setState({
selectedOption: option
});
this.props.onChange(option);
return this.props.close();
},
setOpenSubOptions: function(option, adjust) {
var agg, optionHeight, options, ref;
ref = this.props, options = ref.options, optionHeight = ref.optionHeight;
agg = options.length * optionHeight + (options.length * 1) + adjust;
return this.setState({
openSubOptions: option,
aggregateOptionsHeight: agg
});
},
compareOptions: function(option) {
var label, selectedOption;
selectedOption = this.state.selectedOption;
label = option.label;
if (typeof selectedOption === 'string') {
return selectedOption === label;
} else if (typeof selectedOption === 'object') {
return _.isEqual(selectedOption, option);
}
}
});
module.exports = SelectPvr;
}).call(this);