// 节点提示词编辑器的高度拖拽与展开弹窗尺寸控制。 import { type KeyboardEvent as ReactKeyboardEvent, type PointerEvent as ReactPointerEvent, useRef } from "react"; import { clampPromptEditorModalSize } from "@/lib/canvas/canvas-prompt-editor-size"; import { PROMPT_EDITOR_EXPANDED_LINE_HEIGHT, PROMPT_EDITOR_EXPANDED_MAX_LINES, PROMPT_EDITOR_EXPANDED_MIN_HEIGHT, PROMPT_EDITOR_EXPANDED_VERTICAL_PADDING, PROMPT_EDITOR_LINE_HEIGHT, PROMPT_EDITOR_MAX_LINES, PROMPT_EDITOR_MIN_HEIGHT, PROMPT_EDITOR_VERTICAL_PADDING, PROMPT_REFERENCE_SHELF_HEIGHT, } from "./canvas-node-prompt-panel"; export function PromptResizeHandle({ height, min, max, onResize }: { height: number; min: number; max: number; onResize: (height: number) => void }) { const dragRef = useRef<{ pointerId: number; startY: number; startHeight: number } | null>(null); const finishResize = (event: ReactPointerEvent) => { if (dragRef.current?.pointerId !== event.pointerId) return; if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId); dragRef.current = null; }; const handleKeyDown = (event: ReactKeyboardEvent) => { if (event.key === "ArrowUp") { event.preventDefault(); onResize(Math.max(min, height - 8)); } else if (event.key === "ArrowDown") { event.preventDefault(); onResize(Math.min(max, height + 8)); } else if (event.key === "Home") { event.preventDefault(); onResize(min); } else if (event.key === "End") { event.preventDefault(); onResize(max); } }; return ( ); } export function clampExpandedModalSize(size: { width: number; height: number }) { return clampPromptEditorModalSize(size, { width: window.innerWidth, height: window.innerHeight }); } export function PromptModalResizeHandle({ size, measure, onResize, accent, }: { size: { width: number; height: number } | null; measure: () => { width: number; height: number }; onResize: (size: { width: number; height: number }) => void; accent: string; }) { const dragRef = useRef<{ pointerId: number; startX: number; startY: number; width: number; height: number } | null>(null); const finishResize = (event: ReactPointerEvent) => { if (dragRef.current?.pointerId !== event.pointerId) return; if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId); dragRef.current = null; }; const handleKeyDown = (event: ReactKeyboardEvent) => { const step = event.shiftKey ? 40 : 12; const widthDelta = event.key === "ArrowLeft" ? -step : event.key === "ArrowRight" ? step : 0; const heightDelta = event.key === "ArrowUp" ? -step : event.key === "ArrowDown" ? step : 0; if (!widthDelta && !heightDelta) return; event.preventDefault(); event.stopPropagation(); const base = size ?? measure(); onResize(clampExpandedModalSize({ width: base.width + widthDelta, height: base.height + heightDelta })); }; return ( ); } export function promptEditorBounds(expanded: boolean, hasReferences: boolean) { const shelfHeight = hasReferences ? PROMPT_REFERENCE_SHELF_HEIGHT : 0; const min = (expanded ? PROMPT_EDITOR_EXPANDED_MIN_HEIGHT : PROMPT_EDITOR_MIN_HEIGHT) + shelfHeight; const max = (expanded ? PROMPT_EDITOR_EXPANDED_LINE_HEIGHT * PROMPT_EDITOR_EXPANDED_MAX_LINES + PROMPT_EDITOR_EXPANDED_VERTICAL_PADDING : PROMPT_EDITOR_LINE_HEIGHT * PROMPT_EDITOR_MAX_LINES + PROMPT_EDITOR_VERTICAL_PADDING) + shelfHeight; return { min, max }; } export function estimatePromptContentHeight(value: string, expanded: boolean) { if (!value.trim()) return expanded ? PROMPT_EDITOR_EXPANDED_MIN_HEIGHT : PROMPT_EDITOR_MIN_HEIGHT; const charsPerLine = expanded ? 34 : 38; const lineCount = value.split("\n").reduce((total, line) => total + Math.max(1, Math.ceil(Array.from(line).length / charsPerLine)), 0); const lineHeight = expanded ? PROMPT_EDITOR_EXPANDED_LINE_HEIGHT : PROMPT_EDITOR_LINE_HEIGHT; const verticalPadding = expanded ? PROMPT_EDITOR_EXPANDED_VERTICAL_PADDING : PROMPT_EDITOR_VERTICAL_PADDING; return Math.max(expanded ? PROMPT_EDITOR_EXPANDED_MIN_HEIGHT : PROMPT_EDITOR_MIN_HEIGHT, lineCount * lineHeight + verticalPadding); } export function clampPromptHeight(height: number, bounds: { min: number; max: number }) { return Math.min(bounds.max, Math.max(bounds.min, height)); }