UNPKG

merchi_product_editor

Version:

A React component for editing product images using Fabric.js

224 lines (223 loc) 11.9 kB
"use strict"; 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)); }; Object.defineProperty(exports, "__esModule", { value: true }); var react_1 = __importStar(require("react")); var ProductEditorContext_1 = require("../context/ProductEditorContext"); var grommet_icons_1 = require("grommet-icons"); require("../styles/LayerPanel.css"); var reorder = function (list, startIndex, endIndex) { var result = Array.from(list); var removed = result.splice(startIndex, 1)[0]; result.splice(endIndex, 0, removed); return result; }; var LAYER_ITEM_HEIGHT_PX = 45; var LayerPanel = function () { var _a = (0, ProductEditorContext_1.useProductEditor)(), canvas = _a.canvas, toggleLayerPanel = _a.toggleLayerPanel, selectedObjectId = _a.selectedObjectId, selectObject = _a.selectObject, isMobileView = _a.isMobileView; var _b = (0, react_1.useState)([]), layers = _b[0], setLayers = _b[1]; var dragItemIndex = (0, react_1.useRef)(null); var dragOverItemIndex = (0, react_1.useRef)(null); var _c = (0, react_1.useState)(false), isDraggingOver = _c[0], setIsDraggingOver = _c[1]; var _d = (0, react_1.useState)(null), dragOverIndexVisual = _d[0], setDragOverIndexVisual = _d[1]; (0, react_1.useEffect)(function () { if (canvas) { var updateLayers_1 = function () { var filteredObjects = canvas.getObjects().filter(function (obj) { return (obj.type === 'i-text' || obj.type === 'image') && obj.selectable; }); setLayers(__spreadArray([], filteredObjects, true).reverse()); }; updateLayers_1(); var handleCanvasChange_1 = function () { return updateLayers_1(); }; canvas.on('object:added', handleCanvasChange_1); canvas.on('object:removed', handleCanvasChange_1); canvas.on('stack:changed', handleCanvasChange_1); canvas.on('selection:created', handleCanvasChange_1); canvas.on('selection:updated', handleCanvasChange_1); canvas.on('selection:cleared', handleCanvasChange_1); return function () { canvas.off('object:added', handleCanvasChange_1); canvas.off('object:removed', handleCanvasChange_1); canvas.off('stack:changed', handleCanvasChange_1); canvas.off('selection:created', handleCanvasChange_1); canvas.off('selection:updated', handleCanvasChange_1); canvas.off('selection:cleared', handleCanvasChange_1); }; } }, [canvas]); var getLayerInfo = function (object) { var _a, _b; if (object.type === 'i-text') { return { name: ((_a = object.text) === null || _a === void 0 ? void 0 : _a.substring(0, 20)) || 'Text', icon: react_1.default.createElement(grommet_icons_1.TextAlignCenter, { size: "medium" }) }; } if (object.type === 'image') { var imageObject = object; var src = imageObject.getSrc(); return { name: object.name || (src ? (_b = src.split('/').pop()) === null || _b === void 0 ? void 0 : _b.substring(0, 20) : undefined) || 'Image', icon: react_1.default.createElement("img", { src: src, alt: "layer thumb", className: "layer-thumbnail" }) }; } return { name: 'Unknown Layer', icon: react_1.default.createElement(react_1.default.Fragment, null) }; }; var handleDragStart = function (e, index) { if (isMobileView) return; dragItemIndex.current = index; e.dataTransfer.effectAllowed = 'move'; setTimeout(function () { return setIsDraggingOver(true); }, 0); }; var handleDragEnterItem = function (e, index) { if (isMobileView) return; e.preventDefault(); dragOverItemIndex.current = index; setDragOverIndexVisual(index); }; var handleDragLeaveList = function (e) { if (isMobileView) return; if (!e.currentTarget.contains(e.relatedTarget)) { dragOverItemIndex.current = null; setDragOverIndexVisual(null); } }; var handleDragOverList = function (e) { if (isMobileView) return; e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }; var handleDrop = function (e) { if (isMobileView) return; e.preventDefault(); var sourceIndex = dragItemIndex.current; var destinationIndex = dragOverItemIndex.current; setIsDraggingOver(false); setDragOverIndexVisual(null); dragItemIndex.current = null; dragOverItemIndex.current = null; if (sourceIndex === null || destinationIndex === null || sourceIndex === destinationIndex) { return; } var reorderedLayers = reorder(layers, sourceIndex, destinationIndex); var objectToMove = layers[sourceIndex]; setLayers(reorderedLayers); if (canvas && objectToMove) { var totalObjects = canvas.getObjects().length; var fabricTargetIndex = totalObjects - 1 - destinationIndex; canvas.moveTo(objectToMove, fabricTargetIndex); canvas.requestRenderAll(); } }; var handleDragEnd = function (e) { if (isMobileView) return; setIsDraggingOver(false); setDragOverIndexVisual(null); dragItemIndex.current = null; dragOverItemIndex.current = null; }; var moveLayerUp = function (index) { if (index <= 0 || !canvas) return; var objectToMove = layers[index]; var objectAbove = layers[index - 1]; var fabricIndexOfAbove = canvas.getObjects().indexOf(objectAbove); if (fabricIndexOfAbove < 0) { console.error("Could not find objectAbove in canvas stack for moveLayerUp"); return; } var targetFabricIndex = fabricIndexOfAbove; canvas.moveTo(objectToMove, targetFabricIndex); setLayers(function (prevLayers) { return reorder(prevLayers, index, index - 1); }); canvas.requestRenderAll(); }; var moveLayerDown = function (index) { if (index >= layers.length - 1 || !canvas) return; var objectToMove = layers[index]; var objectBelow = layers[index + 1]; var fabricIndexOfBelow = canvas.getObjects().indexOf(objectBelow); if (fabricIndexOfBelow < 0) { console.error("Could not find objectBelow in canvas stack for moveLayerDown"); return; } var targetFabricIndex = fabricIndexOfBelow; canvas.moveTo(objectToMove, targetFabricIndex); setLayers(function (prevLayers) { return reorder(prevLayers, index, index + 1); }); canvas.requestRenderAll(); }; var handleLayerClick = function (layer) { selectObject(layer); }; return (react_1.default.createElement("div", { className: "layer-panel" }, react_1.default.createElement("div", { className: "layer-panel-header" }, react_1.default.createElement("h3", null, "Layers"), react_1.default.createElement("button", { onClick: toggleLayerPanel, className: "close-button", title: "Close Panel" }, react_1.default.createElement(grommet_icons_1.Close, { size: "small" }))), react_1.default.createElement("ul", { className: "layer-list ".concat(isDraggingOver ? 'is-dragging-active' : ''), onDragOver: handleDragOverList, onDrop: handleDrop, onDragLeave: handleDragLeaveList }, layers.map(function (layer, index) { var layerInfo = getLayerInfo(layer); var layerId = layer.id; var isSelected = layerId && layerId === selectedObjectId; var isDraggingThisItem = !isMobileView && isDraggingOver && dragItemIndex.current === index; var transformStyle = 'translateY(0px)'; if (!isMobileView && isDraggingOver && dragItemIndex.current !== null && dragOverIndexVisual !== null && !isDraggingThisItem) { var draggingFromIndex = dragItemIndex.current; var hoveringOverIndex = dragOverIndexVisual; if (index > draggingFromIndex && index <= hoveringOverIndex) { transformStyle = "translateY(-".concat(LAYER_ITEM_HEIGHT_PX, "px)"); } else if (index < draggingFromIndex && index >= hoveringOverIndex) { transformStyle = "translateY(".concat(LAYER_ITEM_HEIGHT_PX, "px)"); } } return (react_1.default.createElement("li", { key: "layer-".concat(layerId || index), draggable: !isMobileView, onDragStart: function (e) { return handleDragStart(e, index); }, onDragEnter: function (e) { return handleDragEnterItem(e, index); }, onDragEnd: handleDragEnd, onClick: function () { return handleLayerClick(layer); }, className: "layer-item ".concat(isSelected ? 'selected' : '', " ").concat(isDraggingThisItem ? 'is-dragging-item' : ''), style: { transform: transformStyle } }, react_1.default.createElement("span", { className: "layer-icon" }, layerInfo.icon), react_1.default.createElement("span", { className: "layer-name" }, layerInfo.name), isMobileView ? (react_1.default.createElement("div", { className: "layer-mobile-controls" }, react_1.default.createElement("button", { className: "layer-move-button", onClick: function (e) { e.stopPropagation(); moveLayerUp(index); }, disabled: index === 0, title: "Move Up" }, react_1.default.createElement(grommet_icons_1.Up, { size: "small" })), react_1.default.createElement("button", { className: "layer-move-button", onClick: function (e) { e.stopPropagation(); moveLayerDown(index); }, disabled: index === layers.length - 1, title: "Move Down" }, react_1.default.createElement(grommet_icons_1.Down, { size: "small" })))) : (react_1.default.createElement("span", { className: "layer-drag-indicator" }, react_1.default.createElement(grommet_icons_1.Drag, { size: "small" }))))); }), layers.length === 0 && react_1.default.createElement("li", { className: "no-layers" }, "No layers found")))); }; exports.default = LayerPanel;