Skip to content

Commit

Permalink
Use React utilities to work with XMasonry children, fixes #5
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitaeverywhere committed Jul 28, 2017
1 parent a0aa05e commit 90213e7
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 54 deletions.
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ <h3 class="demo">General Features</h3>
you have network problems. Try refreshing the page or updating your browser.
</p>
</div>
<div class="centerText">
<div class="centerText" style="margin-top: 20px">
Like the project?
<a target="_blank" href="http://npmjs.org/package/react-xmasonry">Use it with npm!</a>
<a target="_blank" href="https://github.com/ZitRos/react-xmasonry">Star it on GitHub</a> to
let us know you are interested!
</div>
<div class="littleGray centerText">
<div style="display: inline-block; max-width: 700px; margin: 20px auto">
Expand Down
2 changes: 1 addition & 1 deletion docs/index.js

Large diffs are not rendered by default.

12 changes: 9 additions & 3 deletions docs/jsx/CardsDemo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,20 @@ export default class CardsDemo extends React.Component {
<button onClick={ this.deleteCard.bind(this) }>Delete random card</button>
<button onClick={ this.replaceCard.bind(this) }>Replace random card</button>
</div>
<XMasonry>{ this.state.data.map((d, i) =>
<XMasonry>
<XBlock key={ "persistent" }>
<div className="card" style={ { backgroundColor: "white" } }>
<h1>Persistent card</h1>
<p>This card should always be the first card in this demo.</p>
</div>
</XBlock>{ this.state.data.map((d, i) =>
<XBlock key={ d.id } width={ d.width || 1 }>
<div className="card" style={{ backgroundColor: d.color }}>
<h1>{ d.header }<sup>{ d.id }</sup></h1>
<p>{ d.body }</p>
</div>
</XBlock>
)}</XMasonry>
</XBlock> )}
</XMasonry>
</div>
}

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-xmasonry",
"version": "2.3.1",
"version": "2.4.0",
"description": "Simple & featured native masonry layout implementation for React JS",
"main": "dist/index.js",
"module": "src/index.jsx",
Expand All @@ -11,6 +11,7 @@
"license": "MIT",
"keywords": [
"react",
"component",
"js",
"javascript",
"masonry",
Expand Down
90 changes: 44 additions & 46 deletions src/components/XMasonry.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,17 @@ export default class XMasonry extends React.Component {

componentWillReceiveProps (newProps) {
// Other conditions are already covered, except of removing children without adding new ones
if (newProps.children.length < this.props.children.length) {
if (React.Children.count(newProps.children) < React.Children.count(this.props.children)) {
let newKeys = new Set(),
deleted = {};
for (let i = 0; i < newProps.children.length; i++)
newKeys.add(newProps.children[i].key === null ? i : newProps.children[i].key);
for (let i = 0; i < this.props.children.length; i++) {
const key = this.props.children[i].key === null ? i : this.props.children[i].key;
React.Children.forEach(newProps.children, (child, i) =>
newKeys.add(child.key === null ? i : child.key)
);
React.Children.forEach(this.props.children, (child, i) => {
const key = child.key === null ? i : child.key;
if (!newKeys.has(key))
deleted[key] = {};
}
});
this.recalculatePositions(null, deleted);
}
}
Expand Down Expand Up @@ -330,57 +331,54 @@ export default class XMasonry extends React.Component {

const allKeys = {};
let toMeasure = 0;
const elements = this.containerWidth === 0
? []
: Array.prototype.slice.call(React.isValidElement(this.props.children)
? [this.props.children]
: this.props.children).map((element, i) => {
const key = element.key === null ? i : element.key;
const measured = this.blocks[key]; // || undefined
if (!measured)
++toMeasure;
allKeys[key] = null;
return measured
? React.cloneElement(element, {
"data-key": key,
"key": key,
"style": {
left: Math.floor(measured.left),
top: measured.top
},
"measured": true,
"height": measured.height,
"parent": this
})
: React.cloneElement(element, {
"data-key": key,
"data-xkey": key,
"key": key,
"style": {
visibility: "hidden"
},
"height": 0,
"parent": this
});
});
const elements = this.containerWidth === 0 ? [] : this.props.children;
const children = React.Children.map(elements, (element, i) => {
const key = element.key === null ? i : element.key;
const measured = this.blocks[key]; // || undefined
if (!measured)
++toMeasure;
allKeys[key] = null;
return measured
? React.cloneElement(element, {
"data-key": key,
"key": key,
"style": {
left: Math.floor(measured.left),
top: measured.top
},
"measured": true,
"height": measured.height,
"parent": this
})
: React.cloneElement(element, {
"data-key": key,
"data-xkey": key,
"key": key,
"style": {
visibility: "hidden"
},
"height": 0,
"parent": this
});
});

for (let key in this.blocks) { // empty not used keys
if (!this.blocks.hasOwnProperty(key) || allKeys.hasOwnProperty(key))
continue;
this.blocks[key] = undefined;
}

let actualHeight = elements.length - toMeasure > 0 || elements.length === 0
let actualHeight = children.length - toMeasure > 0 || children.length === 0
? this.fixedHeight = this.state.containerHeight
: this.fixedHeight;

// console.log(`Render: measured=${ elements.length - toMeasure }, not=${ toMeasure
// console.log(`Render: measured=${ children.length - toMeasure }, not=${ toMeasure
// }, W=${ this.containerWidth }, H=${ actualHeight }, fixedH=${
// !(elements.length - toMeasure > 0 || elements.length === 0) } blocks`,
// JSON.parse(JSON.stringify(this.blocks)));
// !(children.length - toMeasure > 0 || children.length === 0) } blocks`,
// JSON.parse(JSON.stringify(this.blocks)), children, this.props.children);

const { center, maxColumns, responsive, smartUpdate, smartUpdateCeil, targetBlockWidth,
updateOnImagesLoad, updateOnFontLoad, className, style, ...restProps } = this.props;
updateOnImagesLoad, updateOnFontLoad, className, style, ...otherProps } = this.props;

return <div className={className ? `xmasonry ${className}` : `xmasonry`}
style={ {
Expand All @@ -389,8 +387,8 @@ export default class XMasonry extends React.Component {
...style
} }
ref={ (c) => this.container = c }
{ ...restProps }>
{ elements }
{ ...otherProps }>
{ children }
</div>;

}
Expand Down

0 comments on commit 90213e7

Please sign in to comment.