import React, { useState, useEffect, useMemo, useRef } from 'react'; import { LabelTemplate, TemplateElement, PaperConfig, VisibilityRule } from '../types'; import { extractTemplateVariables, extractVariablesFromContent, isConditionalVisibility, isTemplateVariableInUse, removeUnusedTemplateVariable, resolveVisibilityRules, toggleVisibilityRuleEnabled, withContentAndSyncedName, } from '../utils'; import { VisibilityRuleDialog } from './VisibilityRuleDialog'; import { VisibilityRuleSummary } from './VisibilityRuleSummary'; import { ValueExtractFields } from './ValueExtractFields'; import { TextDisplayAffixFields } from './TextDisplayAffixFields'; import { alignToSelectionBounds, alignSelectionToCanvas, tileSelectedEvenly, tileSelectedFlush, type AlignMode, } from '../elementAlign'; import { CollapsiblePanelSection } from './CollapsiblePanelSection'; import { FieldSelect } from './PsSelect'; import { CommitInput } from './CommitInput'; import { useAppDialog } from './AppDialog'; import { useIsNarrowScreen } from '../hooks/useIsMobile'; import type { ElementClipboardActions } from '../hooks/useElementClipboard'; import { TablePropertyFields, TableCellContentFields, scaleTableElementSize, } from './TablePropertyFields'; import type { TableCellCoord } from '../tableUtils'; import { expandTableForPadding } from '../tableUtils'; import { Sliders, LayoutGrid, Type, AlignLeft, AlignCenter, AlignRight, Bold, Italic, Underline, Strikethrough, HelpCircle, Lock, Unlock, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Move, Layers, Trash2, Copy, AlignHorizontalJustifyStart, AlignHorizontalJustifyCenter, AlignHorizontalJustifyEnd, AlignVerticalJustifyStart, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignHorizontalSpaceBetween, AlignVerticalSpaceBetween, Columns2, Rows2, Link2, Plus, Ruler, RotateCw, Barcode, QrCode, Image as ImageIcon, Upload, Table2, } from 'lucide-react'; const PANEL_COLLAPSE_STORAGE_KEY = 'label_designer_panel_collapse_v2'; type PanelCollapseState = { content: boolean; properties: boolean; layers: boolean; }; function loadPanelCollapseState(): PanelCollapseState { try { const raw = localStorage.getItem(PANEL_COLLAPSE_STORAGE_KEY); if (raw) return JSON.parse(raw) as PanelCollapseState; } catch { /* ignore */ } return { content: true, properties: false, layers: true }; } const alignBtnClass = 'px-2 py-1.5 bg-[#383838] hover:bg-[#444] border border-[#4a4a4a] hover:border-[#31a8ff]/50 text-[10px] text-[#ccc] flex flex-col items-center justify-center gap-0.5 transition cursor-pointer rounded-sm min-h-[52px]'; interface AlignToolButtonProps { icon: React.ReactNode; label: string; title: string; onClick: () => void; } const AlignToolButton: React.FC = ({ icon, label, title, onClick }) => ( ); const PropInput = CommitInput; interface PropTextareaProps extends Omit, 'onChange'> { value: string; onCommit: (val: string) => void; } const PropTextarea: React.FC = ({ value, onCommit, ...props }) => { const [localVal, setLocalVal] = useState(value); const focusedRef = useRef(false); const localValRef = useRef(localVal); const valueRef = useRef(value); const onCommitRef = useRef(onCommit); localValRef.current = localVal; valueRef.current = value; onCommitRef.current = onCommit; useEffect(() => { if (!focusedRef.current) { setLocalVal(value); } }, [value]); useEffect(() => { return () => { if ( focusedRef.current && localValRef.current !== valueRef.current ) { onCommitRef.current(localValRef.current); } }; }, []); const handleBlur = () => { focusedRef.current = false; if (localValRef.current !== valueRef.current) { onCommitRef.current(localValRef.current); } }; return (