merchi_product_editor
Version:
A React component for editing product images using Fabric.js
132 lines (131 loc) • 8.06 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importStar(require("react"));
var framer_motion_1 = require("framer-motion");
var ImageNavButton_1 = __importDefault(require("./ImageNavButton"));
var ImageZoomModal_1 = __importDefault(require("./ImageZoomModal"));
var grommet_icons_1 = require("grommet-icons");
var ProductEditorContext_1 = require("../context/ProductEditorContext");
var ImageGallery = function (_a) {
var _b;
var _c = _a.fallbackImageUrl, fallbackImageUrl = _c === void 0 ? '' : _c;
var product = (0, ProductEditorContext_1.useProductEditor)().product;
var _d = product.featureImage, featureImage = _d === void 0 ? null : _d, _e = product.images, images = _e === void 0 ? [] : _e, _f = product.name, productName = _f === void 0 ? 'Loading...' : _f;
var _images = featureImage ? __spreadArray([featureImage], images, true) : images;
var allImages = _images.map(function (image) {
if (!image)
return { viewUrl: '/blueman_white.png' };
return { viewUrl: image.viewUrl };
});
var totalImages = allImages.length;
// image browser related states
var _g = (0, react_1.useState)('right'), slideDirection = _g[0], setSlideDirection = _g[1];
var _h = (0, react_1.useState)(false), isZoomModalOpen = _h[0], setIsZoomModalOpen = _h[1];
var _j = (0, react_1.useState)(true), isImageLoading = _j[0], setIsImageLoading = _j[1];
var _k = (0, react_1.useState)(0), currentIndex = _k[0], setCurrentIndex = _k[1];
var _l = (0, react_1.useState)(((_b = allImages[currentIndex]) === null || _b === void 0 ? void 0 : _b.viewUrl) || fallbackImageUrl || '/blueman_white.png'), currentImageUrl = _l[0], setCurrentImageUrl = _l[1];
(0, react_1.useEffect)(function () {
var _a;
// set current image URL (for normal image mode)
if (allImages && allImages.length > 0) {
setCurrentImageUrl(((_a = allImages[currentIndex]) === null || _a === void 0 ? void 0 : _a.viewUrl) || '/blueman_white.png');
}
}, [allImages, currentIndex, fallbackImageUrl]);
var handleNavigation = function (newDirection) {
var _a;
if (!allImages || allImages.length <= 1)
return;
setSlideDirection(newDirection === 'left' ? 'left' : 'right');
var newIndex;
var actualTotalImages = Math.min(totalImages, allImages.length);
if (newDirection === 'left') {
newIndex = currentIndex === 0 ? actualTotalImages - 1 : currentIndex - 1;
}
else {
newIndex = currentIndex === actualTotalImages - 1 ? 0 : currentIndex + 1;
}
setCurrentIndex(newIndex);
setCurrentImageUrl(((_a = allImages[newIndex]) === null || _a === void 0 ? void 0 : _a.viewUrl) || '/blueman_white.png');
};
var handleThumbnailClick = function (index) {
var _a;
setCurrentIndex(index);
setCurrentImageUrl(((_a = allImages[index]) === null || _a === void 0 ? void 0 : _a.viewUrl) || '/blueman_white.png');
};
var slideVariants = {
enter: function (direction) { return ({
x: direction === 'left' ? -1000 : 1000,
opacity: 0
}); },
center: {
zIndex: 1,
x: 0,
opacity: 1
},
exit: function (direction) { return ({
zIndex: 0,
x: direction === 'left' ? 1000 : -1000,
opacity: 0
}); }
};
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement("div", { className: "image-gallery-container" },
react_1.default.createElement("div", { className: "image-container" },
react_1.default.createElement(framer_motion_1.AnimatePresence, { initial: false, custom: slideDirection },
react_1.default.createElement(framer_motion_1.motion.div, { key: currentIndex, custom: slideDirection, variants: slideVariants, initial: "enter", animate: "center", exit: "exit", transition: {
x: { type: "spring", stiffness: 300, damping: 30 },
opacity: { duration: 0.2 }
}, className: "image-slide" },
react_1.default.createElement("img", { src: currentImageUrl, alt: productName || "Product Image", className: "gallery-image ".concat(isImageLoading ? '' : 'image-loaded'), onLoad: function () { return setIsImageLoading(false); } }),
isImageLoading && (react_1.default.createElement("div", { className: "loading-indicator" },
react_1.default.createElement("div", { className: "loading-spinner" }))))),
react_1.default.createElement("button", { onClick: function () { return setIsZoomModalOpen(true); }, className: "zoom-button" },
react_1.default.createElement(grommet_icons_1.ZoomIn, { className: "zoom-icon" }))),
allImages.length > 1 && (react_1.default.createElement("div", { className: "nav-buttons-container" },
react_1.default.createElement(ImageNavButton_1.default, { direction: "left", onClick: function () { return handleNavigation('left'); } }),
react_1.default.createElement(ImageNavButton_1.default, { direction: "right", onClick: function () { return handleNavigation('right'); } })))),
allImages.length > 1 && (react_1.default.createElement("div", { className: "thumbnails-container" },
react_1.default.createElement("div", { className: "thumbnails-row" }, allImages.slice(0, 5).map(function (image, index) {
var imageSrc = image.viewUrl || "/blueman_white.png";
var isSelected = index === currentIndex;
return (react_1.default.createElement("button", { key: index, onClick: function () { return handleThumbnailClick(index); }, className: "thumbnail-button ".concat(isSelected ? 'selected' : '') },
react_1.default.createElement("img", { src: imageSrc, loading: "lazy", alt: "Product Image ".concat(index + 1), className: "thumbnail-image" })));
})))),
react_1.default.createElement(ImageZoomModal_1.default, { isOpen: isZoomModalOpen, onClose: function () { return setIsZoomModalOpen(false); }, imageUrl: currentImageUrl, productName: productName, totalImages: allImages.length, currentIndex: currentIndex, allImages: allImages })));
};
exports.default = ImageGallery;