|
| 1 | +React = require 'react' |
| 2 | +componentWidthMixin = require 'react-component-width-mixin' |
| 3 | + |
| 4 | +module.exports = React.createClass |
| 5 | + displayName: "ImageGrid" |
| 6 | + mixins: [componentWidthMixin] |
| 7 | + |
| 8 | + propTypes: |
| 9 | + children: React.PropTypes.any.isRequired |
| 10 | + |
| 11 | + getInitialState: -> |
| 12 | + width: 0 |
| 13 | + |
| 14 | + getDefaultProps: -> |
| 15 | + margin: 10 |
| 16 | + targetWidth: 200 |
| 17 | + widthHeightRatio: 1 |
| 18 | + |
| 19 | + render: -> |
| 20 | + if @state.componentWidth isnt 0 |
| 21 | + [imageWidth, imagesPerRow] = @calculateImageWidth() |
| 22 | + return ( |
| 23 | + <div className="image-grid #{@props.className}" style={{overflow: "hidden"}}> |
| 24 | + {React.Children.map(@props.children, (child, i) => |
| 25 | + if imagesPerRow is 1 |
| 26 | + marginRight = 0 |
| 27 | + else if i isnt 0 and (i + 1) % imagesPerRow is 0 |
| 28 | + marginRight = 0 |
| 29 | + else |
| 30 | + marginRight = @props.margin |
| 31 | + |
| 32 | + return ( |
| 33 | + React.DOM.div({ |
| 34 | + className: "image-wrapper" |
| 35 | + style: { |
| 36 | + width: "#{imageWidth}px" |
| 37 | + height: "#{imageWidth*@props.widthHeightRatio}px" |
| 38 | + display: "inline-block" |
| 39 | + overflow: "hidden" |
| 40 | + position: "relative" |
| 41 | + "margin-right": "#{marginRight}px" |
| 42 | + "margin-bottom": "#{@props.margin}px" |
| 43 | + } |
| 44 | + }, child) |
| 45 | + ) |
| 46 | + )} |
| 47 | + </div> |
| 48 | + ) |
| 49 | + else |
| 50 | + <div /> |
| 51 | + |
| 52 | + calculateImageWidth: -> |
| 53 | + # Calculate the # of images per row to place. |
| 54 | + imageCount = React.Children.count(@props.children) |
| 55 | + imagesPerRow = Math.round(@state.componentWidth/@props.targetWidth) |
| 56 | + |
| 57 | + # There has to be at least one image per row. |
| 58 | + imagesPerRow = Math.max(imagesPerRow, 1) |
| 59 | + if imagesPerRow > imageCount |
| 60 | + imagesPerRow = imageCount |
| 61 | + |
| 62 | + # Calculate the per-image width with space for in-between |
| 63 | + # images subtracted |
| 64 | + rawWidth = @state.componentWidth / imagesPerRow |
| 65 | + marginRightOffset = ((@props.margin * imagesPerRow) - @props.margin) / imagesPerRow |
| 66 | + imageWidth = rawWidth - marginRightOffset - 0.25 |
| 67 | + |
| 68 | + # Don't get too big. |
| 69 | + maxWidth = if @props.maxWidth? then @props.maxWidth else @props.targetWidth * 1.5 |
| 70 | + imageWidth = Math.min(imageWidth, maxWidth) |
| 71 | + |
| 72 | + return [imageWidth, imagesPerRow] |
0 commit comments