diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index cfe6d7f6..0607c780 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -2,7 +2,6 @@ import { CODES, KEYS } from "../keys"; import { isWritableElement, getFontString, - viewportCoordsToSceneCoords, getFontFamilyString, } from "../utils"; import Scene from "../scene/Scene"; @@ -37,16 +36,20 @@ const getTransform = ( angle: number, appState: AppState, maxWidth: number, + maxHeight: number, ) => { const { zoom, offsetTop, offsetLeft } = appState; const degree = (180 * angle) / Math.PI; // offsets must be multiplied by 2 to account for the division by 2 of // the whole expression afterwards let translateX = ((width - offsetLeft * 2) * (zoom.value - 1)) / 2; - const translateY = ((height - offsetTop * 2) * (zoom.value - 1)) / 2; + let translateY = ((height - offsetTop * 2) * (zoom.value - 1)) / 2; if (width > maxWidth && zoom.value !== 1) { translateX = (maxWidth / 2) * (zoom.value - 1); } + if (height > maxHeight && zoom.value !== 1) { + translateY = ((maxHeight - offsetTop * 2) * (zoom.value - 1)) / 2; + } return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`; }; @@ -106,12 +109,13 @@ export const textWysiwyg = ({ let maxHeight = updatedElement.height; let width = updatedElement.width; - let height = updatedElement.height; + const height = Math.max(editable.scrollHeight, updatedElement.height); if (container && updatedElement.containerId) { const propertiesUpdated = textPropertiesUpdated( updatedElement, editable, ); + if (propertiesUpdated) { const currentContainer = Scene.getScene(updatedElement)?.getElement( updatedElement.containerId, @@ -133,15 +137,14 @@ export const textWysiwyg = ({ maxWidth = container.width - PADDING * 2; maxHeight = container.height - PADDING * 2; width = maxWidth; - height = Math.min(height, maxHeight); // The coordinates of text box set a distance of // 30px to preserve padding coordX = container.x + PADDING; // autogrow container height if text exceeds - if (editable.clientHeight > maxHeight) { + if (editable.scrollHeight > maxHeight) { const diff = Math.min( - editable.clientHeight - maxHeight, + editable.scrollHeight - maxHeight, approxLineHeight, ); mutateElement(container, { height: container.height + diff }); @@ -150,10 +153,10 @@ export const textWysiwyg = ({ // autoshrink container height until original container height // is reached when text is removed container.height > originalContainerHeight && - editable.clientHeight < maxHeight + editable.scrollHeight < maxHeight ) { const diff = Math.min( - maxHeight - editable.clientHeight, + maxHeight - editable.scrollHeight, approxLineHeight, ); mutateElement(container, { height: container.height - diff }); @@ -161,18 +164,17 @@ export const textWysiwyg = ({ // Start pushing text upward until a diff of 30px (padding) // is reached else { - const lines = editable.clientHeight / approxLineHeight; + const lines = editable.scrollHeight / approxLineHeight; // For some reason the scrollHeight gets set to twice the lineHeight // when you start typing for first time and thus line count is 2 // hence this check if (lines > 2 || propertiesUpdated) { // vertically center align the text coordY = - container.y + container.height / 2 - editable.clientHeight / 2; + container.y + container.height / 2 - editable.scrollHeight / 2; } } } - const [viewportX, viewportY] = getViewportCoords(coordX, coordY); const { textAlign, angle } = updatedElement; @@ -192,19 +194,35 @@ export const textWysiwyg = ({ ).marginRight.slice(0, -2), ); } + // Make sure text editor height doesn't go beyond viewport const editorMaxHeight = - (appState.offsetTop + appState.height - viewportY) / + (appState.height - + viewportY - + // There is a ~14px difference which keeps on increasing + // with every zoom step when offset present hence I am subtracting it here + // However this is not the best fix and breaks in + // few scenarios + (appState.offsetTop + ? ((appState.zoom.value * 100 - 100) / 10) * 14 + : 0)) / appState.zoom.value; Object.assign(editable.style, { font: getFontString(updatedElement), // must be defined *after* font ¯\_(ツ)_/¯ lineHeight: `${lineHeight}px`, width: `${width}px`, - height: `${Math.max(editable.clientHeight, updatedElement.height)}px`, + height: `${height}px`, left: `${viewportX}px`, top: `${viewportY}px`, - transform: getTransform(width, height, angle, appState, maxWidth), + transform: getTransform( + width, + height, + angle, + appState, + maxWidth, + editorMaxHeight, + ), textAlign, color: updatedElement.strokeColor, opacity: updatedElement.opacity / 100, @@ -416,20 +434,16 @@ export const textWysiwyg = ({ getFontString(updateElement), container.width, ); - const { x, y } = viewportCoordsToSceneCoords( - { - clientX: Number(editable.style.left.slice(0, -2)), - clientY: Number(editable.style.top.slice(0, -2)), - }, - appState, - ); if (isTextElement(updateElement) && updateElement.containerId) { + const editorHeight = Number(editable.style.height.slice(0, -2)); if (editable.value) { mutateElement(updateElement, { - y: y + appState.offsetTop, - height: Number(editable.style.height.slice(0, -2)), + // vertically center align + y: container.y + container.height / 2 - editorHeight / 2, + height: editorHeight, width: Number(editable.style.width.slice(0, -2)), - x: x + appState.offsetLeft, + // preserve padding + x: container.x + PADDING, }); const boundTextElementId = getBoundTextElementId(container); if (!boundTextElementId || boundTextElementId !== element.id) {