dantrain / react-stonecutter Goto Github PK
View Code? Open in Web Editor NEWAnimated grid layout component for React
Home Page: http://dantrain.github.io/react-stonecutter
License: MIT License
Animated grid layout component for React
Home Page: http://dantrain.github.io/react-stonecutter
License: MIT License
Is there a layout that will center items when the row is not full?
I am attemptiong to render a Pinterest-type board, but am receiving the following error;
Error: Each child must have an "itemHeight" prop or an "itemRect.height" prop.
I will be rendering Semantic UI Card
components with various headers and images, so I do not know the size of the rendered components.
I have demonstrated this below with cats instead of cards;
import React, { Component } from 'react';
import { CSSGrid, layout, measureItems } from 'react-stonecutter';
import uuid from 'uuid';
const Grid = measureItems(CSSGrid);
export default class extends Component {
render() {
return (
<CSSGrid
component="ul"
columns={5}
columnWidth={290}
gutterWidth={5}
gutterHeight={5}
layout={layout.pinterest}
duration={800}
easing="ease-out"
>
<div id="cats">
<img width={290} src={"http://thecatapi.com/api/images/get?format=src&type=jpg&rnd=" + uuid.v4() } />
<img width={290} src={"http://thecatapi.com/api/images/get?format=src&type=jpg&rnd=" + uuid.v4() } />
<img width={290} src={"http://thecatapi.com/api/images/get?format=src&type=jpg&rnd=" + uuid.v4() } />
<img width={290} src={"http://thecatapi.com/api/images/get?format=src&type=jpg&rnd=" + uuid.v4() } />
<img width={290} src={"http://thecatapi.com/api/images/get?format=src&type=jpg&rnd=" + uuid.v4() } />
<img width={290} src={"http://thecatapi.com/api/images/get?format=src&type=jpg&rnd=" + uuid.v4() } />
<img width={290} src={"http://thecatapi.com/api/images/get?format=src&type=jpg&rnd=" + uuid.v4() } />
</div>
</CSSGrid>
)
}
}
I am wondering if its possible to make the grid fit to the width of the parent, instead of defining a maxWidth via makeResponsive.
I am using the SprintGrid to render items within a parent div. It seem as though the component always has a fixed width that I can't control unless I specify the full width on init.
Any ideas?
Kai
Do you have plans on supporting react 16 in your library?
I get a warning when I use the Grid component.
This is my code:
<Grid component="ul"
columns={5}
columnWidth={150}
gutterWidth={5}
gutterHeight={5}
duration={800}
easing="ease-out">
<li key="A">Who controls the British crown?</li>
<li key="B">Who keeps the metric system down?</li>
<li key="C">We do!</li>
<li key="D">We do!</li>
</Grid>
This is what I get in the console:
Warning: Unknown prop
minPadding
ontag. Remove this prop from the element. For details, see https://fb.me/react-unknown-prop
in ul (created by ReactTransitionGroup)
in ReactTransitionGroup (created by CSSGrid)
in CSSGrid (created by Constructor)
I found that by targeting specific Stonecutter source files in my imports, I saved around 220 KB in my (webpack) bundle -- a little more than 80% (pre-minified) compared to importing without direct paths. Everything still functions perfectly:
// before
import { CSSGrid, layout, easings } from 'react-stonecutter';
// after
import CSSGrid from 'react-stonecutter/src/components/CSSGrid';
import simple from 'react-stonecutter/src/layouts/simple';
import { expoOut } from 'react-stonecutter/src/utils/easings';
To do this, though, I had to reconfigure webpack for .jsx files, add the /src
path for compilation, and enable a few Babel loaders that I wasn't already using.
It would be great if the /lib
directory could also include compiled versions of the modules in /src
. You can see an example of this in the Redux source; see /src/applyMiddleware.js
compared to /lib/applyMiddleware.js
.
I would contribute this myself but am unfamiliar with the Gulp/Weback build config you're using. Otherwise I'm happy to pitch in where possible if you think this is worthwhile.
If there is only one item in the grid, exit animation doesn't work because grid instantly unmounts (I am talking about SpringGrid). Same for entering animation, SpringGrid doesn't exist when first item enters.
I wonder if i'm doing something wrong, but it looks like a bug to me. Also, great work on this component!
You have done a great job with this component! Any plans to support React 15 and above? Thank you.
I have a grid layout that recalculates the size of my grid items to take up the remaining space. Currently the CSSGrid component renders this correctly on the first render but when the columnWidth prop changes the grid does not update to respect this. Is there a way to get this to work or is it a limitation of stonecutter?
Thanks.
the reason is that when imagesloaded
callback is called, the DOM still don't have height (0).
so when layout try to layout the item it throws the error.
my current solution is using lodash debounce
to slow down the speed of add items.
i will fix it by check the height element when imagesloaded
Uncaught Error: Each child must have an "itemHeight" prop or an "itemRect.height" prop.(anonymous function) @ react-stonecutter.js:1298t.default @ react-stonecutter.js:1292t.default.u.default.createClass.doLayout @ react-stonecutter.js:403CSSGrid_componentWillReceiveProps @ react-stonecutter.js:399O.updateComponent @ ReactCompositeComponent.js:601O.receiveComponent @ ReactCompositeComponent.js:534s.receiveComponent @ ReactReconciler.js:131l.updateChildren @ ReactChildReconciler.js:94D.Mixin._reconcilerUpdateChildren @ ReactMultiChild.js:213D.Mixin._updateChildren @ ReactMultiChild.js:315D.Mixin.updateChildren @ ReactMultiChild.js:303v.Mixin._updateDOMChildren @ ReactDOMComponent.js:938v.Mixin.updateComponent @ ReactDOMComponent.js:767v.Mixin.receiveComponent @ ReactDOMComponent.js:723s.receiveComponent @ ReactReconciler.js:131O._updateRenderedComponent @ ReactCompositeComponent.js:737O._performComponentUpdate @ ReactCompositeComponent.js:715O.updateComponent @ ReactCompositeComponent.js:634O.performUpdateIfNecessary @ ReactCompositeComponent.js:548s.performUpdateIfNecessary @ ReactReconciler.js:165u @ ReactUpdates.js:151i.perform @ Transaction.js:138i.perform @ Transaction.js:138p.perform @ ReactUpdates.js:90T @ ReactUpdates.js:173i.closeAll @ Transaction.js:204i.perform @ Transaction.js:151d.batchedUpdates @ ReactDefaultBatchingStrategy.js:63s @ ReactUpdates.js:201o @ ReactUpdateQueue.js:25f.enqueueSetState @ ReactUpdateQueue.js:209o.setState @ ReactComponent.js:64u.default.createClass.updateRects @ react-stonecutter.js:1208r @ index.js:149d @ index.js:196p @ index.js:184
Hey, in the live demo there is a button to randomize children. How is that implemented? Can you please let me know?
Hi,
we are not able to get the responsive design while adding the data dynamically in to the box of GRID. we are not knowing the height of the box and dynamically it will change. so Can you please help me solve the issue?
const Grid = measureItems(SpringGrid);
<Grid component="div" columnWidth={257} gutterWidth={5} columns={3} gutterHeight={5} layout={layout.pinterest} duration={800} easing="ease-out" measured={true}>
{
this.state.selectedFilter.map(function(compObj, idx){
return(
<div className="grid-item" key={compObj.compName} style={{width: 257,height:'auto'}}>
<FilterInfoBox filterObj={compObj} filterRemoveFn={_this.toggleFilter}/>
</div>)
})
}
</Grid>
Not sure if there's already support for this, but it'd be fantastic if it were possible.
I've found myself with the following situation:
I tried to pass a custom layout overwriting the pinterest layout code.
I've got this:
import { chunk } from "lodash";
export default function(items, props) {
const { columns, columnWidth, gutterWidth, gutterHeight } = props;
const columnHeights = [];
for (let i = 0; i < columns; i++) {
columnHeights.push(0);
}
const positions = items.map(itemProps => {
const column = columnHeights.indexOf(Math.min.apply(null, columnHeights));
const height =
itemProps.itemHeight || (itemProps.itemRect && itemProps.itemRect.height);
if (!(height && typeof height === "number")) {
throw new Error(
'Each child must have an "itemHeight" prop or an "itemRect.height" prop.'
);
}
const x = column * columnWidth + column * gutterWidth;
const y = columnHeights[column];
columnHeights[column] += Math.round(height) + gutterHeight;
return [x, y];
});
const allHeights = items.map(itemProps =>
itemProps.itemHeight || (itemProps.itemRect && itemProps.itemRect.height)
);
const chunkHeights = chunk(allHeights, columns);
const gridWidth = columns * columnWidth + (columns - 1) * gutterWidth;
const gridHeight = Math.max.apply(null, columnHeights);
const rows = chunk(positions, columns);
let previewRowYStart = 0;
let previewRowYEnd = 0;
const orderedPositions = rows.map((row: any, rowIndex) => {
const columnsYPositions = row.map(([x, y]) => y);
const max = Math.max(...columnsYPositions);
let yPosition = max;
if (rowIndex !== 0) {
const overlap = previewRowYEnd >= max;
if (overlap) yPosition = (max + (previewRowYEnd - max)) * 1.05;
}
previewRowYStart = rowIndex === 0 ? 0 : max;
previewRowYEnd = max + Math.max(...chunkHeights[rowIndex] as number[]);
return row.map(([ x ]) => [ x, yPosition ]);
});
return { positions: orderedPositions.flat(1), gridWidth, gridHeight };
}
Where basically I'm trying to order the item Y position into chunks according to their row, take the highest and set a common Y for all of them. Also I'd take previous row height and detect the chance of an overlap, adding some extra distance if overlapping.
This seems to work except that in some cases, the distance between rows is huge. I've tried to adjust the yPosition
calculation when there's an overlap and also reduced the gutter but I can't get a consistent and logic result.
Any suggestions or directions would be appreciated
Number.isNaN
is not supported in IE causing components that import this to break.
The description is here: http://stackoverflow.com/questions/41926765/react-stone-cutter-component-enter-and-exit-animations.
I have the same issue for CSSGrid
.
Page in question at:
http://merrillaudio.isaacrivera.com/#/news
It can't be scrolled. I assume it is re-rendering. Any insights?
Looks like it expects DOM elements only and when React components supplied as children, there is an error shown KeyEscapeUtils.js?ac04:28 Uncaught RangeError: Maximum call stack size exceeded
I think these 2 features are very important.
Are you planning to add these features
I want to use react-stonecutter with my existing project. However when I tried the simple usage example, nothing is displayed from the <CSSGrid/>
. All I am getting is this error:
Uncaught Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's
render
method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).
import React from 'react'
import { CSSGrid, layout } from 'react-stonecutter';
export default class Photos extends React.Component {
render() {
return(
<div id="profile_photos">
<div id="profile_photos_nav">
<span class="photo_nav" id="photo_timeline">
<button class="active_btn">Timeline Photos</button>
</span>
<span class="photo_nav" id="photo_profile">
<button>Profile Photos</button>
</span>
<span class="clear_both"></span>
</div>
<CSSGrid
component="ul"
columns={5}
columnWidth={150}
gutterWidth={5}
gutterHeight={5}
layout={layout.pinterest}
duration={800}
easing="ease-out"
>
<li key="A" itemHeight={150}>A</li>
<li key="B" itemHeight={120}>B</li>
<li key="C" itemHeight={170}>C</li>
</CSSGrid>
</div>
);
}
}
I don't know whether this is relevant, but I am using "react": "^15.1.0"
, and while installing this package, I got this warning:
npm WARN peerDependencies The peer dependency react@^15.2.0 included from react-addons-transition-group will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
Can you please help me with this? Thank you.
React 15.4 changes the internals of react
, and react-dom
. For both of these dependancies, react-stonecutter uses ^15.3.2
instead of ~15.3.2
.
Using ^
allows npm to skip up to the latest minor version, thus using react 15.4.0. If this dependency changed to ~
, stonecutter would stop at 15.3.N, where N is the last published version of 15.3.
(I'd love just make a pull request for what's basically a one-character change, but sadly I'm on a company-owned machine right now with all kinds of restrictions on open source stuff)
Hello, I want to say that your component is really awesome, I modified the measureItems file, order to wait for the load of image in individual children.
But I have a problem with pagination, the first time the page only flash, it's because you use a grid when the elements are not new and size was calculated, so, Can I render in a grid the new and the old elements?
(I'm sorry for my very bad english, I'm not a native speaker).
Thank you and best regards.
A part of my project is a layout of cards similar to the react-stonecutter
example. I've tried to implement stonecutter
into my cards area, but my cards render in a single column (vice a proper responsive layout).
My assumption is I'm missing some obvious setting, but I can't quite figure it out. Is there a simple reason this might be happening?
All the components involved here are either direct from Material-UI
or slightly modified versions (e.g., <ListingCard> == <Card>++
).
The data structures are Immutable.js, so the methods I'm using (map
, filter
) aren't native JS, if that matters.
import React from 'react'
import ListingCard from 'components/ListingCard'
import SelectField from 'material-ui/SelectField'
import { SpringGrid, makeResponsive } from 'react-stonecutter';
const Grid = makeResponsive(SpringGrid, { maxWidth: 1020, minPadding: 100, defaultColumns: 4 })
export class ListingsArea extends React.Component {
render() {
return (
<div style={style.wrapper}>
<div style={style.controlRow}>
<SelectField
floatingLabelText="Sorted by..."
>
{items}
</SelectField>
</div>
<Grid
columnWidth={300}
gutterWidth={5}
gutterHeight={5}
itemHeight={500}
springConfig={{ stiffness: 170, damping: 26 }}
>
{
this.props.userListings
.filter(/*filter code*/)
.map((val, key) => {
return <ListingCard data={val}/>
})
}
</Grid>
</div>
)
}
}
const style = {
wrapper: {
marginLeft: '25px',
},
controlRow: {
width: '100%',
}
}
Hi,
I would like to ask about this.measureElement method in measureElement HOC. There is no method like that.
058a04d#diff-2a698486281c90b4bc475613f67e168e
Regards!
I have a Next app with react-stonecutter installed. But when I try to install sass
, react-motion
gets deleted. Or, if I install react-motion
, sass
gets deleted.
I got:
"react-motion": "^0.5.2",
"react-scripts": "^5.0.1",
"react-stonecutter": "^0.3.10"
Just realised that you use enquire.js
which sets the media queries to achieve the responsive view. This works fine when the grid occupies 100% in width. However, when the page comes with a side navigation, the grid will be wider than it's parent container.
Do you have any workaround for this? Or I have to write my own makeResponsive
HoC?
If it's a new image getting loaded, the calculation is wrong and panels are overlaying cross each other, any suggestions?
Since the column width is a fixed value, is there a way to specify it in % or "vw", instead of "px"?
I can't seem to get how can I achieve responsive column widths.
Thanks!
Hi when adding itemHeight
to an li
to a css grid like the example I get the message React does not recognize the
itemHeight prop on a DOM element
. When I remove the prop I get a warning Uncaught Error: Each child must have an "itemHeight" prop or an "itemRect.height" prop.
How can I work around this?
First I must say this is a great package! Easy to use (i actually find the Grid example component easier so I'm using that one).
I'm using React Starter Kit - www.reactstarterkit.com, isomorphic is great coz it allows my user to see content without any javascript being downloaded. But looks like this library isn't isomorphic friendly. Layout isn't calculated when I render from the server side, therefore even though my content is sent down on the initial load, but no UI is shown.
I'm not using responsive, so it should be doable to do layout on the sever side. Tried to do some debugging but can't find how to solve it. Any suggestions?
Hi ,
I don't know the heights of my items ahead of time and try to use the measureItems higher-order component to measure them in the browser before layout using the following snippet.
import { SpringGrid, measureItems } from 'react-stonecutter';
const Grid = measureItems(SpringGrid);
<Grid
component="ul"
columns={3}
columnWidth={350}
gutterWidth={3}
gutterHeight={3}
layout={layout.pinterest}
IMG A IMG B IMG C IMG D
But I am getting all images are overlapped with the single image. Any idea about this issue. I want to implement "Pinterest grid layout".
react-stonecutter is an amazing package, many thanks. In addition, I thought it would have been great if it had sorting option for SpringGrid
. Currently it works as per the masonry but compromises with the order (well, nothing wrong in it).
I have used this tool and it works awesome(great job) but I am facing a problem when minimizing the browser window width below 480px using my mouse or opening the application on a smartphone.
Every card is collapsing into each other for all rows and columns and forming like a piled up deck of cards.
I am using the div as a tag and I created my card using bootstrap grid base system (e.g: col-xs-12 col-sm-12 col-md-12 col-lg-12)
===========================
let Catalogue = measureItems(SpringGrid,{ measureImages: true , background:true });
Catalogue = makeResponsive(Catalogue, {
maxWidth: 1900,
minPadding: 80,
defaultColumns: 4
});
const CardCatalogue = ({dataItems}) => {
const setupGrid = {
layout:layouts.pinterest,//simple, pinterest
widthColumn:400,
itemsHeight:530,
stiffness:250,
damping:15,
perspectiveAmt:600,
guttersWidth:10,
guttersHeight:10,
columns:3,
duration:800
};
return(
<Catalogue
component='div'
columnWidth={setupGrid.widthColumn}
gutterWidth={setupGrid.guttersWidth}
gutterHeight={setupGrid.guttersHeight}
layout={setupGrid.layout}
springConfig={{ stiffness: setupGrid.stiffness, damping: setupGrid.damping }}
perspective={setupGrid.perspectiveAmt}
duration={setupGrid.duration}>
{
dataItems.map((item) => (
<div className='card2 tariffCardWidth400px card-1 row noPadMar borderThicker' key={item.id}> <ItemCard key={item.id} item={item} /></div>
))
}
</Catalogue>
);
};
CardCatalogue.propTypes = {
dataItems: PropTypes.array.isRequired
};
export default CardCatalogue;
=========================================
From what I am seeing in the html source code in chrome the transform style is going from (for 2 items)
item1: position: absolute; top: 0px; left: 0px; z-index: 2; opacity: 1; transform: translateX(0px) translateY(0px) perspective(600px) scale(1);
item2: position: absolute; top: 0px; left: 0px; z-index: 2; opacity: 1; transform: translateX(0px) translateY(553px) perspective(600px) scale(1);
into for both of the items
position: absolute; top: 0px; left: 0px; z-index: 2; opacity: 1; transform: translateX(-410px) translateY(0px) perspective(600px) scale(1);
Its weird because -410 is the width for each item 400+10(gutter).
Am I doing something wrong?
=================================================
css that i use on the div inside the map is
.tariffCardWidth400px{
width: 400px;
}
.card2 {
background: #ffffff;
border-radius: 1px;
display: inline-block;
position: relative;
overflow-y: auto;
padding: 0;
margin: 0;
border-bottom-width: 40px!important;
border-bottom-color: #49C5D1!important;
}
.card-1 {
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
}
.card-1:hover {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
.noPadMar{
padding-left: 0px!important;
padding-right: 0px!important;
padding-top: 0px!important;
padding-bottom: 0px!important;
margin-left: 0px!important;
margin-right: 0px!important;
margin-top: 0px!important;
margin-bottom: 0px!important;
}
.borderThicker{
border-color: #e7eaec;
border-width: thin;
border-style: solid;
}
Hey Great component,
Would be great to be able to define "stamps" much like Isotope Stamps.
which is pretty much the only thing stopping me from using it...
For now it's impossible to set z-index of item because it is getting overrided, I think user should be able to set zIndex on his own.
Hi,
I have an issue with react-stonecutter because the first element of my list disappear when the screen is lower that 400px. It add a <!-- react-empty: 2967 -->
instead.
See below which parameters of react-stonecutter I use.
const Grid = makeResponsive(measureItems(CSSGrid, { measureImages: true }), {
maxWidth: 1920,
minPadding: 100
});
<Grid
component="ul"
columns={5}
columnWidth={300}
gutterWidth={10}
gutterHeight={8}
layout={layout.pinterest}
duration={800}
easing="ease-out"
className="cards list_styled-none"
>
{ids.map((id, key) => (
<li key={key} className={roles[id].children.length > 0 ? "card_container card" : "card"}>
<Card role={roles[id]}/>
</li>
))}
</Grid>
Thanks for you help!
Currently, if you provide custom react components under <CSSGrid>
, it will throw an error.
The code is here https://github.com/dantrain/react-stonecutter/blob/master/src/utils/assertIsElement.js
The solution is to wrap it with an extra <div>
. Unfortunately, it doesn't work well for me because I also use react-dnd
, and I have a weird bug on mobile.
Is possible to remove this validation? I am using a fork with this change and it works without any problems.
The custom component must only apply provided style
to the main <div>
.
If I include this module in my react project I get window undefined error thrown related to enquire.js library.
I am using this control, but I want to move a tile to the bottom if it doesn't have an image associated with it. Is there a way to move a tile programatically?
Also, do tiles support resizing and drag and drop?
Hi,
I'm using react-stonecutter on a server-side rendered page. You can see the example here: https://smartariffa.it/.
The server-side rendering is working, you can see that the cards content is present in the html source, search for “Senza limiti” for instance. However when the page loads the cards aren't displayed, until the Stonecutter layout calculation is done (I'm using measureItems
with a custom layout and a SpringGrid
) — which takes about 1 sec in the above example.
Do you have any idea why stonecutter “re-hydrating” isn't working as for other React server-side rendered components, and do you have any pointer about how to fix this issue?
With React 15.2+ I'm seeing the unknown props warning in react-stonecutter:
Warning: Unknown props columnWidth
, gutterWidth
, gutterHeight
, minPadding
, columns
, angleUnit
, layout
, enter
, entered
, exit
on
and
Warning: Unknown prop itemRect
on
Not sure what FB changed but lots of libs are tossing these warnings now. Stonecutter still works, but just wanted to give you a heads up.
I'm creating my grid like this:
private render() {
const Grid = makeResponsive(measureItems(SpringGrid), { maxWidth: 1024, minPadding: 50, defaultColumns: 2 });
let children = this.props.items.map(i =><li key={i.Id}><ItemCard item={i} /></li>);
return <div className='items-panel'>
<Grid component='ul' columnWidth={300} gutterWidth={10} gutterHeight={10} layout={layout.pinterest}>
{children}
</Grid>
</div>;
}
When I pass in only one item as my items, I'm seeing ItemsCard
's constructor being called twice:
Once as a result of being in the elementsToMeasure
collection, and then again after a state change when the element has been measured. On that second pass 'cloneElement' adds the itemRect
property to the object props, and as a result, the initial object is torn down and removed from the DOM and the new item is added.
Is there any way to make this more efficient so that it doesn't recalcuate, as my ItemCard
is quite a large component.
Is there some optimization I need to do in my ItemCard
? I attempted to add the lifecycle events for componentWillReceiveProps
but it is never called due to cloning.
Any plans to implement Drag & Drop reorder of panels? That would be a killing feature!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.