ldx-widgets
Version:
widgets
212 lines (166 loc) • 6.01 kB
text/coffeescript
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'
###&
Select popover menu with sub-option capability
.options - [Array] - Required
array of objects containing at minimum a label and value attribute
optionally a subLabel property can be passed
.defaultSelected - [Object|String] - Optional
value of the option selected by default
.close - [Function] - Required
func that closes the popover
.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
.onChange - [Function] - Required
method to call when the non selected option is clicked
.hideSelected - [Boolean] - Optional
when on, the defaultSelected option will be removed from the list
.headerTitle - [String] - Optional
optional title String for popover header
.headerClass - [String] - Optional
optional class for popover header
.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.
.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} =
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} =
{selectedOption, scale, aggregateOptionsHeight, openSubOptions} =
style = {}
pvrProps = cloneDeep .pvrProps
= headerTitle?
unless pvrProps.height?
pvrProps.height = aggregateOptionsHeight - (if hideSelected then optionHeight else 0)
if
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 =
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:
canDeselect: chld.canDeselect
handleChange: chld.handleChange or
noWrapOptions: chld.noWrapOptions
customClass: chld.customClass
}
optionEls.push SelectPvrOption {
hasSubLabel: subLabel?
option: option
optionHeight: optionHeight
key: id or value
isSelected: optionsEqual
canDeselect: canDeselect
handleChange:
noWrapOptions: noWrapOptions
subOptionsHeight: subOptionsHeight
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
div {
key: 'header'
className: "header plain-pvr-content-item #{headerClass}"
}, headerTitle
div {
key: 'inner-rows'
}, optionEls
]
Pvr(pvrProps)
handleChange: (option) ->
selectedOption: option
.onChange option
.close()
setOpenSubOptions: (option, adjust) ->
{options, optionHeight} =
agg = options.length * optionHeight + (options.length * 1) + adjust
openSubOptions: option
aggregateOptionsHeight: agg
compareOptions: (option) ->
{selectedOption} =
{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