Skip to content

Commit

Permalink
feat: wrap long text when pasting (excalidraw#8026)
Browse files Browse the repository at this point in the history
Co-authored-by: dwelle <[email protected]>
  • Loading branch information
ryan-di and dwelle authored May 21, 2024
1 parent eddbe55 commit c540bd6
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 11 deletions.
43 changes: 34 additions & 9 deletions packages/excalidraw/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import {
isIOS,
supportsResizeObserver,
DEFAULT_COLLISION_THRESHOLD,
DEFAULT_TEXT_ALIGN,
} from "../constants";
import type { ExportedElements } from "../data";
import { exportCanvas, loadFromBlob } from "../data";
Expand Down Expand Up @@ -331,6 +332,8 @@ import {
getLineHeightInPx,
isMeasureTextSupported,
isValidTextContainer,
measureText,
wrapText,
} from "../element/textElement";
import {
showHyperlinkTooltip,
Expand Down Expand Up @@ -430,6 +433,7 @@ import {
} from "./hyperlink/helpers";
import { getShortcutFromShortcutName } from "../actions/shortcuts";
import { actionTextAutoResize } from "../actions/actionTextAutoResize";
import { getVisibleSceneBounds } from "../element/bounds";

const AppContext = React.createContext<AppClassProperties>(null!);
const AppPropsContext = React.createContext<AppProps>(null!);
Expand Down Expand Up @@ -2565,7 +2569,7 @@ class App extends React.Component<AppProps, AppState> {
addEventListener(document, EVENT.KEYUP, this.onKeyUp, { passive: true }),
addEventListener(
document,
EVENT.MOUSE_MOVE,
EVENT.POINTER_MOVE,
this.updateCurrentCursorPosition,
),
// rerender text elements on font load to fix #637 && #1553
Expand Down Expand Up @@ -3341,32 +3345,53 @@ class App extends React.Component<AppProps, AppState> {
text,
fontSize: this.state.currentItemFontSize,
fontFamily: this.state.currentItemFontFamily,
textAlign: this.state.currentItemTextAlign,
textAlign: DEFAULT_TEXT_ALIGN,
verticalAlign: DEFAULT_VERTICAL_ALIGN,
locked: false,
};

const fontString = getFontString({
fontSize: textElementProps.fontSize,
fontFamily: textElementProps.fontFamily,
});
const lineHeight = getDefaultLineHeight(textElementProps.fontFamily);
const [x1, , x2] = getVisibleSceneBounds(this.state);
// long texts should not go beyond 800 pixels in width nor should it go below 200 px
const maxTextWidth = Math.max(Math.min((x2 - x1) * 0.5, 800), 200);
const LINE_GAP = 10;
let currentY = y;

const lines = isPlainPaste ? [text] : text.split("\n");
const textElements = lines.reduce(
(acc: ExcalidrawTextElement[], line, idx) => {
const text = line.trim();

const lineHeight = getDefaultLineHeight(textElementProps.fontFamily);
if (text.length) {
const originalText = line.trim();
if (originalText.length) {
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
x,
y: currentY,
});

let metrics = measureText(originalText, fontString, lineHeight);
const isTextWrapped = metrics.width > maxTextWidth;

const text = isTextWrapped
? wrapText(originalText, fontString, maxTextWidth)
: originalText;

metrics = isTextWrapped
? measureText(text, fontString, lineHeight)
: metrics;

const startX = x - metrics.width / 2;
const startY = currentY - metrics.height / 2;

const element = newTextElement({
...textElementProps,
x,
y: currentY,
x: startX,
y: startY,
text,
originalText,
lineHeight,
autoResize: !isTextWrapped,
frameId: topLayerFrame ? topLayerFrame.id : null,
});
acc.push(element);
Expand Down
6 changes: 4 additions & 2 deletions packages/excalidraw/element/newElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,15 @@ const getTextElementPositionOffsets = (
export const newTextElement = (
opts: {
text: string;
originalText?: string;
fontSize?: number;
fontFamily?: FontFamilyValues;
textAlign?: TextAlign;
verticalAlign?: VerticalAlign;
containerId?: ExcalidrawTextContainer["id"] | null;
lineHeight?: ExcalidrawTextElement["lineHeight"];
strokeWidth?: ExcalidrawTextElement["strokeWidth"];
autoResize?: ExcalidrawTextElement["autoResize"];
} & ElementConstructorOpts,
): NonDeleted<ExcalidrawTextElement> => {
const fontFamily = opts.fontFamily || DEFAULT_FONT_FAMILY;
Expand Down Expand Up @@ -252,8 +254,8 @@ export const newTextElement = (
width: metrics.width,
height: metrics.height,
containerId: opts.containerId || null,
originalText: text,
autoResize: true,
originalText: opts.originalText ?? text,
autoResize: opts.autoResize ?? true,
lineHeight,
};

Expand Down

0 comments on commit c540bd6

Please sign in to comment.