diff --git a/packages/wms-map-react-components/src/components/breadcrumb/breadcrumb.tsx b/packages/wms-map-react-components/src/components/breadcrumb/breadcrumb.tsx index 07559a29..66f8349d 100644 --- a/packages/wms-map-react-components/src/components/breadcrumb/breadcrumb.tsx +++ b/packages/wms-map-react-components/src/components/breadcrumb/breadcrumb.tsx @@ -1,14 +1,23 @@ import React, { FC, useState, useEffect, useRef } from 'react'; import BreadcrumbEditModal from './breadcrumb-edit-modal'; +import { ViewMode } from '../../typings'; import styles from './breadcrumb.module.scss'; interface BreadcrumbProps { warehouseIds: string[]; + viewMode: ViewMode; + showBreadcrumbEditButton?: (warehouseIds: string[]) => boolean; onWarehouseClick?: (warehouseId: string, index: number) => void; onNameChange?: (name: string) => Promise; } -const Breadcrumb: FC = ({ warehouseIds, onWarehouseClick, onNameChange }) => { +const Breadcrumb: FC = ({ + warehouseIds, + viewMode, + showBreadcrumbEditButton = (): boolean => true, + onWarehouseClick, + onNameChange, +}) => { const [showDropdown, setShowDropdown] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [editingIndex, setEditingIndex] = useState(-1); @@ -141,17 +150,19 @@ const Breadcrumb: FC = ({ warehouseIds, onWarehouseClick, onNam
{shouldCollapse ? renderCollapsedBreadcrumb() : renderFullBreadcrumb()} - + {viewMode === ViewMode.EDIT && showBreadcrumbEditButton(warehouseIds) && ( + + )}
diff --git a/packages/wms-map-react-components/src/components/canvas/react-flow-canvas.tsx b/packages/wms-map-react-components/src/components/canvas/react-flow-canvas.tsx index 39833729..c6577ab0 100644 --- a/packages/wms-map-react-components/src/components/canvas/react-flow-canvas.tsx +++ b/packages/wms-map-react-components/src/components/canvas/react-flow-canvas.tsx @@ -48,6 +48,7 @@ interface ReactFlowCanvasProps { onNodeMouseEnter?: (event: React.MouseEvent, node: ReactFlowNode) => void; onNodeMouseLeave?: (event: React.MouseEvent, node: ReactFlowNode) => void; onNodeClick?: (event: React.MouseEvent, node: ReactFlowNode) => void; + onNodeDoubleClick?: (event: React.MouseEvent, node: ReactFlowNode) => void; showBackground?: boolean; } @@ -118,6 +119,7 @@ const ReactFlowCanvas: FC = ({ onNodeMouseEnter, onNodeMouseLeave, onNodeClick, + onNodeDoubleClick, showBackground = true, }) => { // console.log('🖼️ ReactFlowCanvas 接收到 showBackground:', showBackground); @@ -258,6 +260,7 @@ const ReactFlowCanvas: FC = ({ onNodeMouseEnter={onNodeMouseEnter} onNodeMouseLeave={onNodeMouseLeave} onNodeClick={onNodeClick} + onNodeDoubleClick={onNodeDoubleClick} nodeTypes={nodeTypes} className={styles.reactFlowCanvas} style={{ background: '#F5F5F5' }} @@ -271,7 +274,7 @@ const ReactFlowCanvas: FC = ({ panOnDrag={viewMode === ViewMode.VIEW || (viewMode === ViewMode.EDIT && drawingMode === DrawingMode.NONE)} panOnScroll={false} zoomOnScroll={true} - zoomOnDoubleClick={viewMode === ViewMode.EDIT && drawingMode !== DrawingMode.PEN} + zoomOnDoubleClick={false} nodeOrigin={[0, 0]} preventScrolling={true} > diff --git a/packages/wms-map-react-components/src/components/modal/wms-map-content.tsx b/packages/wms-map-react-components/src/components/modal/wms-map-content.tsx index 500e7d19..a12063f2 100644 --- a/packages/wms-map-react-components/src/components/modal/wms-map-content.tsx +++ b/packages/wms-map-react-components/src/components/modal/wms-map-content.tsx @@ -40,11 +40,13 @@ const WMSMapContent: FC = ({ selectedColor, viewMode, colorPalette, + showBreadcrumbEditButton, onEditModeChange, onToggleRectangleTool, onTogglePenTool, onColorChange, onNodeClick, + onNodeDoubleClick, onSave, onBreadcrumbClick, onNameChange, @@ -674,11 +676,73 @@ const WMSMapContent: FC = ({ [viewMode], ); + const clickTimerRef = useRef | null>(null); + + useEffect( + () => (): void => { + if (clickTimerRef.current) { + clearTimeout(clickTimerRef.current); + clickTimerRef.current = null; + } + }, + [], + ); + const handleNodeClick = useCallback( (_event: React.MouseEvent, node: ReactFlowNode) => { const flowNode = node as unknown as FlowNode; - debugLog('events', 'Node clicked (React Flow)', { + const fireClick = (): void => { + debugLog('events', 'Node clicked (React Flow)', { + id: flowNode.id.slice(-4), + type: flowNode.type, + viewMode, + editMode, + }); + + logNodeData(flowNode); + + if (onNodeClick) { + const nodeClickInfo = transformNodeToClickInfo(flowNode); + + if (nodeClickInfo) { + debugLog('events', '將點擊資訊傳遞給父組件:', nodeClickInfo); + onNodeClick(nodeClickInfo); + } + } + }; + + // 沒有訂閱雙擊事件時,單擊直接觸發避免引入無謂的 350ms 延遲 + if (!onNodeDoubleClick) { + fireClick(); + + return; + } + + // 延遲觸發 click,讓 double click 有機會取消 + if (clickTimerRef.current) { + clearTimeout(clickTimerRef.current); + } + + clickTimerRef.current = setTimeout(() => { + clickTimerRef.current = null; + fireClick(); + }, 350); + }, + [viewMode, editMode, onNodeClick, onNodeDoubleClick], + ); + + const handleNodeDoubleClick = useCallback( + (_event: React.MouseEvent, node: ReactFlowNode) => { + // 取消待執行的 click,避免 double click 同時觸發 click + if (clickTimerRef.current) { + clearTimeout(clickTimerRef.current); + clickTimerRef.current = null; + } + + const flowNode = node as unknown as FlowNode; + + debugLog('events', 'Node double clicked (React Flow)', { id: flowNode.id.slice(-4), type: flowNode.type, viewMode, @@ -687,16 +751,16 @@ const WMSMapContent: FC = ({ logNodeData(flowNode); - if (onNodeClick) { - const nodeClickInfo = transformNodeToClickInfo(flowNode); + if (onNodeDoubleClick) { + const nodeDoubleClickInfo = transformNodeToClickInfo(flowNode); - if (nodeClickInfo) { - debugLog('events', '將點擊資訊傳遞給父組件:', nodeClickInfo); - onNodeClick(nodeClickInfo); + if (nodeDoubleClickInfo) { + debugLog('events', '將雙擊資訊傳遞給父組件:', nodeDoubleClickInfo); + onNodeDoubleClick(nodeDoubleClickInfo); } } }, - [viewMode, editMode, onNodeClick], + [viewMode, editMode, onNodeDoubleClick], ); const handleToggleBackground = useCallback((show: boolean) => { @@ -811,7 +875,13 @@ const WMSMapContent: FC = ({ return ( <> - + {viewMode === ViewMode.EDIT && ( = ({ onNodeMouseEnter={handleNodeMouseEnter} onNodeMouseLeave={handleNodeMouseLeave} onNodeClick={handleNodeClick} + onNodeDoubleClick={handleNodeDoubleClick} showBackground={showBackground} /> diff --git a/packages/wms-map-react-components/src/components/modal/wms-map-modal-container.tsx b/packages/wms-map-react-components/src/components/modal/wms-map-modal-container.tsx index 99079ca9..c1d94403 100644 --- a/packages/wms-map-react-components/src/components/modal/wms-map-modal-container.tsx +++ b/packages/wms-map-react-components/src/components/modal/wms-map-modal-container.tsx @@ -14,11 +14,13 @@ export const WMSMapModalContent = ({ selectedColor, viewMode, colorPalette, + showBreadcrumbEditButton, onEditModeChange, onToggleRectangleTool, onTogglePenTool, onColorChange, onNodeClick, + onNodeDoubleClick, onSave, onBreadcrumbClick, onNameChange, @@ -38,11 +40,13 @@ export const WMSMapModalContent = ({ selectedColor={selectedColor} viewMode={viewMode} colorPalette={colorPalette} + showBreadcrumbEditButton={showBreadcrumbEditButton} onEditModeChange={onEditModeChange} onToggleRectangleTool={onToggleRectangleTool} onTogglePenTool={onTogglePenTool} onColorChange={onColorChange} onNodeClick={onNodeClick} + onNodeDoubleClick={onNodeDoubleClick} onSave={onSave} onBreadcrumbClick={onBreadcrumbClick} onNameChange={onNameChange} @@ -63,7 +67,9 @@ const WMSMapModalContainer: FC = ({ onClose, viewMode = ViewMode.EDIT, colorPalette, + showBreadcrumbEditButton, onNodeClick, + onNodeDoubleClick, onSave, onBreadcrumbClick, onNameChange, @@ -139,11 +145,13 @@ const WMSMapModalContainer: FC = ({ selectedColor={selectedColor} viewMode={viewMode} colorPalette={colorPalette} + showBreadcrumbEditButton={showBreadcrumbEditButton} onEditModeChange={handleEditModeChange} onToggleRectangleTool={handleToggleRectangleTool} onTogglePenTool={handleTogglePenTool} onColorChange={handleColorChange} onNodeClick={onNodeClick} + onNodeDoubleClick={onNodeDoubleClick} onSave={onSave} onBreadcrumbClick={onBreadcrumbClick} onNameChange={onNameChange} diff --git a/packages/wms-map-react-components/src/types/component-props.types.ts b/packages/wms-map-react-components/src/types/component-props.types.ts index 6ffca819..3fba2e24 100644 --- a/packages/wms-map-react-components/src/types/component-props.types.ts +++ b/packages/wms-map-react-components/src/types/component-props.types.ts @@ -6,7 +6,9 @@ export interface WMSMapModalProps { open: boolean; viewMode?: ViewMode; colorPalette?: string[]; + showBreadcrumbEditButton?: (warehouseIds: string[]) => boolean; onNodeClick?: (nodeInfo: WMSNodeClickInfo) => void; + onNodeDoubleClick?: (nodeInfo: WMSNodeClickInfo) => void; onSave?: (mapData: Map) => void; onBreadcrumbClick?: (warehouseId: string, index: number) => void; onNameChange?: (name: string) => Promise; @@ -26,11 +28,13 @@ export interface WMSMapContentProps { selectedColor: string; viewMode: ViewMode; colorPalette?: string[]; + showBreadcrumbEditButton?: (warehouseIds: string[]) => boolean; onEditModeChange: (mode: EditMode) => void; onToggleRectangleTool: () => void; onTogglePenTool: () => void; onColorChange: (color: string) => void; onNodeClick?: (nodeInfo: WMSNodeClickInfo) => void; + onNodeDoubleClick?: (nodeInfo: WMSNodeClickInfo) => void; onSave?: (mapData: Map) => void; onBreadcrumbClick?: (warehouseId: string, index: number) => void; onNameChange?: (name: string) => Promise; diff --git a/packages/wms-map-react-components/stories/wms-map-modal.stories.tsx b/packages/wms-map-react-components/stories/wms-map-modal.stories.tsx index cf2c92d1..a81fa799 100644 --- a/packages/wms-map-react-components/stories/wms-map-modal.stories.tsx +++ b/packages/wms-map-react-components/stories/wms-map-modal.stories.tsx @@ -86,6 +86,7 @@ const meta: Meta = { open: true, onClose: action('onClose'), onNodeClick: action('onNodeClick'), + onNodeDoubleClick: action('onNodeDoubleClick'), onSave: action('onSave'), onBreadcrumbClick: action('onBreadcrumbClick'), onUpload: async (files: File[]): Promise => {