feat: support vertical text align for bound containers (#4852)

* feat: support vertical text align for bound containers

* update icons

* use const

* fix lint

* rename to  and show when text editor active

* don't update vertical align if not center

* fix svgs

* fix y coords when vertical align bottm

Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Aakansha Doshi 2022-03-02 20:06:07 +05:30 committed by GitHub
parent c5a7723185
commit 8e26d5b500
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 222 additions and 66 deletions

View file

@ -23,7 +23,7 @@ import { adjustXYWithRotation } from "../math";
import { getResizedElementAbsoluteCoords } from "./bounds";
import { getContainerElement, measureText, wrapText } from "./textElement";
import { isBoundToContainer } from "./typeChecks";
import { BOUND_TEXT_PADDING } from "../constants";
import { BOUND_TEXT_PADDING, VERTICAL_ALIGN } from "../constants";
type ElementConstructorOpts = MarkOptional<
Omit<ExcalidrawGenericElement, "id" | "type" | "isDeleted" | "updated">,
@ -175,7 +175,7 @@ const getAdjustedDimensions = (
let y: number;
if (
textAlign === "center" &&
verticalAlign === "middle" &&
verticalAlign === VERTICAL_ALIGN.MIDDLE &&
!element.containerId
) {
const prevMetrics = measureText(

View file

@ -8,7 +8,7 @@ import {
NonDeletedExcalidrawElement,
} from "./types";
import { mutateElement } from "./mutateElement";
import { BOUND_TEXT_PADDING } from "../constants";
import { BOUND_TEXT_PADDING, VERTICAL_ALIGN } from "../constants";
import { MaybeTransformHandleType } from "./transformHandles";
import Scene from "../scene/Scene";
import { AppState } from "../types";
@ -39,11 +39,19 @@ export const redrawTextBoundingBox = (
let coordY = element.y;
// Resize container and vertically center align the text
if (container) {
coordY = container.y + container.height / 2 - metrics.height / 2;
let nextHeight = container.height;
if (metrics.height > container.height - BOUND_TEXT_PADDING * 2) {
nextHeight = metrics.height + BOUND_TEXT_PADDING * 2;
coordY = container.y + nextHeight / 2 - metrics.height / 2;
if (element.verticalAlign === VERTICAL_ALIGN.TOP) {
coordY = container.y + BOUND_TEXT_PADDING;
} else if (element.verticalAlign === VERTICAL_ALIGN.BOTTOM) {
coordY =
container.y + container.height - metrics.height - BOUND_TEXT_PADDING;
} else {
coordY = container.y + container.height / 2 - metrics.height / 2;
if (metrics.height > container.height - BOUND_TEXT_PADDING * 2) {
nextHeight = metrics.height + BOUND_TEXT_PADDING * 2;
coordY = container.y + nextHeight / 2 - metrics.height / 2;
}
}
mutateElement(container, { height: nextHeight });
}
@ -142,7 +150,14 @@ export const handleBindTextResize = (
});
}
const updatedY = element.y + containerHeight / 2 - nextHeight / 2;
let updatedY;
if (textElement.verticalAlign === VERTICAL_ALIGN.TOP) {
updatedY = element.y + BOUND_TEXT_PADDING;
} else if (textElement.verticalAlign === VERTICAL_ALIGN.BOTTOM) {
updatedY = element.y + element.height - nextHeight - BOUND_TEXT_PADDING;
} else {
updatedY = element.y + element.height / 2 - nextHeight / 2;
}
mutateElement(textElement, {
text,

View file

@ -7,7 +7,7 @@ import {
} from "../utils";
import Scene from "../scene/Scene";
import { isBoundToContainer, isTextElement } from "./typeChecks";
import { CLASSES, BOUND_TEXT_PADDING } from "../constants";
import { CLASSES, BOUND_TEXT_PADDING, VERTICAL_ALIGN } from "../constants";
import {
ExcalidrawElement,
ExcalidrawTextElement,
@ -105,6 +105,8 @@ export const textWysiwyg = ({
const updatedElement = Scene.getScene(element)?.getElement(
id,
) as ExcalidrawTextElement;
const { textAlign, verticalAlign } = updatedElement;
const approxLineHeight = getApproxLineHeight(getFontString(updatedElement));
if (updatedElement && isTextElement(updatedElement)) {
let coordX = updatedElement.x;
@ -140,7 +142,7 @@ export const textWysiwyg = ({
maxHeight = container.height - BOUND_TEXT_PADDING * 2;
width = maxWidth;
// The coordinates of text box set a distance of
// 30px to preserve padding
// 5px to preserve padding
coordX = container.x + BOUND_TEXT_PADDING;
// autogrow container height if text exceeds
if (height > maxHeight) {
@ -160,11 +162,16 @@ export const textWysiwyg = ({
// is reached
else {
// vertically center align the text
coordY = container.y + container.height / 2 - height / 2;
if (verticalAlign === VERTICAL_ALIGN.MIDDLE) {
coordY = container.y + container.height / 2 - height / 2;
}
if (verticalAlign === VERTICAL_ALIGN.BOTTOM) {
coordY =
container.y + container.height - height - BOUND_TEXT_PADDING;
}
}
}
const [viewportX, viewportY] = getViewportCoords(coordX, coordY);
const { textAlign } = updatedElement;
const initialSelectionStart = editable.selectionStart;
const initialSelectionEnd = editable.selectionEnd;
const initialLength = editable.value.length;
@ -212,6 +219,7 @@ export const textWysiwyg = ({
editorMaxHeight,
),
textAlign,
verticalAlign,
color: updatedElement.strokeColor,
opacity: updatedElement.opacity / 100,
filter: "var(--theme-filter)",

View file

@ -1,5 +1,5 @@
import { Point } from "../types";
import { FONT_FAMILY, THEME } from "../constants";
import { FONT_FAMILY, THEME, VERTICAL_ALIGN } from "../constants";
export type ChartType = "bar" | "line";
export type FillStyle = "hachure" | "cross-hatch" | "solid";
@ -12,7 +12,9 @@ export type PointerType = "mouse" | "pen" | "touch";
export type StrokeSharpness = "round" | "sharp";
export type StrokeStyle = "solid" | "dashed" | "dotted";
export type TextAlign = "left" | "center" | "right";
export type VerticalAlign = "top" | "middle";
type VerticalAlignKeys = keyof typeof VERTICAL_ALIGN;
export type VerticalAlign = typeof VERTICAL_ALIGN[VerticalAlignKeys];
type _ExcalidrawElementBase = Readonly<{
id: string;