Merge remote-tracking branch 'origin/release' into danieljgeiger-mathjax
This commit is contained in:
commit
91fe07d9c5
14
.github/workflows/publish-docker.yml
vendored
14
.github/workflows/publish-docker.yml
vendored
@ -12,14 +12,24 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v4
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
excalidraw/excalidraw
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: excalidraw/excalidraw:latest
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
@ -183,6 +183,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
|
font-family: inherit;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
border: 0;
|
border: 0;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
font-family: inherit;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 0.2fr;
|
grid-template-columns: 1fr 0.2fr;
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
// container in body where the actual tooltip is appended to
|
// container in body where the actual tooltip is appended to
|
||||||
.excalidraw-tooltip {
|
.excalidraw-tooltip {
|
||||||
|
--ui-font: Assistant, system-ui, BlinkMacSystemFont, -apple-system, Segoe UI,
|
||||||
|
Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
font-family: var(--ui-font);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
|
||||||
|
@ -354,6 +354,7 @@
|
|||||||
border-radius: var(--space-factor);
|
border-radius: var(--space-factor);
|
||||||
border: 1px solid var(--button-gray-2);
|
border: 1px solid var(--button-gray-2);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
|
font-family: inherit;
|
||||||
outline: none;
|
outline: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
background-image: var(--dropdown-icon);
|
background-image: var(--dropdown-icon);
|
||||||
@ -413,6 +414,7 @@
|
|||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
font-family: inherit;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--button-hover-bg);
|
background-color: var(--button-hover-bg);
|
||||||
|
@ -155,7 +155,7 @@ export const loadSceneOrLibraryFromBlob = async (
|
|||||||
},
|
},
|
||||||
localAppState,
|
localAppState,
|
||||||
localElements,
|
localElements,
|
||||||
{ repairBindings: true, refreshDimensions: true },
|
{ repairBindings: true, refreshDimensions: false },
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
} else if (isValidLibrary(data)) {
|
} else if (isValidLibrary(data)) {
|
||||||
|
@ -28,7 +28,7 @@ import {
|
|||||||
measureTextElement,
|
measureTextElement,
|
||||||
normalizeText,
|
normalizeText,
|
||||||
wrapTextElement,
|
wrapTextElement,
|
||||||
getMaxContainerWidth,
|
getBoundTextMaxWidth,
|
||||||
getDefaultLineHeight,
|
getDefaultLineHeight,
|
||||||
} from "./textElement";
|
} from "./textElement";
|
||||||
import {
|
import {
|
||||||
@ -333,7 +333,7 @@ export const refreshTextDimensions = (
|
|||||||
}
|
}
|
||||||
const container = getContainerElement(textElement);
|
const container = getContainerElement(textElement);
|
||||||
if (container) {
|
if (container) {
|
||||||
text = wrapTextElement(textElement, getMaxContainerWidth(container), {
|
text = wrapTextElement(textElement, getBoundTextMaxWidth(container), {
|
||||||
text,
|
text,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,10 @@ import {
|
|||||||
getBoundTextElementId,
|
getBoundTextElementId,
|
||||||
getContainerElement,
|
getContainerElement,
|
||||||
handleBindTextResize,
|
handleBindTextResize,
|
||||||
getMaxContainerWidth,
|
getBoundTextMaxWidth,
|
||||||
getApproxMinLineHeight,
|
getApproxMinLineHeight,
|
||||||
measureTextElement,
|
measureTextElement,
|
||||||
getMaxContainerHeight,
|
getBoundTextMaxHeight,
|
||||||
} from "./textElement";
|
} from "./textElement";
|
||||||
|
|
||||||
export const normalizeAngle = (angle: number): number => {
|
export const normalizeAngle = (angle: number): number => {
|
||||||
@ -204,7 +204,7 @@ const measureFontSizeFromWidth = (
|
|||||||
if (hasContainer) {
|
if (hasContainer) {
|
||||||
const container = getContainerElement(element);
|
const container = getContainerElement(element);
|
||||||
if (container) {
|
if (container) {
|
||||||
width = getMaxContainerWidth(container);
|
width = getBoundTextMaxWidth(container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const nextFontSize = element.fontSize * (nextWidth / width);
|
const nextFontSize = element.fontSize * (nextWidth / width);
|
||||||
@ -431,8 +431,8 @@ export const resizeSingleElement = (
|
|||||||
|
|
||||||
const nextFont = measureFontSizeFromWidth(
|
const nextFont = measureFontSizeFromWidth(
|
||||||
boundTextElement,
|
boundTextElement,
|
||||||
getMaxContainerWidth(updatedElement),
|
getBoundTextMaxWidth(updatedElement),
|
||||||
getMaxContainerHeight(updatedElement),
|
getBoundTextMaxHeight(updatedElement, boundTextElement),
|
||||||
);
|
);
|
||||||
if (nextFont === null) {
|
if (nextFont === null) {
|
||||||
return;
|
return;
|
||||||
@ -714,10 +714,10 @@ const resizeMultipleElements = (
|
|||||||
const metrics = measureFontSizeFromWidth(
|
const metrics = measureFontSizeFromWidth(
|
||||||
boundTextElement ?? (element.orig as ExcalidrawTextElement),
|
boundTextElement ?? (element.orig as ExcalidrawTextElement),
|
||||||
boundTextElement
|
boundTextElement
|
||||||
? getMaxContainerWidth(updatedElement)
|
? getBoundTextMaxWidth(updatedElement)
|
||||||
: updatedElement.width,
|
: updatedElement.width,
|
||||||
boundTextElement
|
boundTextElement
|
||||||
? getMaxContainerHeight(updatedElement)
|
? getBoundTextMaxHeight(updatedElement, boundTextElement)
|
||||||
: updatedElement.height,
|
: updatedElement.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3,15 +3,15 @@ import { API } from "../tests/helpers/api";
|
|||||||
import {
|
import {
|
||||||
computeContainerDimensionForBoundText,
|
computeContainerDimensionForBoundText,
|
||||||
getContainerCoords,
|
getContainerCoords,
|
||||||
getMaxContainerWidth,
|
getBoundTextMaxWidth,
|
||||||
getMaxContainerHeight,
|
getBoundTextMaxHeight,
|
||||||
wrapText,
|
wrapText,
|
||||||
detectLineHeight,
|
detectLineHeight,
|
||||||
getLineHeightInPx,
|
getLineHeightInPx,
|
||||||
getDefaultLineHeight,
|
getDefaultLineHeight,
|
||||||
parseTokens,
|
parseTokens,
|
||||||
} from "./textElement";
|
} from "./textElement";
|
||||||
import { FontString } from "./types";
|
import { ExcalidrawTextElementWithContainer, FontString } from "./types";
|
||||||
|
|
||||||
describe("Test wrapText", () => {
|
describe("Test wrapText", () => {
|
||||||
const font = "20px Cascadia, width: Segoe UI Emoji" as FontString;
|
const font = "20px Cascadia, width: Segoe UI Emoji" as FontString;
|
||||||
@ -311,7 +311,7 @@ describe("Test measureText", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test getMaxContainerWidth", () => {
|
describe("Test getBoundTextMaxWidth", () => {
|
||||||
const params = {
|
const params = {
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 194,
|
height: 194,
|
||||||
@ -319,39 +319,76 @@ describe("Test measureText", () => {
|
|||||||
|
|
||||||
it("should return max width when container is rectangle", () => {
|
it("should return max width when container is rectangle", () => {
|
||||||
const container = API.createElement({ type: "rectangle", ...params });
|
const container = API.createElement({ type: "rectangle", ...params });
|
||||||
expect(getMaxContainerWidth(container)).toBe(168);
|
expect(getBoundTextMaxWidth(container)).toBe(168);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return max width when container is ellipse", () => {
|
it("should return max width when container is ellipse", () => {
|
||||||
const container = API.createElement({ type: "ellipse", ...params });
|
const container = API.createElement({ type: "ellipse", ...params });
|
||||||
expect(getMaxContainerWidth(container)).toBe(116);
|
expect(getBoundTextMaxWidth(container)).toBe(116);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return max width when container is diamond", () => {
|
it("should return max width when container is diamond", () => {
|
||||||
const container = API.createElement({ type: "diamond", ...params });
|
const container = API.createElement({ type: "diamond", ...params });
|
||||||
expect(getMaxContainerWidth(container)).toBe(79);
|
expect(getBoundTextMaxWidth(container)).toBe(79);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test getMaxContainerHeight", () => {
|
describe("Test getBoundTextMaxHeight", () => {
|
||||||
const params = {
|
const params = {
|
||||||
width: 178,
|
width: 178,
|
||||||
height: 194,
|
height: 194,
|
||||||
|
id: '"container-id',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const boundTextElement = API.createElement({
|
||||||
|
type: "text",
|
||||||
|
id: "text-id",
|
||||||
|
x: 560.51171875,
|
||||||
|
y: 202.033203125,
|
||||||
|
width: 154,
|
||||||
|
height: 175,
|
||||||
|
fontSize: 20,
|
||||||
|
fontFamily: 1,
|
||||||
|
text: "Excalidraw is a\nvirtual \nopensource \nwhiteboard for \nsketching \nhand-drawn like\ndiagrams",
|
||||||
|
textAlign: "center",
|
||||||
|
verticalAlign: "middle",
|
||||||
|
containerId: params.id,
|
||||||
|
}) as ExcalidrawTextElementWithContainer;
|
||||||
|
|
||||||
it("should return max height when container is rectangle", () => {
|
it("should return max height when container is rectangle", () => {
|
||||||
const container = API.createElement({ type: "rectangle", ...params });
|
const container = API.createElement({ type: "rectangle", ...params });
|
||||||
expect(getMaxContainerHeight(container)).toBe(184);
|
expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(184);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return max height when container is ellipse", () => {
|
it("should return max height when container is ellipse", () => {
|
||||||
const container = API.createElement({ type: "ellipse", ...params });
|
const container = API.createElement({ type: "ellipse", ...params });
|
||||||
expect(getMaxContainerHeight(container)).toBe(127);
|
expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(127);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return max height when container is diamond", () => {
|
it("should return max height when container is diamond", () => {
|
||||||
const container = API.createElement({ type: "diamond", ...params });
|
const container = API.createElement({ type: "diamond", ...params });
|
||||||
expect(getMaxContainerHeight(container)).toBe(87);
|
expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(87);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return max height when container is arrow", () => {
|
||||||
|
const container = API.createElement({
|
||||||
|
type: "arrow",
|
||||||
|
...params,
|
||||||
|
});
|
||||||
|
expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(194);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return max height when container is arrow and height is less than threshold", () => {
|
||||||
|
const container = API.createElement({
|
||||||
|
type: "arrow",
|
||||||
|
...params,
|
||||||
|
height: 70,
|
||||||
|
boundElements: [{ type: "text", id: "text-id" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(
|
||||||
|
boundTextElement.height,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -90,7 +90,7 @@ export const redrawTextBoundingBox = (
|
|||||||
boundTextUpdates.text = textElement.text;
|
boundTextUpdates.text = textElement.text;
|
||||||
|
|
||||||
if (container) {
|
if (container) {
|
||||||
maxWidth = getMaxContainerWidth(container);
|
maxWidth = getBoundTextMaxWidth(container);
|
||||||
boundTextUpdates.text = wrapTextElement(textElement, maxWidth);
|
boundTextUpdates.text = wrapTextElement(textElement, maxWidth);
|
||||||
}
|
}
|
||||||
const metrics = measureTextElement(textElement, {
|
const metrics = measureTextElement(textElement, {
|
||||||
@ -110,16 +110,11 @@ export const redrawTextBoundingBox = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (container) {
|
if (container) {
|
||||||
if (isArrowElement(container)) {
|
|
||||||
const centerX = textElement.x + textElement.width / 2;
|
|
||||||
const centerY = textElement.y + textElement.height / 2;
|
|
||||||
const diffWidth = metrics.width - textElement.width;
|
|
||||||
const diffHeight = metrics.height - textElement.height;
|
|
||||||
boundTextUpdates.x = centerY - (textElement.height + diffHeight) / 2;
|
|
||||||
boundTextUpdates.y = centerX - (textElement.width + diffWidth) / 2;
|
|
||||||
} else {
|
|
||||||
const containerDims = getContainerDims(container);
|
const containerDims = getContainerDims(container);
|
||||||
let maxContainerHeight = getMaxContainerHeight(container);
|
const maxContainerHeight = getBoundTextMaxHeight(
|
||||||
|
container,
|
||||||
|
textElement as ExcalidrawTextElementWithContainer,
|
||||||
|
);
|
||||||
|
|
||||||
let nextHeight = containerDims.height;
|
let nextHeight = containerDims.height;
|
||||||
if (metrics.height > maxContainerHeight) {
|
if (metrics.height > maxContainerHeight) {
|
||||||
@ -128,7 +123,6 @@ export const redrawTextBoundingBox = (
|
|||||||
container.type,
|
container.type,
|
||||||
);
|
);
|
||||||
mutateElement(container, { height: nextHeight });
|
mutateElement(container, { height: nextHeight });
|
||||||
maxContainerHeight = getMaxContainerHeight(container);
|
|
||||||
updateOriginalContainerCache(container.id, nextHeight);
|
updateOriginalContainerCache(container.id, nextHeight);
|
||||||
}
|
}
|
||||||
const updatedTextElement = {
|
const updatedTextElement = {
|
||||||
@ -139,7 +133,6 @@ export const redrawTextBoundingBox = (
|
|||||||
boundTextUpdates.x = x;
|
boundTextUpdates.x = x;
|
||||||
boundTextUpdates.y = y;
|
boundTextUpdates.y = y;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mutateElement(textElement, boundTextUpdates);
|
mutateElement(textElement, boundTextUpdates);
|
||||||
};
|
};
|
||||||
@ -210,8 +203,11 @@ export const handleBindTextResize = (
|
|||||||
let nextHeight = textElement.height;
|
let nextHeight = textElement.height;
|
||||||
let nextWidth = textElement.width;
|
let nextWidth = textElement.width;
|
||||||
const containerDims = getContainerDims(container);
|
const containerDims = getContainerDims(container);
|
||||||
const maxWidth = getMaxContainerWidth(container);
|
const maxWidth = getBoundTextMaxWidth(container);
|
||||||
const maxHeight = getMaxContainerHeight(container);
|
const maxHeight = getBoundTextMaxHeight(
|
||||||
|
container,
|
||||||
|
textElement as ExcalidrawTextElementWithContainer,
|
||||||
|
);
|
||||||
let containerHeight = containerDims.height;
|
let containerHeight = containerDims.height;
|
||||||
let nextBaseLine = textElement.baseline;
|
let nextBaseLine = textElement.baseline;
|
||||||
if (transformHandleType !== "n" && transformHandleType !== "s") {
|
if (transformHandleType !== "n" && transformHandleType !== "s") {
|
||||||
@ -275,8 +271,8 @@ export const computeBoundTextPosition = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const containerCoords = getContainerCoords(container);
|
const containerCoords = getContainerCoords(container);
|
||||||
const maxContainerHeight = getMaxContainerHeight(container);
|
const maxContainerHeight = getBoundTextMaxHeight(container, boundTextElement);
|
||||||
const maxContainerWidth = getMaxContainerWidth(container);
|
const maxContainerWidth = getBoundTextMaxWidth(container);
|
||||||
|
|
||||||
let x;
|
let x;
|
||||||
let y;
|
let y;
|
||||||
@ -909,18 +905,10 @@ export const computeContainerDimensionForBoundText = (
|
|||||||
return dimension + padding;
|
return dimension + padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getMaxContainerWidth = (container: ExcalidrawElement) => {
|
export const getBoundTextMaxWidth = (container: ExcalidrawElement) => {
|
||||||
const width = getContainerDims(container).width;
|
const width = getContainerDims(container).width;
|
||||||
if (isArrowElement(container)) {
|
if (isArrowElement(container)) {
|
||||||
const containerWidth = width - BOUND_TEXT_PADDING * 8 * 2;
|
return width - BOUND_TEXT_PADDING * 8 * 2;
|
||||||
if (containerWidth <= 0) {
|
|
||||||
const boundText = getBoundTextElement(container);
|
|
||||||
if (boundText) {
|
|
||||||
return boundText.width;
|
|
||||||
}
|
|
||||||
return BOUND_TEXT_PADDING * 8 * 2;
|
|
||||||
}
|
|
||||||
return containerWidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container.type === "ellipse") {
|
if (container.type === "ellipse") {
|
||||||
@ -937,16 +925,15 @@ export const getMaxContainerWidth = (container: ExcalidrawElement) => {
|
|||||||
return width - BOUND_TEXT_PADDING * 2;
|
return width - BOUND_TEXT_PADDING * 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getMaxContainerHeight = (container: ExcalidrawElement) => {
|
export const getBoundTextMaxHeight = (
|
||||||
|
container: ExcalidrawElement,
|
||||||
|
boundTextElement: ExcalidrawTextElementWithContainer,
|
||||||
|
) => {
|
||||||
const height = getContainerDims(container).height;
|
const height = getContainerDims(container).height;
|
||||||
if (isArrowElement(container)) {
|
if (isArrowElement(container)) {
|
||||||
const containerHeight = height - BOUND_TEXT_PADDING * 8 * 2;
|
const containerHeight = height - BOUND_TEXT_PADDING * 8 * 2;
|
||||||
if (containerHeight <= 0) {
|
if (containerHeight <= 0) {
|
||||||
const boundText = getBoundTextElement(container);
|
return boundTextElement.height;
|
||||||
if (boundText) {
|
|
||||||
return boundText.height;
|
|
||||||
}
|
|
||||||
return BOUND_TEXT_PADDING * 8 * 2;
|
|
||||||
}
|
}
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,8 @@ import {
|
|||||||
normalizeText,
|
normalizeText,
|
||||||
redrawTextBoundingBox,
|
redrawTextBoundingBox,
|
||||||
wrapText,
|
wrapText,
|
||||||
getMaxContainerHeight,
|
getBoundTextMaxHeight,
|
||||||
getMaxContainerWidth,
|
getBoundTextMaxWidth,
|
||||||
computeContainerDimensionForBoundText,
|
computeContainerDimensionForBoundText,
|
||||||
detectLineHeight,
|
detectLineHeight,
|
||||||
} from "./textElement";
|
} from "./textElement";
|
||||||
@ -174,7 +174,7 @@ export const textWysiwyg = ({
|
|||||||
? wrapText(
|
? wrapText(
|
||||||
updatedTextElement.originalText,
|
updatedTextElement.originalText,
|
||||||
getFontString(updatedTextElement),
|
getFontString(updatedTextElement),
|
||||||
getMaxContainerWidth(container),
|
getBoundTextMaxWidth(container),
|
||||||
)
|
)
|
||||||
: updatedTextElement.originalText,
|
: updatedTextElement.originalText,
|
||||||
getFontString(updatedTextElement),
|
getFontString(updatedTextElement),
|
||||||
@ -189,7 +189,7 @@ export const textWysiwyg = ({
|
|||||||
|
|
||||||
if (container && updatedTextElement.containerId) {
|
if (container && updatedTextElement.containerId) {
|
||||||
textElementHeight = Math.min(
|
textElementHeight = Math.min(
|
||||||
getMaxContainerHeight(container),
|
getBoundTextMaxWidth(container),
|
||||||
textElementHeight,
|
textElementHeight,
|
||||||
);
|
);
|
||||||
if (isArrowElement(container)) {
|
if (isArrowElement(container)) {
|
||||||
@ -221,7 +221,7 @@ export const textWysiwyg = ({
|
|||||||
wrapText(
|
wrapText(
|
||||||
updatedTextElement.originalText,
|
updatedTextElement.originalText,
|
||||||
font,
|
font,
|
||||||
getMaxContainerWidth(container),
|
getBoundTextMaxWidth(container),
|
||||||
).split("\n").length;
|
).split("\n").length;
|
||||||
textElementHeight = Math.max(
|
textElementHeight = Math.max(
|
||||||
textElementHeight,
|
textElementHeight,
|
||||||
@ -245,8 +245,11 @@ export const textWysiwyg = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maxWidth = getMaxContainerWidth(container);
|
maxWidth = getBoundTextMaxWidth(container);
|
||||||
maxHeight = getMaxContainerHeight(container);
|
maxHeight = getBoundTextMaxHeight(
|
||||||
|
container,
|
||||||
|
updatedTextElement as ExcalidrawTextElementWithContainer,
|
||||||
|
);
|
||||||
|
|
||||||
// autogrow container height if text exceeds
|
// autogrow container height if text exceeds
|
||||||
if (!isArrowElement(container) && textElementHeight > maxHeight) {
|
if (!isArrowElement(container) && textElementHeight > maxHeight) {
|
||||||
@ -437,7 +440,7 @@ export const textWysiwyg = ({
|
|||||||
const wrappedText = wrapText(
|
const wrappedText = wrapText(
|
||||||
`${editable.value}${data}`,
|
`${editable.value}${data}`,
|
||||||
font,
|
font,
|
||||||
getMaxContainerWidth(container),
|
getBoundTextMaxWidth(container),
|
||||||
);
|
);
|
||||||
const width = getTextWidth(wrappedText, font);
|
const width = getTextWidth(wrappedText, font);
|
||||||
editable.style.width = `${width}px`;
|
editable.style.width = `${width}px`;
|
||||||
@ -454,7 +457,7 @@ export const textWysiwyg = ({
|
|||||||
const wrappedText = wrapText(
|
const wrappedText = wrapText(
|
||||||
normalizeText(editable.value),
|
normalizeText(editable.value),
|
||||||
font,
|
font,
|
||||||
getMaxContainerWidth(container!),
|
getBoundTextMaxWidth(container!),
|
||||||
);
|
);
|
||||||
const { width, height } = measureText(
|
const { width, height } = measureText(
|
||||||
wrappedText,
|
wrappedText,
|
||||||
|
@ -263,7 +263,7 @@ export const loadScene = async (
|
|||||||
await importFromBackend(id, privateKey),
|
await importFromBackend(id, privateKey),
|
||||||
localDataState?.appState,
|
localDataState?.appState,
|
||||||
localDataState?.elements,
|
localDataState?.elements,
|
||||||
{ repairBindings: true, refreshDimensions: true },
|
{ repairBindings: true, refreshDimensions: false },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
data = restore(localDataState || null, null, null, {
|
data = restore(localDataState || null, null, null, {
|
||||||
|
@ -4,9 +4,9 @@ import { FONT_FAMILY, SVG_NS } from "../../../../constants";
|
|||||||
import { getFontString, getFontFamilyString, isRTL } from "../../../../utils";
|
import { getFontString, getFontFamilyString, isRTL } from "../../../../utils";
|
||||||
import {
|
import {
|
||||||
getBoundTextElement,
|
getBoundTextElement,
|
||||||
|
getBoundTextMaxWidth,
|
||||||
getContainerElement,
|
getContainerElement,
|
||||||
getDefaultLineHeight,
|
getDefaultLineHeight,
|
||||||
getMaxContainerWidth,
|
|
||||||
getTextWidth,
|
getTextWidth,
|
||||||
measureText,
|
measureText,
|
||||||
wrapText,
|
wrapText,
|
||||||
@ -1018,7 +1018,7 @@ const renderMathElement = function (element, context, renderCb) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const container = getContainerElement(_element);
|
const container = getContainerElement(_element);
|
||||||
const parentWidth = container ? getMaxContainerWidth(container) : undefined;
|
const parentWidth = container ? getBoundTextMaxWidth(container) : undefined;
|
||||||
|
|
||||||
const offsetX =
|
const offsetX =
|
||||||
(_element.width - (container ? parentWidth! : _element.width)) *
|
(_element.width - (container ? parentWidth! : _element.width)) *
|
||||||
@ -1095,7 +1095,7 @@ const renderSvgMathElement = function (svgRoot, root, element, opt) {
|
|||||||
tempSvg.appendChild(groupNode);
|
tempSvg.appendChild(groupNode);
|
||||||
|
|
||||||
const container = getContainerElement(_element);
|
const container = getContainerElement(_element);
|
||||||
const parentWidth = container ? getMaxContainerWidth(container) : undefined;
|
const parentWidth = container ? getBoundTextMaxWidth(container) : undefined;
|
||||||
|
|
||||||
const offsetX =
|
const offsetX =
|
||||||
(_element.width - (container ? parentWidth! : _element.width)) *
|
(_element.width - (container ? parentWidth! : _element.width)) *
|
||||||
|
@ -45,8 +45,8 @@ import {
|
|||||||
getContainerCoords,
|
getContainerCoords,
|
||||||
getContainerElement,
|
getContainerElement,
|
||||||
getLineHeightInPx,
|
getLineHeightInPx,
|
||||||
getMaxContainerHeight,
|
getBoundTextMaxHeight,
|
||||||
getMaxContainerWidth,
|
getBoundTextMaxWidth,
|
||||||
} from "../element/textElement";
|
} from "../element/textElement";
|
||||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||||
|
|
||||||
@ -875,14 +875,17 @@ const drawElementFromCanvas = (
|
|||||||
"true" &&
|
"true" &&
|
||||||
hasBoundTextElement(element)
|
hasBoundTextElement(element)
|
||||||
) {
|
) {
|
||||||
|
const textElement = getBoundTextElement(
|
||||||
|
element,
|
||||||
|
) as ExcalidrawTextElementWithContainer;
|
||||||
const coords = getContainerCoords(element);
|
const coords = getContainerCoords(element);
|
||||||
context.strokeStyle = "#c92a2a";
|
context.strokeStyle = "#c92a2a";
|
||||||
context.lineWidth = 3;
|
context.lineWidth = 3;
|
||||||
context.strokeRect(
|
context.strokeRect(
|
||||||
(coords.x + renderConfig.scrollX) * window.devicePixelRatio,
|
(coords.x + renderConfig.scrollX) * window.devicePixelRatio,
|
||||||
(coords.y + renderConfig.scrollY) * window.devicePixelRatio,
|
(coords.y + renderConfig.scrollY) * window.devicePixelRatio,
|
||||||
getMaxContainerWidth(element) * window.devicePixelRatio,
|
getBoundTextMaxWidth(element) * window.devicePixelRatio,
|
||||||
getMaxContainerHeight(element) * window.devicePixelRatio,
|
getBoundTextMaxHeight(element, textElement) * window.devicePixelRatio,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { isTextElement, refreshTextDimensions } from "../element";
|
import { isTextElement, refreshTextDimensions } from "../element";
|
||||||
import { newElementWith } from "../element/mutateElement";
|
import { newElementWith } from "../element/mutateElement";
|
||||||
|
import { isBoundToContainer } from "../element/typeChecks";
|
||||||
import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
|
import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
|
||||||
import { invalidateShapeForElement } from "../renderer/renderElement";
|
import { invalidateShapeForElement } from "../renderer/renderElement";
|
||||||
import { getFontString } from "../utils";
|
import { getFontString } from "../utils";
|
||||||
@ -52,7 +53,7 @@ export class Fonts {
|
|||||||
let didUpdate = false;
|
let didUpdate = false;
|
||||||
|
|
||||||
this.scene.mapElements((element) => {
|
this.scene.mapElements((element) => {
|
||||||
if (isTextElement(element)) {
|
if (isTextElement(element) && !isBoundToContainer(element)) {
|
||||||
invalidateShapeForElement(element);
|
invalidateShapeForElement(element);
|
||||||
didUpdate = true;
|
didUpdate = true;
|
||||||
return newElementWith(element, {
|
return newElementWith(element, {
|
||||||
|
@ -20,7 +20,7 @@ import { resize, rotate } from "./utils";
|
|||||||
import {
|
import {
|
||||||
getBoundTextElementPosition,
|
getBoundTextElementPosition,
|
||||||
wrapText,
|
wrapText,
|
||||||
getMaxContainerWidth,
|
getBoundTextMaxWidth,
|
||||||
} from "../element/textElement";
|
} from "../element/textElement";
|
||||||
import * as textElementUtils from "../element/textElement";
|
import * as textElementUtils from "../element/textElement";
|
||||||
import { ROUNDNESS, VERTICAL_ALIGN } from "../constants";
|
import { ROUNDNESS, VERTICAL_ALIGN } from "../constants";
|
||||||
@ -729,7 +729,7 @@ describe("Test Linear Elements", () => {
|
|||||||
type: "text",
|
type: "text",
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
text: wrapText(text, font, getMaxContainerWidth(container)),
|
text: wrapText(text, font, getBoundTextMaxWidth(container)),
|
||||||
containerId: container.id,
|
containerId: container.id,
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 20,
|
height: 20,
|
||||||
@ -1149,7 +1149,7 @@ describe("Test Linear Elements", () => {
|
|||||||
expect(rect.x).toBe(400);
|
expect(rect.x).toBe(400);
|
||||||
expect(rect.y).toBe(0);
|
expect(rect.y).toBe(0);
|
||||||
expect(
|
expect(
|
||||||
wrapText(textElement.originalText, font, getMaxContainerWidth(arrow)),
|
wrapText(textElement.originalText, font, getBoundTextMaxWidth(arrow)),
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"Online whiteboard collaboration
|
"Online whiteboard collaboration
|
||||||
made easy"
|
made easy"
|
||||||
@ -1172,7 +1172,7 @@ describe("Test Linear Elements", () => {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
wrapText(textElement.originalText, font, getMaxContainerWidth(arrow)),
|
wrapText(textElement.originalText, font, getBoundTextMaxWidth(arrow)),
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
"Online whiteboard
|
"Online whiteboard
|
||||||
collaboration made
|
collaboration made
|
||||||
|
Loading…
x
Reference in New Issue
Block a user