react-column-gallery
Version:
An React Column Gallery in react.
160 lines (150 loc) • 6.9 kB
JavaScript
;
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var React__default = _interopDefault(React);
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var round = function (value, decimals) {
if (!decimals)
decimals = 0;
return Number(Math.round(Number(value + 'e' + decimals)) + 'e-' + decimals);
};
var computeColumnLayout = function (photos, columns, containerWidth, spacing, footerHeight) {
var horizontalGap = 0;
var verticalGap = 0;
if (typeof spacing === 'number') {
horizontalGap = spacing;
verticalGap = spacing;
}
else {
horizontalGap = spacing.horizontal;
verticalGap = spacing.vertical;
}
// calculate each colWidth based on total width and column amount
var colWidth = (containerWidth - horizontalGap * (columns - 1)) / columns;
// map through each photo to assign adjusted height and width based on colWidth
var photosWithSize = photos.map(function (photo) {
var newHeight = (photo.height / photo.width) * colWidth;
return __assign(__assign({}, photo), { width: round(colWidth, 1), height: round(newHeight, 1), itemHeight: round(newHeight + footerHeight, 1) });
});
// store all possible left positions
// and current top positions for each column
var colLeftPositions = [];
var colCurrTopPositions = [];
for (var i = 0; i < columns; i++) {
colLeftPositions[i] = round(i * (colWidth + horizontalGap), 1);
colCurrTopPositions[i] = 0;
}
var containerHeight = 0;
// map through each photo, then reduce thru each "column"
// find column with the smallest height and assign to photo's 'top'
// update that column's height with this photo's height
var photosPositioned = photosWithSize.map(function (photo) {
var smallestCol = colCurrTopPositions.reduce(function (acc, item, i) {
acc = item < colCurrTopPositions[acc] ? i : acc;
return acc;
}, 0);
var top = colCurrTopPositions[smallestCol];
var left = colLeftPositions[smallestCol];
colCurrTopPositions[smallestCol] =
colCurrTopPositions[smallestCol] + photo.itemHeight + verticalGap;
var tallestCol = colCurrTopPositions.reduce(function (acc, item, i) {
acc = item > colCurrTopPositions[acc] ? i : acc;
return acc;
}, 0);
containerHeight = colCurrTopPositions[tallestCol];
return __assign(__assign({}, photo), { left: left, top: top });
});
return { photosPositioned: photosPositioned, containerHeight: containerHeight };
};
var defaultColumnsProvider = function (containerWidth) {
if (containerWidth >= 1500) {
return 4;
}
else if (containerWidth >= 900) {
return 3;
}
else if (containerWidth > 500) {
return 2;
}
else {
return 1;
}
};
var defaultSpacingProvider = function (containerWidth) {
if (containerWidth >= 1500) {
return 16;
}
else if (containerWidth >= 900) {
return 12;
}
else if (containerWidth > 500) {
return 8;
}
else {
return 4;
}
};
var Gallery = function (_a) {
var photos = _a.photos, columns = _a.columns, spacing = _a.spacing, initialContainerWidth = _a.initialContainerWidth, footerHeight = _a.footerHeight, renderPhoto = _a.renderPhoto, renderFooter = _a.renderFooter;
var _b = React.useState(initialContainerWidth || 0), containerWidth = _b[0], setContainerWidth = _b[1];
var measuredRef = React.useCallback(function (node) {
var observer = null;
if (node !== null) {
setContainerWidth(Math.floor(node.getBoundingClientRect().height));
observer = new ResizeObserver(function (entries) {
var newWidth = entries[0].contentRect.width;
if (containerWidth !== newWidth) {
window.requestAnimationFrame(function () {
setContainerWidth(Math.floor(newWidth));
});
}
});
observer.observe(node);
}
}, []);
columns = columns || defaultColumnsProvider;
if (typeof columns === "function") {
columns = columns(containerWidth);
}
spacing = spacing || defaultSpacingProvider;
if (typeof spacing === "function") {
spacing = spacing(containerWidth);
}
var _c = computeColumnLayout(photos, columns, containerWidth, spacing, footerHeight || 0), photosPositioned = _c.photosPositioned, containerHeight = _c.containerHeight;
return (React__default.createElement("div", { className: "react-column-gallery" },
React__default.createElement("div", { ref: measuredRef, style: {
position: "relative",
height: containerHeight,
} }, photosPositioned.map(function (p, index) { return (React__default.createElement("div", { key: p.key, className: "photo-wrapper", style: {
position: "absolute",
left: p.left,
top: p.top,
width: p.width,
height: p.height,
} }, renderPhoto ? (renderPhoto(p, index)) : (React__default.createElement("div", { className: "photo-card" },
React__default.createElement("img", { src: p.src, alt: p.alt, loading: p.loading, width: p.width, height: p.height, style: { verticalAlign: 'bottom' } }),
renderFooter && renderFooter(p, index))))); }))));
};
module.exports = Gallery;
//# sourceMappingURL=index.js.map