Share
Embed
Building the Media Block in ReactJS
Your component API is an interface that needs designing.
Nicole Sullivan
June 09, 2015
Transcript
107 slides
-
BUILDING THE MEDIA BLOCK IN REACTJS the API is an
interface that needs to be designed https://www.flickr.com/photos/darpi/212323100/in/photolist-jLdg7-4zEiwa-nwFCR-cZVtBE-4NHtnv-7daytd-pce3y-4NH3fh-5TLS72-58aMX7-58aMVN-a3826y-gVDVKr-8DRhUB-nEdkNf-6tnApQ- fqJRqv-4NMHx7-7fUPoM-cNu2W-8etirE-o7PZA-wsB4L-7ABatu-8LyEF5-7iEjwY-3faCd1-9Gn1fF-4qYRms-JUKbE-7B97bb-69Uer5-5DQMzG-f4ZgsG-7TvUJp-5zyhEh-65naZh-nBkNs-5eCcAF-sErjv-4ePHGY-6kV1Q4- nxWYX-dpGR5-55vgqd-5scyot-5t7uJJ-nLQn5y-9Njbu-79B4aw -
WHAT WILL WE COVER? ❖ What is a media block?
❖ Why use ReactJS ❖ Making a media block in ReactJS -
WHAT IS THE MEDIA BLOCK? let’s look at an example
from Facebook -
WHAT DO WE KNOW? ! ❖ Can be nested ❖
Optional right button ❖ Must clearfix -
WHAT DO WE KNOW? ! ❖ Allows top, middle, or
bottom alignment -
WHAT DON’T WE KNOW? ❖ Image width and decoration vary
❖ Right content is unknown ❖ Width unknown -
A FEW LINES OF HTML... <div class="media attribution"> <a href="http://twitter.com/stubbornella"
class="img"> <img src="mini.jpg" alt="Stubbornella" /> </a> <div class="bd">@Stubbornella 14 minutes ago</div> </div> -
I <3 HTML, WHY USE REACT? ❖ html consistency (modal
debugging) ❖ smaller api (fewer breaking changes) ❖ don’t need to go everywhere a component was used to update the dom if it changes ❖ lightning fast dom updates when data changes ❖ not managing those updates manually ❖ simpler APIs (tabs example) -
I CAN’T COVER EVERYTHING So do Ryan Florence’s tutorials: https://github.com/
ryanflorence/react-training/ -
WHAT ARE THE ELEMENTS OF A REACT INTERFACE ❖ Elements
❖ Attributes ❖ Nested children ❖ Data Sounds a lot like html, right? -
HOW DO YOU MAKE A MEDIA COMPONENT? in React Code
var Media = React.createClass({ ! }); -
SO THEN, HOW WOULD YOU USE IT? It’s kind of
like HTML, it’s called jsx <Media> My very first React component! </Media> -
BUT, WE NEED TO EXPORT the Media component, so it
can be used in other files module.exports = { Media: Media }; -
DESCRIBE IT WITH A RENDER FUNCTION This tells the browser
what HTML to render. var Media = React.createClass({ render: function () { return ( <p> {this.props.children} </p> ); } }); just render a paragraph, for now tell React where to render children -
LET’S TRY IT! Sweet, this is gonna be rad. <Media>
This text is our component’s children! </Media> ! ! ! ! <p> This text is our component’s children! </p> -
LET’S TRY IT! Sweet, this is gonna be rad. <Media>
This text is our component’s children! </Media> ! ! ! ! <p> This text is our component’s children! </p> When React renders that component we get this html -
LET’S TRY IT! Sweet, this is gonna be rad. <Media>
This text is our component’s children! </Media> ! ! ! ! <p> This text is our component’s children! </p> {this.props.children} When React renders that component we get this html -
NOT VERY USEFUL, RIGHT? You'd never use react to render
a simple paragraph because it already understands <p> tags, you can just use them! -
SO, WHAT DID WE TRY FIRST? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji -
CREATE A SOURCE ATTRIBUTE We’ll use it in our render
function to set the src of the image <Media leftImageSource='http://placehold.it/50x50'> Media block content </Media> React props are a lot like HTML attributes -
SO, LET’S ADD AN HREF ATTRIBUTE <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com'> Media
block content </Media> Our render function will make this into a link wrapper (if it is set) -
ADD AN ALIGNMENT ATTRIBUTE <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle'> Media block
content </Media> vertical alignment, could be top, middle or bottom -
WE NEED AN ALT ATTRIBUTE <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile
photo"> Media block content </Media> Our render function will make this into an alt attribute on the <img> tag -
WE NEED A HEIGHT AND WIDTH <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle'
leftImageAlt="profile photo" leftImageHeight="50px" leftImageWidth="50px"> Media block content </Media> Explicit height and width allow the browser to do a single rendering/painting pass -
SET THE GUTTER BETWEEN IMAGE AND CONTENT with the spacing
attribute <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile photo" leftImageHeight="50px" leftImageWidth="50px" leftImageSpacing="medium"> Media block content </Media> For when the 10px default spacing isn’t right, like a tiny icon with text -
FOR EXAMPLE, IT’S RESPONSIVE via the stacksize (breakpoint) attribute <Media
leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile photo" leftImageHeight="50px" leftImageWidth="50px" leftImageSpacing="medium" stackSize='medium'> Media block content </Media> stack size puts the image above the text at the breakpoint -
THIS IS GETTING OUT OF HAND! But we forgot something,
the media block can have a right image -
ADD THE RIGHT IMAGE PROPERTIES This is out of control,
we are going the wrong way! <Media leftImageSource='http://placehold.it/50x50' leftImageHref='http://www.google.com' leftImageAlignment='middle' leftImageAlt="profile photo" leftImageHeight="50px" leftImageWidth="50px" rightImageSource='http://placehold.it/50x50' rightImageHref='http://www.google.com' rightImageAlignment='middle' rightImageAlt="profile photo" rightImageHeight="50px" rightImageWidth="50px" rightImageSpacing="medium" bodyAlignment='middle' stackSize='medium'> Media block content </Media> right image props -
PROS/CONS ❖ It’s very explicit, we know what each thing
does What works? ❖ We're basically recreating html in React, yuck! (we shouldn’t make a new different alt attribute! ❖ We have image properties and media properties all mixed up ❖ We have too many properties What doesn’t work? -
SO, WHAT DID WE TRY NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji -
OUR IMAGES AS JSON kinda weird, but it might work…
var images = [ { "src": "http://placehold.it/50x50", "href": "http://www.google.com", "alignment": "middle", "alt": "profile photo", "height": "50px", "width": "50px" }, { "src": "http://placehold.it/50x50", "href": "http://www.google.com", "alignment": "middle", "alt": "profile photo", "height": "50px", "width": "50px" } ]; -
JSON IN THE MEDIA passed in as another property <Media
images={images} bodyAlignment='middle' stackSize='medium'> Media block content </Media> -
JSON IN THE MEDIA passed in as another property <Media
images={images} bodyAlignment='middle' stackSize='medium'> Media block content </Media> {curly braces} mean it’s a JavaScript variable rather than a string -
JSON IN THE MEDIA passed in as another property <Media
images={images} bodyAlignment='middle' stackSize='medium'> Media block content </Media> json goes into the images attribute {curly braces} mean it’s a JavaScript variable rather than a string -
What works? What doesn’t work? PROS/CONS ❖ abstraction of passing
in JSON means all the code isn't in the same place ❖ weird to have JSON in the middle of what looks like markup ❖ still reinventing html attributes of an <img> tag ❖ cleaner separation of concerns (media takes care of media stuff, rather than the properties of its children) -
PARSING CHILDREN We decided to try including the images as
children https://www.flickr.com/photos/i-am-mclovin/16535518502/in/photolist-rcbRyA-nshV4n-eAaqTz-bCfUFZ-jH4tBF-pctQQD-qNmfZS-eT3GMZ-bTJsji-N8LkW-iCxgoA-7JDTp2-mPGu7V-dV4m7G-igpkaV-dRobZv-mnUN9i-igoYgJ-bCzBBi- f9tdxa-oMiWTE-b6LMzz-rcTY6S-dYq12b-qUh6hV-f6oFCx-pmwC9Z-hNLucH-moYnBt-6uGwja-aRrBm4-mPGGDB-igp6YC-f8b3QR-igpkXB-igoY3C-o62zzh-iC3JNn-9217QQ-D3JPG-pcHyUy-pprMfU-igoJAg-hgRxSL-pqomg9- ahQDpD-4LkbKg-hNLcDy-igoJb8-9STs34 -
PARSING CHILDREN better, everything is normal html! But, it has
a few drawbacks <Media> <img src='http://placehold.it/50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width="50px" > <p>My media content</p> <img src='http://placehold.it/50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width="50px" > </Media> -
What works? What doesn’t work? PROS/CONS ❖ The images and
body content need to be in a very particular order, it seems weird to expose that to the user ❖ Violates the "build components you can use without understanding CSS” principle ❖ Normal HTML ❖ Facebook does it this way -
WHAT *ELSE* DOESN’T WORK? ❖ We could loop over children
and reorder them, but how do we tell the difference between content images and media images? ❖ We were still discovering React, and didn't know how to loop over children yet ❖ React provides handy error messages and property validations. We would lose out on that if we made the images children ❖ Facebook's images aren't optional, so it's a different case -
SO, WHAT DID WE TRY NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji -
FIRST, WE MAKE OUR IMAGES var leftImage = <img src='http://placehold.it/
50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width="50px">; ! var rightImage = <img src='http://placehold.it/ 50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width=“50px">; -
NEXT, WE MAKE OUR MEDIA OBJECT this looks similar to
the JSON example <Media leftImage={leftImage} rightImage={rightImage} bodyAlignment='middle' stackSize='medium'> Media block content </Media> -
NEXT, WE MAKE OUR MEDIA OBJECT this looks similar to
the JSON example <Media leftImage={leftImage} rightImage={rightImage} bodyAlignment='middle' stackSize='medium'> Media block content </Media> left and right images are passed into attributes -
YOU CAN EVEN WRITE IT like this if you really
want to <Media leftImage={<img src='http://placehold.it/50x50' href='http://www.google.com' alignment='middle' alt="profile photo" height="50px" width="50px">} bodyAlignment='middle' stackSize='medium'> Media block content </Media> image component directly in the attribute property -
What works? What doesn’t work? PROS/CONS ❖ HTML inside an
attribute (in the latter example) is a bit odd, though it does have advantages. ❖ React passes default html attributes in to the resulting img tag, so we don't have to do anything special with height, width, src, aria and alt. ❖ We separate concerns and the image takes care of it's own properties ❖ No need to parse content -
WHAT *ELSE* DOESN’T WORK? ❖ href will be passed through.
So our image will have an href attribute. I like clean html, and that feels weird to me! <div class="media"> <a href="styleguide.pivotal.io"> <img href="styleguide.pivotal.io" /> ... Yuck! -
WE CONSIDERED GOING BACK TO PROPERTIES… but decided we should
make our own <img> wrapper <Media leftImageHref="styleguide.pivotal.io"> to property or not to property? -
SO, WHAT DID WE TRY NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji -
GOAL: OUTPUTS A SIMPLE <IMG> TAG but won't pass through
attributes that don't make sense like href -
STEP 2: EXPORT THE IMAGE the same way we did
the Media component module.exports = {Image}; -
STEP 3: GET ITS PROPERTIES and render an image var
Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src} className={classes}>; ! return href ? <a {...{href}}>{image}</a> : image; } }); -
STEP 3: GET ITS PROPERTIES and render an image var
Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src} className={classes}>; ! return href ? <a {...{href}}>{image}</a> : image; } }); get the properties we need -
STEP 3: GET ITS PROPERTIES and render an image var
Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src} className={classes}>; ! return href ? <a {...{href}}>{image}</a> : image; } }); get the properties we need build the image from our properties -
STEP 3: GET ITS PROPERTIES and render an image var
Image = React.createClass({ render() { var {href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src} className={classes}>; ! return href ? <a {...{href}}>{image}</a> : image; } }); get the properties we need build the image from our properties if we have a link, wrap the image in an <a> tag -
STEP 4: MAKE IT RESPONSIVE by handling the responsive boolean
var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src}>; return href ? <a {...{href}}>{image}</a> : image; } }); -
STEP 4: MAKE IT RESPONSIVE by handling the responsive boolean
var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var image = <img {...other} src={src}>; return href ? <a {...{href}}>{image}</a> : image; } }); get the responsive property -
STEP 4: MAKE IT RESPONSIVE and setting the img-responsive class
if the boolean is true var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var classes = classnames({'img-responsive': responsive}, className); ! ! ! ! ! ! ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); -
STEP 4: MAKE IT RESPONSIVE and setting the img-responsive class
if the boolean is true var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var classes = classnames({'img-responsive': responsive}, className); ! ! ! ! ! ! ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); add this class if this evaluates to true -
STEP 4: MAKE IT RESPONSIVE and setting the img-responsive class
if the boolean is true var Image = React.createClass({ render() { var {responsive, href, src, children, className, ...other} = this.props; ! var classes = classnames({'img-responsive': responsive}, className); ! ! ! ! ! ! ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); add this class if this evaluates to true then, put the class on the image -
STEP 5: VALIDATE PROPERTIES var Image = React.createClass({ propTypes: {
responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); -
STEP 5: VALIDATE PROPERTIES var Image = React.createClass({ propTypes: {
responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); responsive has to be true or false -
STEP 5: VALIDATE PROPERTIES var Image = React.createClass({ propTypes: {
responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); -
STEP 5: VALIDATE PROPERTIES var Image = React.createClass({ propTypes: {
responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); the href is a string -
STEP 5: VALIDATE PROPERTIES var Image = React.createClass({ propTypes: {
responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); -
STEP 5: VALIDATE PROPERTIES var Image = React.createClass({ propTypes: {
responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); src is a string and required -
STEP 5: VALIDATE PROPERTIES var Image = React.createClass({ propTypes: {
responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); -
STEP 5: VALIDATE PROPERTIES var Image = React.createClass({ propTypes: {
responsive: types.bool, href: types.string, src: types.string.isRequired }, ! render() { var {responsive, href, src, children, className, ...other} = this.props; var classes = classnames({'img-responsive': responsive}, className); ! var image = <img {...other} src={src} className={classes}>{children}</img>; return href ? <a {...{href}}>{image}</a> : image; } }); -
OUR “AH-HA” MOMENT Users are still needing to specify too
many things to get this component to work, they might as well just write html! -
SO, WHAT DID WE DO NEXT? https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE- amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji https://www.flickr.com/photos/mstewartphotography/6195718653/in/photolist-aruFip-3Ym2sP-d5ipmU-61ivfM-2SmfSo-eMWyyv-7Tx3yN-p7xVZN-5LExX5-dG1RK2-86LsMW-6TDV5Y-9isMj1-cJuUm-4v2NE-
amKvge-61TfaY-61PcSp-61nGEd-86FasK-qrz8VS-4bGoKp-77DPsN-7NeZKn-botCkn-8vpoEE-oTAKWV-5Sz1Fv-a5oF29-86Hf14-aS9vmZ-a8M5q6-a8Mh8k-7AKzoA-86HcPz-61HM17-7AFRcK-a8LXht-5c5LvE-a8LZXX-61Hb8A- fJgHuw-86LhDq-86Lmch-3jzdZ-5mYENE-8UMWoM-bx1iUr-p9jsSa-a865Ji -
ELEMENTS FTW we can simplify our interface further https://www.flickr.com/photos/rejik/14681743931/in/photolist-onnLY4-nPYfhm-ed6PWM-bvWmjA-mMGE1V-j88ToM-ngTbpk-nUg38a-9n1hgv-4KZr2Z-nucMef-dd5exw-9eyaqy-8QWK1i-eaTuFL-4RbvFX-7kiwo3-7NqP2a-4R1KYB- mZEx1J-5iV12q-39v9f8-bqt2rx-7zvWs-9eyamJ-7JKZAh-hiwiDa-poG8fx-ehZRGj-684GeT-pPeQGL-efRP9f-icXKJY-aNxWqT-9niyKk-ouarpw-bmC5SK-7s5DNV-bqt3F8-bqsZ24-mZCLWp-86YqXk-e6ERub-bqtEL8-8K3pJf-
kik4tg-8yYivi-8fi3Ep-dVohpu-fzmggH https://www.flickr.com/photos/rejik/14681743931/in/photolist-onnLY4-nPYfhm-ed6PWM-bvWmjA-mMGE1V-j88ToM-ngTbpk-nUg38a-9n1hgv-4KZr2Z-nucMef-dd5exw-9eyaqy-8QWK1i-eaTuFL-4RbvFX-7kiwo3-7NqP2a-4R1KYB- mZEx1J-5iV12q-39v9f8-bqt2rx-7zvWs-9eyamJ-7JKZAh-hiwiDa-poG8fx-ehZRGj-684GeT-pPeQGL-efRP9f-icXKJY-aNxWqT-9niyKk-ouarpw-bmC5SK-7s5DNV-bqt3F8-bqsZ24-mZCLWp-86YqXk-e6ERub-bqtEL8-8K3pJf- kik4tg-8yYivi-8fi3Ep-dVohpu-fzmggH -
DESIGNERS ONLY USE 2 KINDS OF ALIGNMENT ❖ Traditional media
with everything top aligned ! ! ! ❖ “Flag” component a la Harry Roberts middle aligns -
WE MADE THESE TWO USE CASES DEAD SIMPLE ❖ We
changed the media component to default to top alignment if nothing else was specified. ❖ We created the <flag> component <Flag leftImage={refreshImage}> refresh </Flag> -
What works? What doesn’t work? PROS/CONS ❖ engineers don't always
know what the flag object is, documentation and teaching help ❖ with Flag and Media, we no longer need to specify alignment unless we want something weird -
var sortableCols = [ { name: 'name', title: 'Name', sortable:
true }, { name: 'instances', title: 'Instances', sortable: true, align: 'center' }, { name: 'cpu', title: 'CPU', sortable: true, align: 'right' }, { name: 'synergy', title: 'Synergy', align: 'left' } ] -
TABS IN BOOTSTRAP <div role="tabpanel"> ! <!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist"> <li role="presentation" class=“active"> <a href="#home" aria-controls="home" role="tab" data-toggle=“tab">Home</a> </li> <li role=“presentation"> <a href="#profile" aria-controls="profile" role="tab" data-toggle=“tab”> Profile</a> </li> </ul> ! <!-- Tab panes --> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="home">...</div> <div role="tabpanel" class="tab-pane" id="profile">...</div> </div> ! </div> -
TABS IN REACT <SimpleTabs defaultActiveKey={1}> <Tab eventKey={1} tab="Home"> ... </Tab>
<Tab eventKey={2} tab="Profile"> ... </Tab> </SimpleTabs> -
GOOD DESIGN PRINCIPLES ❖ Many drawers - Tom O ❖
Set good defaults ❖ User shouldn’t need to understand CSS to use it ❖ Make tiny components with one job (same as CSS) ❖ Allow flexibility ❖ Prefer a complex implementation over a complex interface what has worked for us -
WHO ARE YOUR USERS? component creators and maintainers, contributors, developers
building features, actual product users https://www.flickr.com/photos/fabiansociety/16300828766/in/photolist-qQs1tQ-qAa8pJ-pVJmYw-qxNcH4-qAaDuJ-qSHJsr-5SDe5H-josG7R-dxrFDm-e6S4TN-fddCLi-po7JuN-d21PZN-ax7LAK-qBLEie-dEMphp-byfU17-nPjAPc-eZ7ooX- ctHbf5-g5QFS-naVVhZ-cFgo6s-akEb2Q-qUQi3c-aGJ83i-627cGv-aRFFNx-nSyXpr-dyXFU7-aupkvk-buYgB2-nj7Xyv-jHSXR5-9eAqzK-eNqYdm-a4GaUk-qiFrdF-dy1QsG-bPqzrk-9dEUm7-n7cmgE-gJNeKz-nigszh-mi4QjT-s76Yxa- -
USE ALL THE TOOLS IN YOUR TOOLBOX ❖ Elements (built
in and custom) ❖ Attributes (simple and objects) ❖ JSON ❖ Children -
WE OPEN SOURCED EVERYTHING Please do give us feedback npm:
https://www.npmjs.com/search?q=pui github: github.com/pivotal-cf/pivotal-ui