Building the Media Block in ReactJS

4,302 views

Published on

the API is an interface that needs to be designed.

http://styleguide.pivotal.io/react_beta.html
https://www.npmjs.com/search?q=pui

Published in: Technology
1 Comment
15 Likes
Statistics
Notes
No Downloads
Views
Total views
4,302
On SlideShare
0
From Embeds
0
Number of Embeds
57
Actions
Shares
0
Downloads
28
Comments
1
Likes
15
Embeds 0
No embeds

No notes for slide

Building the Media Block in ReactJS

  1. 1. 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
  2. 2. @STUBBORNELLA twitter really is the best way to reach me…
  3. 3. WHAT WILL WE COVER? ❖ What is a media block? ❖ Why use ReactJS ❖ Making a media block in ReactJS
  4. 4. WHAT IS THE MEDIA BLOCK? let’s look at an example from Facebook
  5. 5. MEDIA BLOCK EXAMPLE
  6. 6. ALL OF THESE ARE THE SAME OBJECT
  7. 7. WHAT DO WE KNOW? ! ❖ Can be nested ❖ Optional right button ❖ Must clearfix
  8. 8. WHAT DO WE KNOW? ! ❖ Allows top, middle, or bottom alignment
  9. 9. WHAT DON’T WE KNOW? ❖ Image width and decoration vary ❖ Right content is unknown ❖ Width unknown
  10. 10. 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>
  11. 11. 4 LINES OF CSS... _
  12. 12. 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)
  13. 13. I CAN’T COVER EVERYTHING So do Ryan Florence’s tutorials: https://github.com/ ryanflorence/react-training/
  14. 14. https://www.flickr.com/photos/wscullin/3770015991/in/photolist-6K9jpH-4mbNmG-4Cryx-6K9jC4-9hYhWK-dexZ3L-bpV8UA-6K9jb8-2aRBU9-c2mfZu-8desRa-ntKGaS-8ZxBba-7RVQRi-7AbLTM-dMTqW3-4866mH-rjNaZL-7MP9RU- dhfQ5N-rfCB9g-nBshnQ-7Xn7f-87asnj-84R7FU-sepy36-dtEmrp-rhsh7A-hVCY8u-4m7NmB-qqiNK6-bMLUPp-qY4LbS-q1prK-5WoP4f-Ftxe-4mbHVY-jB4t16-5qgm94-5WjwED-7vS6fV-5WoP4N-biVihz-9KsFUo-9KpQVF-9KpQMz- BUILDING THE MEDIA BLOCK IN REACT APIs are an interface that needs to be designed
  15. 15. WHAT ARE THE ELEMENTS OF A REACT INTERFACE ❖ Elements ❖ Attributes ❖ Nested children ❖ Data Sounds a lot like html, right?
  16. 16. HOW DO YOU MAKE A MEDIA COMPONENT? in React Code var Media = React.createClass({ ! });
  17. 17. SO THEN, HOW WOULD YOU USE IT? It’s kind of like HTML, it’s called jsx <Media> My very first React component! </Media>
  18. 18. BUT, WE NEED TO EXPORT the Media component, so it can be used in other files module.exports = { Media: Media };
  19. 19. 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
  20. 20. WHAT ! ! ! IS GENERATED? https://www.flickr.com/photos/f-l-e-x/3096005116/in/photolist-5HzQsy-ah1UJ3-9WjzQW-q6xrU5-eQkJhu-oWah5L-noSbAV-9nNZaQ-5XZ3To-9gi7Rx-eMzU1y-9gb3m8-eQ8LqD-9WSkjF-9WSkhK-9zurtr-9WSk3X-eQkasL-eQ8GQ6- gi65Qe-9gbgVc-9geLWE-9gbiwR-k3TpbP-9EiwTi-bMTAYe-aYNGWB-6VTDDM-96t4ms-9s4Jas-bsjtmK-edG4Dq-rFb2Q-aZYKCH-Paes6-sd9Vtx-eg9fuW-9rYCnp-edgbX5-bmrzPv-9qA9iA-aMgUmz-s1AMwV-9zurqp-gXd9UH- iEyyC-3NaTMa-bodPpW-dLeWjL-bxHrbz
  21. 21. 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>
  22. 22. 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
  23. 23. 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
  24. 24. 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!
  25. 25. LET’S BUILD AN ACTUAL MEDIA BLOCK Step 1:Add the left image
  26. 26. 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
  27. 27. TONS OF ATTRIBUTES What could go wrong? ;) https://www.flickr.com/photos/ilo_oli/5856288807/in/photolist-jpnSsc-bp1mTF-iC3JNn-feu2hV-feJdEw-dCsd6V-aQmwUk-qJvwYx-qKHp7N-qKJtpL-pMFnAC-9XxWkr-qKJEV1-q6hte9-qZZXHG-q6hp8d-qKHchA-qKJt8U-bp1mv2- b6LSWT-bKfSon-kxWCNt-b6LNN8-b8Vpk6-ehScwd-c5CMgq-qKJcqw-r3iaXK-pMieGe-9ZUFNi-aD4zaE-fDwLBF-9Vv1CF-kzarYi-9ovVLy-rVLApS-fDwKki-b5sxAg-fskG7P-bUUme1-bKgdD6-c5CMiW-a1wsSP-4u7U5a-dtv95k-dtvKP6- dtBtwJ-dtvrRR-dtBm2s-abcAqR
  28. 28. 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
  29. 29. BUT WAIT, THE IMAGE CAN BE A LINK Sometimes…
  30. 30. 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)
  31. 31. THE IMAGE CAN BE VERTICALLY ALIGNED
  32. 32. 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
  33. 33. OH SHOOT, ACCESSIBILITY!
  34. 34. 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
  35. 35. OH, AND PERFORMANCE!
  36. 36. 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
  37. 37. 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
  38. 38. PROPERTIES OF THE MEDIA rather than its images
  39. 39. 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
  40. 40. THIS IS GETTING OUT OF HAND! But we forgot something, the media block can have a right image
  41. 41. 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
  42. 42. 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?
  43. 43. 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
  44. 44. JSON ALL THE THINGS https://www.flickr.com/photos/bike/4797449644/in/photolist-8iWbD3-5HPWhF-QyKg5-eVYyjt-3meRNg-5HPW94-4HwYMz-utah8-3qvXS-aqsJtx-eyQK4T-42P9p1-7Th995-5oKgDS-5mJEJe-9bt9At-4zbwwo-8vDr8Z-7konhy- BhrJ9-5zHQ7E-bobveq-DmrMg-3qvNs-5HPW1P-qtLJmp-5ZCPcW-9QuNBj-5HUdgS-9thCcq-6FmTKV-7QgAua-6DZyzu-gkukag-apwsgp-8hWccC-4U7EX6-pfaKPb-hvM3q-asXuSH-at18RL-asXuDV-asXuC4-9ys6M7-phFVSp- dkdPkb-86toqn-dzVg-zVaLA-cDsK7N
  45. 45. 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" } ];
  46. 46. JSON IN THE MEDIA passed in as another property <Media images={images} bodyAlignment='middle' stackSize='medium'> Media block content </Media>
  47. 47. 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
  48. 48. 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
  49. 49. 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)
  50. 50. 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
  51. 51. 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
  52. 52. 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>
  53. 53. 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
  54. 54. 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
  55. 55. 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
  56. 56. REACT BUILT-IN <IMG> COMPONENT In react, everything is a component.
  57. 57. 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">;
  58. 58. 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>
  59. 59. 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
  60. 60. 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
  61. 61. 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
  62. 62. 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!
  63. 63. 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?
  64. 64. 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
  65. 65. CUSTOM IMAGE COMPONENT And another component was born… https://www.flickr.com/photos/eltonharding/522073772/in/photolist-N8LkW-dLnt39-dsdYRQ-qcf3KQ-rgojpc-dsdWxA-dRxje9-iAgtmB-aaTYBU-mgGFrk-d3TMAf-opZhPw-nbi6ut-gMDt1W-adGAGZ-j8HqHK-gAt6ec-mc944B- nEMWpG-oQkVQ4-qR9xvi-gSVfC5-oUurRb-9jGTJD-nWUZza-e5NeHJ-aTYLCT-dTTRha-rp3zLC-qn7i8t-hQxDrG-9qcih5-sn5TTi-9aQfXm-nsgfeC-niFxPL-dRxjy7-9Ry7C3-p8VRa4-noA5cx-oovJdV-kLSLxL-dpgFWM-rhZ9Ri- dRxkm3-9qResk-kGDeJb-bprRNw-oCC5tt-oCX7iY
  66. 66. GOAL: OUTPUTS A SIMPLE <IMG> TAG but won't pass through attributes that don't make sense like href
  67. 67. STEP 1: CREATE THE IMAGE COMPONENT var Image = React.createClass({ ! });
  68. 68. STEP 2: EXPORT THE IMAGE the same way we did the Media component module.exports = {Image};
  69. 69. 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; } });
  70. 70. 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
  71. 71. 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
  72. 72. 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
  73. 73. 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; } });
  74. 74. 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
  75. 75. 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; } });
  76. 76. 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
  77. 77. 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
  78. 78. 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; } });
  79. 79. 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
  80. 80. 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; } });
  81. 81. 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
  82. 82. 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; } });
  83. 83. 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
  84. 84. 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; } });
  85. 85. 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; } });
  86. 86. 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!
  87. 87. 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
  88. 88. 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
  89. 89. DESIGNERS ONLY USE 2 KINDS OF ALIGNMENT ❖ Traditional media with everything top aligned ! ! ! ❖ “Flag” component a la Harry Roberts middle aligns
  90. 90. 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>
  91. 91. 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
  92. 92. ARE ANY OF THESE WRONG? No, absolutely not. https://gist.github.com/stubbornella/e97662e4a197eb9a534a
  93. 93. CHARTS loop over children https://www.flickr.com/photos/sidereal/3326112973/in/photolist-AKC4i-9YVVYN-6EiwN6-GadYk-a67Nur-5VXHT1-Fv7K6-aozvYE-6fp6gc-6FzLjQ-fKvtt-2JGK9-bqeuyX-3jcvLj-Ljyy3-6kUXKM- bVyHMC-4dDwYk-5CGecv-6DUvgk-64Vcvp-8cK4x4-6b5yLD-jDwYG-wnfrN-vdeo8-8343Sa-dRCSgx-83wSzz-5xtVxe-5xyrZd-5VDSw6- fXTYR-82Dnu2-5VDSwa-7MNruk-81biBH-5e3irn-5e3i4T-6mxH7A-5m93Dg-5pi6WC-5uvUeA-6n89sp-c465FQ-6SDa5S-5AbJnS-cN17Zf-KGVTi-7yvvmH
  94. 94. 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' } ]
  95. 95. 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>
  96. 96. TABS IN REACT <SimpleTabs defaultActiveKey={1}> <Tab eventKey={1} tab="Home"> ... </Tab> <Tab eventKey={2} tab="Profile"> ... </Tab> </SimpleTabs>
  97. 97. https://www.flickr.com/photos/wscullin/3770015991/in/photolist-6K9jpH-4mbNmG-4Cryx-6K9jC4-9hYhWK-dexZ3L-bpV8UA-6K9jb8-2aRBU9-c2mfZu-8desRa-ntKGaS-8ZxBba-7RVQRi-7AbLTM-dMTqW3-4866mH-rjNaZL-7MP9RU- dhfQ5N-rfCB9g-nBshnQ-7Xn7f-87asnj-84R7FU-sepy36-dtEmrp-rhsh7A-hVCY8u-4m7NmB-qqiNK6-bMLUPp-qY4LbS-q1prK-5WoP4f-Ftxe-4mbHVY-jB4t16-5qgm94-5WjwED-7vS6fV-5WoP4N-biVihz-9KsFUo-9KpQVF-9KpQMz- IT’S A DESIGN DECISION each component is different
  98. 98. KEEP LOOPING BACK change the interface until it works well
  99. 99. 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
  100. 100. 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-
  101. 101. USE ALL THE TOOLS IN YOUR TOOLBOX ❖ Elements (built in and custom) ❖ Attributes (simple and objects) ❖ JSON ❖ Children
  102. 102. styleguide.pivotal.io
  103. 103. WE OPEN SOURCED EVERYTHING Please do give us feedback npm: https://www.npmjs.com/search?q=pui github: github.com/pivotal-cf/pivotal-ui
  104. 104. THANK YOU! @stubbornella

×