优化布局和交互
This commit is contained in:
@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react'
|
||||
import { createPortal } from 'react-dom';
|
||||
import { LabelTemplate, TemplateElement } from '../types';
|
||||
import { mmToPx, MM_TO_PX, shouldRenderElement } from '../utils';
|
||||
import type { ElementClipboardActions } from '../hooks/useElementClipboard';
|
||||
import {
|
||||
createDefaultTableElement,
|
||||
getTableColWidths,
|
||||
@@ -18,6 +19,7 @@ import { CanvasLabelImage } from './CanvasLabelImage';
|
||||
import { ElementFloatPreview, renderElementFloatPreview } from './ElementFloatPreview';
|
||||
import { renderLabelToDataUrl } from '../labelRenderer';
|
||||
import { useAppDialog } from './AppDialog';
|
||||
import { MobileMainToolButtons, type MobileToolButtonItem } from './MobileMainToolButtons';
|
||||
import {
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
@@ -40,6 +42,10 @@ interface LabelDesignerProps {
|
||||
variant?: 'desktop' | 'mobile';
|
||||
/** 微调等场景下隐藏选区框与缩放手柄 */
|
||||
suppressSelectionChrome?: boolean;
|
||||
elementClipboard?: Pick<
|
||||
ElementClipboardActions,
|
||||
'copySelectedElements' | 'pasteClipboardElements' | 'canCopy' | 'canPaste' | 'clipboardCount'
|
||||
>;
|
||||
}
|
||||
|
||||
type ActiveTool = 'move' | 'text' | 'barcode' | 'qrcode' | 'table';
|
||||
@@ -212,6 +218,7 @@ export const LabelDesigner: React.FC<LabelDesignerProps> = ({
|
||||
onSelectTableCells,
|
||||
variant = 'desktop',
|
||||
suppressSelectionChrome = false,
|
||||
elementClipboard,
|
||||
}) => {
|
||||
const { showConfirm } = useAppDialog();
|
||||
const selectedElementId = selectedElementIds[0] || null;
|
||||
@@ -494,6 +501,17 @@ export const LabelDesigner: React.FC<LabelDesignerProps> = ({
|
||||
onSelectElements(template.elements.filter((el) => !el.locked).map((el) => el.id));
|
||||
return;
|
||||
}
|
||||
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c') {
|
||||
e.preventDefault();
|
||||
elementClipboard?.copySelectedElements();
|
||||
return;
|
||||
}
|
||||
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v') {
|
||||
e.preventDefault();
|
||||
elementClipboard?.pasteClipboardElements();
|
||||
setActiveTool('move');
|
||||
return;
|
||||
}
|
||||
if (e.key === 'Delete' || e.key === 'Backspace') {
|
||||
e.preventDefault();
|
||||
void deleteSelectedElements();
|
||||
@@ -539,6 +557,7 @@ export const LabelDesigner: React.FC<LabelDesignerProps> = ({
|
||||
addElement,
|
||||
onSelectElements,
|
||||
deleteSelectedElements,
|
||||
elementClipboard,
|
||||
]);
|
||||
|
||||
const clearInteractionCanvasState = useCallback(() => {
|
||||
@@ -1430,6 +1449,28 @@ export const LabelDesigner: React.FC<LabelDesignerProps> = ({
|
||||
{ id: 'qrcode', icon: <QrCode className="w-[18px] h-[18px]" />, label: '二维码' },
|
||||
];
|
||||
|
||||
const mobileToolItems = useMemo<MobileToolButtonItem[]>(
|
||||
() => [
|
||||
...tools.map((tool) => ({
|
||||
id: tool.id,
|
||||
icon: tool.icon,
|
||||
label: tool.label,
|
||||
shortcut: tool.shortcut,
|
||||
active: activeTool === tool.id,
|
||||
onClick: () => handleToolClick(tool.id),
|
||||
})),
|
||||
{
|
||||
id: 'image',
|
||||
icon: <ImageIcon className="w-[18px] h-[18px]" />,
|
||||
label: '图片',
|
||||
active: false,
|
||||
onClick: handleImageToolClick,
|
||||
},
|
||||
],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- tools 为静态配置,随 activeTool 更新即可
|
||||
[activeTool]
|
||||
);
|
||||
|
||||
const mainToolButtons = (
|
||||
<>
|
||||
{tools.map((tool) => (
|
||||
@@ -1922,9 +1963,14 @@ export const LabelDesigner: React.FC<LabelDesignerProps> = ({
|
||||
|
||||
{isMobileLayout ? (
|
||||
<div className="mobile-design-toolstrip">
|
||||
<div className="mobile-design-toolstrip-tools">
|
||||
{mainToolButtons}
|
||||
</div>
|
||||
<MobileMainToolButtons items={mobileToolItems} />
|
||||
<input
|
||||
ref={imageInputRef}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
className="hidden"
|
||||
onChange={handleImageFile}
|
||||
/>
|
||||
{zoomControls}
|
||||
</div>
|
||||
) : (
|
||||
@@ -1952,7 +1998,7 @@ export const LabelDesigner: React.FC<LabelDesignerProps> = ({
|
||||
)}
|
||||
{activeTool === 'move' && (
|
||||
<span className="text-[#888] hidden sm:inline">
|
||||
| 框选 · Shift/Ctrl+点选 · Ctrl+A 全选
|
||||
| 框选 · Shift/Ctrl+点选 · Ctrl+A 全选 · Ctrl+C/V 复制粘贴
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user