UNPKG

ldx-widgets

Version:

widgets

212 lines (166 loc) 6.01 kB
React = require 'react' PropTypes = require 'prop-types' createClass = require 'create-react-class' assign = require 'lodash/assign' cloneDeep = require 'lodash/cloneDeep' isEqual = require 'lodash/isEqual' animationMixin = require '../mixins/animation_mixin' Pvr = React.createFactory(require './pvr') SelectPvrOption = React.createFactory(require './select_pvr_option') {div} = require 'react-dom-factories' ###& @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: -> {defaultSelected, options, optionHeight} = @props selectedOption: defaultSelected or null aggregateOptionsHeight: options.length * optionHeight + options.length * 1 openSubOptions: null getDefaultProps: -> { options: [] styleMixin: {} headerTitle: null headerClass: '' hideSelected: no optionHeight: 36 noWrapOptions: no pvrProps: {} canDeselect: no } render: -> {styleMixin, options, hideSelected, optionHeight, headerTitle, headerClass, noWrapOptions, disabled, className, maxHeight, close, canDeselect} = @props {selectedOption, scale, aggregateOptionsHeight, openSubOptions} = @state style = {} pvrProps = cloneDeep @props.pvrProps @hasHeader = headerTitle? unless pvrProps.height? pvrProps.height = aggregateOptionsHeight - (if hideSelected then optionHeight else 0) if @hasHeader pvrProps.height += 34 if maxHeight? and pvrProps.height > maxHeight pvrProps.height = maxHeight assign style, styleMixin if pvrProps.styleMixin?.maxHeight? style.maxHeight = pvrProps.styleMixin.maxHeight style.height = pvrProps.height if pvrProps.width style.width = pvrProps.width optionEls = [] for option in options {children, label, id, value, subLabel} = option optionsEqual = @compareOptions(option) continue if hideSelected and optionsEqual childItems = [] subOptionsHeight = 0 if children? for chld in children when chld? opth = chld.optionHeight or optionHeight subOptionsHeight += opth childItems.push SelectPvrOption { key: chld.id or chld.value hasSubLabel: chld.subLabel? option: chld optionHeight: opth isSelected: @compareOptions(chld) canDeselect: chld.canDeselect handleChange: chld.handleChange or @handleChange noWrapOptions: chld.noWrapOptions customClass: chld.customClass } optionEls.push SelectPvrOption { hasSubLabel: subLabel? option: option optionHeight: optionHeight key: id or value isSelected: optionsEqual canDeselect: canDeselect handleChange: @handleChange noWrapOptions: noWrapOptions subOptionsHeight: subOptionsHeight setOpenSubOptions: @setOpenSubOptions isOpen: childItems.length and openSubOptions is option }, childItems pvrProps.scale = scale pvrProps.close = close pvrProps.element = div { key: 'select-pvr' className: 'select-pvr' style: style }, [ if @hasHeader div { key: 'header' className: "header plain-pvr-content-item #{headerClass}" }, headerTitle div { key: 'inner-rows' }, optionEls ] Pvr(pvrProps) handleChange: (option) -> @setState selectedOption: option @props.onChange option @props.close() setOpenSubOptions: (option, adjust) -> {options, optionHeight} = @props agg = options.length * optionHeight + (options.length * 1) + adjust @setState openSubOptions: option aggregateOptionsHeight: agg compareOptions: (option) -> {selectedOption} = @state {label} = option if typeof selectedOption is 'string' then return selectedOption is label else if typeof selectedOption is 'object' then return isEqual(selectedOption, option) module.exports = SelectPvr