From b7b185386b3ea062b58c6bc460c6797f00da3f75 Mon Sep 17 00:00:00 2001 From: Nicole Sullivan Date: Tue, 16 Dec 2014 11:42:02 -0500 Subject: [PATCH] feat(react-media): Media component rendered in jsx - Only takes images for now, we'll have separate stories for icons, svg, video once those components are built [Finishes #84493762] Signed-off-by: Geoff Pleiss --- src/pivotal-ui/components/media.scss | 36 ++++ src/pivotal-ui/javascripts/media.jsx | 80 ++++++++ .../javascripts/pivotal-ui-react.js | 2 + test/spec/javascripts/media_spec.js | 177 ++++++++++++++++++ 4 files changed, 295 insertions(+) create mode 100644 src/pivotal-ui/javascripts/media.jsx create mode 100644 test/spec/javascripts/media_spec.js diff --git a/src/pivotal-ui/components/media.scss b/src/pivotal-ui/components/media.scss index bbe006c5f..5f746ee0e 100644 --- a/src/pivotal-ui/components/media.scss +++ b/src/pivotal-ui/components/media.scss @@ -233,3 +233,39 @@ For example, `.media-stackable-xs` is stacked on screen sizes from 0-480px and t width: 1000000px; } } + + +/*doc +--- +title: React Media +name: media_react +category: Beta +--- + +The images or other media can be aligned top, middle, or bottom. The default is top aligned. + +The base button renderer. You won't really interact with this directly. + +```html_example +
+``` + +```jsx_example +React.render( + + something + , + document.getElementById('media-example') +); +``` + + +*/ diff --git a/src/pivotal-ui/javascripts/media.jsx b/src/pivotal-ui/javascripts/media.jsx new file mode 100644 index 000000000..9643d6b67 --- /dev/null +++ b/src/pivotal-ui/javascripts/media.jsx @@ -0,0 +1,80 @@ +'use strict'; + +var React = require('react/addons'); +var _ = require('lodash'); +var setClass = React.addons.classSet; + +var MediaObject = React.createClass({ + render: function () { + var leftClasses = setClass({ + 'media-left': this.props.horizontalAlignment === 'left', + 'media-right': this.props.horizontalAlignment === 'right', + 'media-middle': this.props.verticalAlignment == 'middle', + 'media-bottom': this.props.verticalAlignment == 'bottom' + }); + + return ( + + ... + + ); + } +}); + +var Media = React.createClass({ + + render: function () { + var leftMedia, + rightMedia = ''; + + var classes = setClass({ + 'media': true, + 'media-stackable-xs': this.props.stackSize == 'xsmall', + 'media-stackable-sm': this.props.stackSize == 'small', + 'media-stackable-md': this.props.stackSize == 'medium', + 'media-stackable-lg': this.props.stackSize == 'large' + }); + + var bodyClasses = setClass({ + 'media-body': true, + 'media-middle': this.props.bodyAlignment == 'middle', + 'media-bottom': this.props.bodyAlignment == 'bottom' + }); + + if (this.props.leftImageSource) { + leftMedia = ( + + + ); + } + + if (this.props.rightImageSource) { + rightMedia = ( + + + ); + } + + return ( +
+ {leftMedia} +
+ {this.props.children} +
+ {rightMedia} +
+ ); + } +}); + +module.exports = { + Media: Media +}; diff --git a/src/pivotal-ui/javascripts/pivotal-ui-react.js b/src/pivotal-ui/javascripts/pivotal-ui-react.js index 618eddc7f..6b09984cc 100644 --- a/src/pivotal-ui/javascripts/pivotal-ui-react.js +++ b/src/pivotal-ui/javascripts/pivotal-ui-react.js @@ -37,6 +37,8 @@ global.DividerInverse = require('./dividers.jsx').DividerInverse; global.Row = require('./grids.jsx').Row; global.Col = require('./grids.jsx').Col; +global.Media = require('./media.jsx').Media; + global.PivnetHomepage = require('./pivnet_homepage.jsx').PivnetHomepage; global.Panel = require('./panels.jsx').Panel; diff --git a/test/spec/javascripts/media_spec.js b/test/spec/javascripts/media_spec.js new file mode 100644 index 000000000..62fe57063 --- /dev/null +++ b/test/spec/javascripts/media_spec.js @@ -0,0 +1,177 @@ +'use strict'; + +var $ = require('jquery'); +var React = require('react/addons'); +var TestUtils = React.addons.TestUtils; + +var Media = React.createFactory(require('../../../src/pivotal-ui/javascripts/media.jsx').Media); + +describe('Media', function() { + beforeEach(function() { + this.node = $('
').appendTo('body').get(0); + + React.render( + Media({ + children: "fop" + }), + this.node + ); + }); + + afterEach(function() { + React.unmountComponentAtNode(this.node); + document.body.removeChild(this.node); + }); + + it("creates a Media component", function() { + expect($('#container .media .media-body')).toContainText('fop'); + }); + + describe("when left image src is set", function() { + beforeEach(function() { + React.render( + Media({ + children: "fop", + leftImageSource: "http://placehold.it/20x20", + leftImageHref: "http://www.google.com" + }), + this.node + ); + }); + + it("displays the media-left link with an image inside", function() { + expect($('#container .media .media-left .media-object').attr('src')).toEqual('http://placehold.it/20x20'); + }); + + it("links to it's href (google, in this case)", function(){ + expect($('#container .media .media-left').attr('href')).toEqual('http://www.google.com'); + }); + }); + + describe("when left image src is not set", function() { + beforeEach(function() { + React.render( + Media({ + children: "fop" + }), + this.node + ); + }); + + it("does not display the media-left link or image inside", function() { + expect($('#container .media')).not.toContainElement('.media-left'); + }); + }); + + describe("when right image src is set", function() { + beforeEach(function() { + React.render( + Media({ + children: "fop", + rightImageSource: "http://placehold.it/20x20", + rightImageHref: "http://www.google.com" + }), + this.node + ); + }); + + it("displays the media-right link with an image inside", function() { + expect($('#container .media .media-right .media-object').attr('src')).toEqual('http://placehold.it/20x20'); + }); + + it("links to it's href (google, in this case)", function(){ + expect($('#container .media .media-right').attr('href')).toEqual('http://www.google.com'); + }); + }); + + describe("when image alignment is set to middle", function() { + beforeEach(function() { + React.render( + Media({ + children: "fop", + leftImageSource: "http://placehold.it/20x20", + leftImageHref: "http://www.google.com", + leftImageAlignment: "middle" + }), + this.node + ); + }); + + it("displays the media-middle class", function() { + expect($('#container .media .media-left')).toHaveClass('media-middle'); + }); + }); + + describe("when image alignment is set to bottom", function() { + beforeEach(function() { + React.render( + Media({ + children: "fop", + leftImageSource: "http://placehold.it/20x20", + leftImageHref: "http://www.google.com", + leftImageAlignment: "bottom" + }), + this.node + ); + }); + + it("displays the media-middle class", function() { + expect($('#container .media .media-left')).toHaveClass('media-bottom'); + }); + }); + + describe("when body alignment is set to middle", function() { + beforeEach(function() { + React.render( + Media({ + children: "fop", + bodyAlignment: "middle" + }), + this.node + ); + }); + + it("displays the media-middle class", function() { + expect($('#container .media .media-body')).toHaveClass('media-middle'); + }); + }); + + describe("when media block is set to stack on small screens", function() { + beforeEach(function() { + React.render( + Media({ + children: "fop", + leftImageSource: "http://placehold.it/20x20", + leftImageHref: "http://www.google.com", + leftImageAlignment: "middle", + stackSize: "small" + }), + this.node + ); + }); + + it("the media-stackable-sm class is applied to the media element", function() { + expect($('#container .media')).toHaveClass('media-stackable-sm'); + }); + }); + + describe("when media block is set to stack on medium screens", function() { + beforeEach(function() { + React.render( + Media({ + children: "fop", + leftImageSource: "http://placehold.it/20x20", + leftImageHref: "http://www.google.com", + leftImageAlignment: "middle", + stackSize: "medium" + }), + this.node + ); + }); + + it("the media-stackable-md class is applied to the media element", function() { + expect($('#container .media')).toHaveClass('media-stackable-md'); + }); + }); + +});