This commit is contained in:
ct
2025-06-17 20:55:51 +08:00
parent 933e12d7fb
commit bf54d37306
2 changed files with 35 additions and 16 deletions

View File

@@ -292,7 +292,7 @@ const VideoPreview = ({
[onElementUpdate, timelineElements],
);
// Handle transform events (scale, rotate) with snapping - USES NATIVE KONVA ROTATION SNAPPING
// Handle transform events - TRANSFORMER IS SOURCE OF TRUTH
const handleTransform = useCallback(
(elementId) => {
const node = elementRefs.current[elementId];
@@ -307,11 +307,25 @@ const VideoPreview = ({
const scaleY = node.scaleY();
let newWidth, newHeight;
let updates = { rotation };
if (element.type === 'text') {
// For text, allow free scaling
newWidth = node.width() * scaleX;
newHeight = node.height() * scaleY;
// For text: Convert scale to actual fontSize and reset scale to 1
const avgScale = Math.max(Math.abs(scaleX), Math.abs(scaleY));
const newFontSize = Math.round(element.fontSize * avgScale);
// Clamp font size to reasonable limits
const clampedFontSize = Math.max(8, Math.min(120, newFontSize));
updates.fontSize = clampedFontSize;
// Reset scale to 1 since we've applied it to fontSize
node.scaleX(1);
node.scaleY(1);
// Text dimensions are handled by Konva based on content and fontSize
newWidth = node.width();
newHeight = node.height();
} else {
// For images/videos, maintain aspect ratio by using the larger scale
const scale = Math.max(Math.abs(scaleX), Math.abs(scaleY));
@@ -327,6 +341,9 @@ const VideoPreview = ({
// Update offset for center rotation
node.offsetX(newWidth / 2);
node.offsetY(newHeight / 2);
updates.width = newWidth;
updates.height = newHeight;
}
// Calculate position for snapping
@@ -375,16 +392,12 @@ const VideoPreview = ({
});
}
// Update state with the final calculated values
const finalTransform = {
x: topLeftX,
y: topLeftY,
width: newWidth,
height: newHeight,
rotation: rotation,
};
// Add position to updates
updates.x = topLeftX;
updates.y = topLeftY;
onElementUpdate(elementId, finalTransform);
// Update state with all calculated values
onElementUpdate(elementId, updates);
},
[onElementUpdate, dimensions.width, dimensions.height, timelineElements],
);
@@ -471,6 +484,9 @@ const VideoPreview = ({
align="center"
// Let text have natural width and height for multiline support
wrap="word"
// Always scale 1 - size changes go through fontSize
scaleX={1}
scaleY={1}
draggable
dragBoundFunc={createDragBoundFunc(element.id)}
onClick={() => handleElementSelect(element.id)}

View File

@@ -35,11 +35,11 @@ export default function TextSidebar({ isOpen, onClose }) {
const MAX_FONT_SIZE = 120;
const FONT_SIZE_STEP = 2;
// Update state when selected element changes
// Update state when selected element changes - THIS KEEPS SIDEBAR IN SYNC WITH TRANSFORMER
useEffect(() => {
if (selectedTextElement) {
setTextValue(selectedTextElement.text || '');
setFontSize(selectedTextElement.fontSize || 24);
setFontSize(selectedTextElement.fontSize || 24); // Always use current fontSize from element
setIsBold(selectedTextElement.fontWeight === 'bold' || selectedTextElement.fontWeight === 700 || true);
setIsItalic(selectedTextElement.fontStyle === 'italic' || false);
setFontFamily(selectedTextElement.fontFamily || 'Montserrat');
@@ -59,7 +59,7 @@ export default function TextSidebar({ isOpen, onClose }) {
}
};
// Handle font size changes
// Handle font size changes - CLAMP AND UPDATE
const handleFontSizeChange = (newSize) => {
const clampedSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, newSize));
setFontSize(clampedSize);
@@ -196,6 +196,9 @@ export default function TextSidebar({ isOpen, onClose }) {
<div className="mt-1 text-center text-xs text-gray-500">
Size range: {MIN_FONT_SIZE}px - {MAX_FONT_SIZE}px
</div>
{/* Note about transformer resize */}
<div className="mt-1 text-center text-xs text-blue-600">💡 You can also resize by dragging the corners</div>
</div>
{/* Font Style Controls */}