├── .gitignore ├── .npmignore ├── render.png ├── package.json ├── LICENSE ├── README.md ├── src └── index.js ├── index.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | src 4 | -------------------------------------------------------------------------------- /render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fulll/masonreact/HEAD/render.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "masonreact", 3 | "version": "1.0.3", 4 | "description": "React component to play with the great library Masonry from desandro.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/xeonys/masonreact.git" 9 | }, 10 | "keywords": [ 11 | "xeonys", 12 | "react", 13 | "masonry", 14 | "responsive", 15 | "layout", 16 | "grid" 17 | ], 18 | "author": "Didier Franc", 19 | "contributors": [ 20 | "Igor ESCHALIER (https://github.com/ieschalier/)" 21 | ], 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/xeonys/masonreact/issues" 25 | }, 26 | "homepage": "https://github.com/xeonys/masonreact#readme", 27 | "dependencies": { 28 | "masonry-layout": "^4.1.1", 29 | "prop-types": "^15.6.0" 30 | }, 31 | "devDependencies": { 32 | "react": "^16.0.0", 33 | "react-dom": "^16.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 In Extenso Digital 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### [Live](https://xeonys.github.io/react-showroom/#grid) 2 | 3 | # Masonreact 4 | 5 | React component to play with the great library [Masonry](https://github.com/desandro/masonry) from [desandro](https://github.com/desandro). 6 | 7 | 8 | ### Installation 9 | 10 | ``` 11 | npm i -S masonreact 12 | ``` 13 | 14 | ### Usage 15 | 16 | You can pass this props to Masonreact : `cols`, `margin` and `transitionDuration`. 17 | 18 | 19 | ```js 20 | import React from 'react' 21 | import Masonry from 'masonreact' 22 | import color from 'randomcolor' 23 | 24 | const App = () => { 25 | 26 | const style = { 27 | color: 'white', 28 | fontFamily: 'Sans-serif', 29 | textShadow: '0 0 2px rgba(0,0,0,0.5)', 30 | padding: 20 31 | } 32 | 33 | return ( 34 | 35 |
1
36 |
2
37 |
3
38 |
4
39 |
5
40 |
6
41 |
42 | ) 43 | 44 | } 45 | 46 | 47 | export default App 48 | ``` 49 | 50 | #### Refresh 51 | 52 | You can import `masonrefresh` from `masonreact` and run it to laid out items again, inside children `componentDidMount` for example. 53 | 54 | ```js 55 | import React from 'react' 56 | import { masonrefresh } from 'masonreact' 57 | 58 | export default class Something extends React.Component { 59 | 60 | componentDidMount = () => masonrefresh() 61 | 62 | render = () => ( 63 |
64 | ... 65 |
66 | ) 67 | 68 | } 69 | 70 | ``` 71 | 72 | ### Render 73 | 74 | ![Render](https://raw.githubusercontent.com/inextensodigital/masonreact/master/render.png) 75 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Masonry from 'masonry-layout' 4 | 5 | class Masonreact extends React.Component { 6 | 7 | deferred = () => setTimeout(() => this.msnry.layout(), 0) 8 | 9 | componentDidMount = () => { 10 | 11 | this.msnry = new Masonry(`.${this.props.gridClassName}`, { 12 | percentPosition: true, 13 | transitionDuration: this.props.transitionDuration 14 | }) 15 | 16 | window.addEventListener('masonreact', this.deferred) 17 | 18 | } 19 | 20 | componentWillUnmount = () => { 21 | window.removeEventListener('masonreact', this.deferred) 22 | } 23 | 24 | render = () => { 25 | 26 | const { cols, margin, children, gridClassName } = this.props 27 | 28 | const style = { 29 | item: { 30 | boxSizing: 'border-box', 31 | width: `calc(${100 / cols}% - ${2 * margin}px)`, 32 | margin 33 | }, 34 | grid: { 35 | width: '100%', 36 | transition: 'none' 37 | } 38 | } 39 | 40 | return( 41 |
42 | {React.Children.map(children, child => 43 | child ? React.cloneElement(child, { 44 | style: { 45 | ...child.props.style, 46 | ...style.item 47 | } 48 | }) : null 49 | )} 50 |
51 | ) 52 | } 53 | } 54 | 55 | Masonreact.propTypes = { 56 | children: PropTypes.node.isRequired, 57 | style: PropTypes.shape({}), 58 | cols: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), 59 | margin: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), 60 | transitionDuration: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), 61 | gridClassName: PropTypes.string, 62 | } 63 | 64 | Masonreact.defaultProps = { 65 | style: undefined, 66 | cols: 1, 67 | margin: 5, 68 | transitionDuration: 0, 69 | gridClassName: 'grid', 70 | } 71 | 72 | export default Masonreact 73 | 74 | let event = document.createEvent('Event') 75 | event.initEvent('masonreact', true, false) 76 | 77 | export const masonrefresh = () => window.dispatchEvent(event) 78 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.masonrefresh = undefined; 7 | 8 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 9 | 10 | var _react = require('react'); 11 | 12 | var _react2 = _interopRequireDefault(_react); 13 | 14 | var _propTypes = require('prop-types'); 15 | 16 | var _propTypes2 = _interopRequireDefault(_propTypes); 17 | 18 | var _masonryLayout = require('masonry-layout'); 19 | 20 | var _masonryLayout2 = _interopRequireDefault(_masonryLayout); 21 | 22 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 23 | 24 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 25 | 26 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 27 | 28 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 29 | 30 | var Masonreact = function (_React$Component) { 31 | _inherits(Masonreact, _React$Component); 32 | 33 | function Masonreact() { 34 | var _ref; 35 | 36 | var _temp, _this, _ret; 37 | 38 | _classCallCheck(this, Masonreact); 39 | 40 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 41 | args[_key] = arguments[_key]; 42 | } 43 | 44 | return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Masonreact.__proto__ || Object.getPrototypeOf(Masonreact)).call.apply(_ref, [this].concat(args))), _this), _this.deferred = function () { 45 | return setTimeout(function () { 46 | return _this.msnry.layout(); 47 | }, 0); 48 | }, _this.componentDidMount = function () { 49 | 50 | _this.msnry = new _masonryLayout2.default('.' + _this.props.gridClassName, { 51 | percentPosition: true, 52 | transitionDuration: _this.props.transitionDuration 53 | }); 54 | 55 | window.addEventListener('masonreact', _this.deferred); 56 | }, _this.componentWillUnmount = function () { 57 | window.removeEventListener('masonreact', _this.deferred); 58 | }, _this.render = function () { 59 | var _this$props = _this.props, 60 | cols = _this$props.cols, 61 | margin = _this$props.margin, 62 | children = _this$props.children, 63 | gridClassName = _this$props.gridClassName; 64 | 65 | 66 | var style = { 67 | item: { 68 | boxSizing: 'border-box', 69 | width: 'calc(' + 100 / cols + '% - ' + 2 * margin + 'px)', 70 | margin: margin 71 | }, 72 | grid: { 73 | width: '100%', 74 | transition: 'none' 75 | } 76 | }; 77 | 78 | return _react2.default.createElement( 79 | 'div', 80 | { className: gridClassName, style: style.grid }, 81 | _react2.default.Children.map(children, function (child) { 82 | return child ? _react2.default.cloneElement(child, { 83 | style: _extends({}, child.props.style, style.item) 84 | }) : null; 85 | }) 86 | ); 87 | }, _temp), _possibleConstructorReturn(_this, _ret); 88 | } 89 | 90 | return Masonreact; 91 | }(_react2.default.Component); 92 | 93 | Masonreact.propTypes = { 94 | children: _propTypes2.default.node.isRequired, 95 | style: _propTypes2.default.shape({}), 96 | cols: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]), 97 | margin: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]), 98 | transitionDuration: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]), 99 | gridClassName: _propTypes2.default.string 100 | }; 101 | 102 | Masonreact.defaultProps = { 103 | style: undefined, 104 | cols: 1, 105 | margin: 5, 106 | transitionDuration: 0, 107 | gridClassName: 'grid' 108 | }; 109 | 110 | exports.default = Masonreact; 111 | 112 | 113 | var event = document.createEvent('Event'); 114 | event.initEvent('masonreact', true, false); 115 | 116 | var masonrefresh = exports.masonrefresh = function masonrefresh() { 117 | return window.dispatchEvent(event); 118 | }; -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | asap@~2.0.3: 6 | version "2.0.5" 7 | resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" 8 | 9 | core-js@^1.0.0: 10 | version "1.2.7" 11 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" 12 | 13 | desandro-matches-selector@^2.0.0: 14 | version "2.0.2" 15 | resolved "https://registry.yarnpkg.com/desandro-matches-selector/-/desandro-matches-selector-2.0.2.tgz#717beed4dc13e7d8f3762f707a6d58a6774218e1" 16 | 17 | encoding@^0.1.11: 18 | version "0.1.12" 19 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 20 | dependencies: 21 | iconv-lite "~0.4.13" 22 | 23 | ev-emitter@^1.0.0: 24 | version "1.0.3" 25 | resolved "https://registry.yarnpkg.com/ev-emitter/-/ev-emitter-1.0.3.tgz#ee5ef74b6ed28d911b32ddcbfc97867f580937bc" 26 | 27 | fbjs@^0.8.16: 28 | version "0.8.16" 29 | resolved "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" 30 | dependencies: 31 | core-js "^1.0.0" 32 | isomorphic-fetch "^2.1.1" 33 | loose-envify "^1.0.0" 34 | object-assign "^4.1.0" 35 | promise "^7.1.1" 36 | setimmediate "^1.0.5" 37 | ua-parser-js "^0.7.9" 38 | 39 | fizzy-ui-utils@^2.0.0: 40 | version "2.0.4" 41 | resolved "https://registry.yarnpkg.com/fizzy-ui-utils/-/fizzy-ui-utils-2.0.4.tgz#35dab07177ce530b5380c8ce05f7c1e361daedd5" 42 | dependencies: 43 | desandro-matches-selector "^2.0.0" 44 | 45 | get-size@^2.0.2: 46 | version "2.0.2" 47 | resolved "https://registry.yarnpkg.com/get-size/-/get-size-2.0.2.tgz#555ea98ab8732e0c021e9e23e2219adcbe398e98" 48 | 49 | iconv-lite@~0.4.13: 50 | version "0.4.15" 51 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" 52 | 53 | is-stream@^1.0.1: 54 | version "1.1.0" 55 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 56 | 57 | isomorphic-fetch@^2.1.1: 58 | version "2.2.1" 59 | resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" 60 | dependencies: 61 | node-fetch "^1.0.1" 62 | whatwg-fetch ">=0.10.0" 63 | 64 | js-tokens@^3.0.0: 65 | version "3.0.1" 66 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" 67 | 68 | loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: 69 | version "1.3.1" 70 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" 71 | dependencies: 72 | js-tokens "^3.0.0" 73 | 74 | masonry-layout@^4.1.1: 75 | version "4.1.1" 76 | resolved "https://registry.yarnpkg.com/masonry-layout/-/masonry-layout-4.1.1.tgz#e8c8c6f5a9e621a75203ac4b7000855a36f6753e" 77 | dependencies: 78 | get-size "^2.0.2" 79 | outlayer "^2.1.0" 80 | 81 | node-fetch@^1.0.1: 82 | version "1.6.3" 83 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" 84 | dependencies: 85 | encoding "^0.1.11" 86 | is-stream "^1.0.1" 87 | 88 | object-assign@^4.1.0, object-assign@^4.1.1: 89 | version "4.1.1" 90 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 91 | 92 | outlayer@^2.1.0: 93 | version "2.1.0" 94 | resolved "https://registry.yarnpkg.com/outlayer/-/outlayer-2.1.0.tgz#83b7beefc19becd3278c8ade988d268788d6f93d" 95 | dependencies: 96 | ev-emitter "^1.0.0" 97 | fizzy-ui-utils "^2.0.0" 98 | get-size "^2.0.2" 99 | 100 | promise@^7.1.1: 101 | version "7.1.1" 102 | resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" 103 | dependencies: 104 | asap "~2.0.3" 105 | 106 | prop-types@^15.6.0: 107 | version "15.6.0" 108 | resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" 109 | dependencies: 110 | fbjs "^0.8.16" 111 | loose-envify "^1.3.1" 112 | object-assign "^4.1.1" 113 | 114 | react-dom@^16.0.0: 115 | version "16.0.0" 116 | resolved "https://registry.npmjs.org/react-dom/-/react-dom-16.0.0.tgz#9cc3079c3dcd70d4c6e01b84aab2a7e34c303f58" 117 | dependencies: 118 | fbjs "^0.8.16" 119 | loose-envify "^1.1.0" 120 | object-assign "^4.1.1" 121 | prop-types "^15.6.0" 122 | 123 | react@^16.0.0: 124 | version "16.0.0" 125 | resolved "https://registry.npmjs.org/react/-/react-16.0.0.tgz#ce7df8f1941b036f02b2cca9dbd0cb1f0e855e2d" 126 | dependencies: 127 | fbjs "^0.8.16" 128 | loose-envify "^1.1.0" 129 | object-assign "^4.1.1" 130 | prop-types "^15.6.0" 131 | 132 | setimmediate@^1.0.5: 133 | version "1.0.5" 134 | resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" 135 | 136 | ua-parser-js@^0.7.9: 137 | version "0.7.12" 138 | resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" 139 | 140 | whatwg-fetch@>=0.10.0: 141 | version "2.0.3" 142 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" 143 | --------------------------------------------------------------------------------