mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-04-14 16:40:58 -04:00
Compare commits
10 commits
14272fa18e
...
d7169302d8
Author | SHA1 | Date | |
---|---|---|---|
|
d7169302d8 | ||
|
01304aac49 | ||
|
0337942c0b | ||
|
b854f659fe | ||
|
b6bca21662 | ||
|
0f9c130ea8 | ||
|
381817053c | ||
|
bfa2dd4663 | ||
|
64c540dceb | ||
|
31e3bd69f2 |
9 changed files with 202 additions and 34 deletions
36
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
name: "🐛 Bug report"
|
||||
description: Report a reproducible bug or regression
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for reporting an issue :pray:
|
||||
|
||||
This issue tracker is for reporting reproducible bugs or regression's found in Excalidraw or Excalidraw+
|
||||
If you have a question about how to achieve something and are struggling, please post a question
|
||||
inside of excalidraw's [Discussions tab](https://github.com/excalidraw/excalidraw/discussions)
|
||||
|
||||
Before submitting a new bug/issue, please check the links below to see if there is a solution or question posted there already:
|
||||
- excalidraw's [Discussions tab](https://github.com/excalidraw/excalidraw/discussions)
|
||||
- excalidraw's [Open Issues](https://github.com/excalidraw/excalidraw/discussions/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc)
|
||||
- excalidraw's [Closed Issues](https://github.com/excalidraw/excalidraw/discussions/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed)
|
||||
|
||||
The more information you fill in, the better the community can help you.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: Provide a clear and concise description of the challenge you are running into.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: platform
|
||||
attributes:
|
||||
label: Platform
|
||||
description: |
|
||||
Please let us know which Operting System, Browser and Browser version you were using when the issue occurred.
|
||||
placeholder: |
|
||||
- OS + version: e.g. MacOS Big Sur, Windows 11, Linux, iOS 14, Android
|
||||
- Browser + version: e.g. Chrome 104, Safari 15, Firefox 102
|
||||
validations:
|
||||
required: true
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Feature Requests & Questions
|
||||
url: https://github.com/excalidraw/excalidraw/discussions
|
||||
about: Please ask and answer questions here.
|
|
@ -112,6 +112,7 @@ export const YOUTUBE_STATES = {
|
|||
export const ENV = {
|
||||
TEST: "test",
|
||||
DEVELOPMENT: "development",
|
||||
PRODUCTION: "production",
|
||||
};
|
||||
|
||||
export const CLASSES = {
|
||||
|
|
|
@ -739,6 +739,8 @@ export const isTestEnv = () => import.meta.env.MODE === ENV.TEST;
|
|||
|
||||
export const isDevEnv = () => import.meta.env.MODE === ENV.DEVELOPMENT;
|
||||
|
||||
export const isProdEnv = () => import.meta.env.MODE === ENV.PRODUCTION;
|
||||
|
||||
export const isServerEnv = () =>
|
||||
typeof process !== "undefined" && !!process?.env?.NODE_ENV;
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import {
|
|||
TEXT_ALIGN,
|
||||
VERTICAL_ALIGN,
|
||||
getFontString,
|
||||
isProdEnv,
|
||||
invariant,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import type { AppState } from "@excalidraw/excalidraw/types";
|
||||
|
@ -26,6 +28,8 @@ import {
|
|||
isTextElement,
|
||||
} from "./typeChecks";
|
||||
|
||||
import type { Radians } from "../../math/src";
|
||||
|
||||
import type { MaybeTransformHandleType } from "./transformHandles";
|
||||
import type {
|
||||
ElementsMap,
|
||||
|
@ -44,13 +48,25 @@ export const redrawTextBoundingBox = (
|
|||
informMutation = true,
|
||||
) => {
|
||||
let maxWidth = undefined;
|
||||
|
||||
if (!isProdEnv()) {
|
||||
invariant(
|
||||
!container || !isArrowElement(container) || textElement.angle === 0,
|
||||
"text element angle must be 0 if bound to arrow container",
|
||||
);
|
||||
}
|
||||
|
||||
const boundTextUpdates = {
|
||||
x: textElement.x,
|
||||
y: textElement.y,
|
||||
text: textElement.text,
|
||||
width: textElement.width,
|
||||
height: textElement.height,
|
||||
angle: container?.angle ?? textElement.angle,
|
||||
angle: (container
|
||||
? isArrowElement(container)
|
||||
? 0
|
||||
: container.angle
|
||||
: textElement.angle) as Radians,
|
||||
};
|
||||
|
||||
boundTextUpdates.text = textElement.text;
|
||||
|
@ -335,7 +351,10 @@ export const getTextElementAngle = (
|
|||
textElement: ExcalidrawTextElement,
|
||||
container: ExcalidrawTextContainer | null,
|
||||
) => {
|
||||
if (!container || isArrowElement(container)) {
|
||||
if (isArrowElement(container)) {
|
||||
return 0;
|
||||
}
|
||||
if (!container) {
|
||||
return textElement.angle;
|
||||
}
|
||||
return container.angle;
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
|
||||
import {
|
||||
hasBoundTextElement,
|
||||
isArrowElement,
|
||||
isTextBindableContainer,
|
||||
isTextElement,
|
||||
isUsingAdaptiveRadius,
|
||||
|
@ -46,6 +47,8 @@ import { CaptureUpdateAction } from "../store";
|
|||
|
||||
import { register } from "./register";
|
||||
|
||||
import type { Radians } from "../../math/src";
|
||||
|
||||
import type { AppState } from "../types";
|
||||
|
||||
export const actionUnbindText = register({
|
||||
|
@ -155,6 +158,7 @@ export const actionBindText = register({
|
|||
verticalAlign: VERTICAL_ALIGN.MIDDLE,
|
||||
textAlign: TEXT_ALIGN.CENTER,
|
||||
autoResize: true,
|
||||
angle: (isArrowElement(container) ? 0 : container?.angle ?? 0) as Radians,
|
||||
});
|
||||
mutateElement(container, {
|
||||
boundElements: (container.boundElements || []).concat({
|
||||
|
|
|
@ -5352,37 +5352,37 @@ class App extends React.Component<AppProps, AppState> {
|
|||
y: sceneY,
|
||||
});
|
||||
|
||||
const element = existingTextElement
|
||||
? existingTextElement
|
||||
: newTextElement({
|
||||
x: parentCenterPosition
|
||||
? parentCenterPosition.elementCenterX
|
||||
: sceneX,
|
||||
y: parentCenterPosition
|
||||
? parentCenterPosition.elementCenterY
|
||||
: sceneY,
|
||||
strokeColor: this.state.currentItemStrokeColor,
|
||||
backgroundColor: this.state.currentItemBackgroundColor,
|
||||
fillStyle: this.state.currentItemFillStyle,
|
||||
strokeWidth: this.state.currentItemStrokeWidth,
|
||||
strokeStyle: this.state.currentItemStrokeStyle,
|
||||
roughness: this.state.currentItemRoughness,
|
||||
opacity: this.state.currentItemOpacity,
|
||||
text: "",
|
||||
fontSize,
|
||||
fontFamily,
|
||||
textAlign: parentCenterPosition
|
||||
? "center"
|
||||
: this.state.currentItemTextAlign,
|
||||
verticalAlign: parentCenterPosition
|
||||
? VERTICAL_ALIGN.MIDDLE
|
||||
: DEFAULT_VERTICAL_ALIGN,
|
||||
containerId: shouldBindToContainer ? container?.id : undefined,
|
||||
groupIds: container?.groupIds ?? [],
|
||||
lineHeight,
|
||||
angle: container?.angle ?? (0 as Radians),
|
||||
frameId: topLayerFrame ? topLayerFrame.id : null,
|
||||
});
|
||||
const element =
|
||||
existingTextElement ||
|
||||
newTextElement({
|
||||
x: parentCenterPosition ? parentCenterPosition.elementCenterX : sceneX,
|
||||
y: parentCenterPosition ? parentCenterPosition.elementCenterY : sceneY,
|
||||
strokeColor: this.state.currentItemStrokeColor,
|
||||
backgroundColor: this.state.currentItemBackgroundColor,
|
||||
fillStyle: this.state.currentItemFillStyle,
|
||||
strokeWidth: this.state.currentItemStrokeWidth,
|
||||
strokeStyle: this.state.currentItemStrokeStyle,
|
||||
roughness: this.state.currentItemRoughness,
|
||||
opacity: this.state.currentItemOpacity,
|
||||
text: "",
|
||||
fontSize,
|
||||
fontFamily,
|
||||
textAlign: parentCenterPosition
|
||||
? "center"
|
||||
: this.state.currentItemTextAlign,
|
||||
verticalAlign: parentCenterPosition
|
||||
? VERTICAL_ALIGN.MIDDLE
|
||||
: DEFAULT_VERTICAL_ALIGN,
|
||||
containerId: shouldBindToContainer ? container?.id : undefined,
|
||||
groupIds: container?.groupIds ?? [],
|
||||
lineHeight,
|
||||
angle: container
|
||||
? isArrowElement(container)
|
||||
? (0 as Radians)
|
||||
: container.angle
|
||||
: (0 as Radians),
|
||||
frameId: topLayerFrame ? topLayerFrame.id : null,
|
||||
});
|
||||
|
||||
if (!existingTextElement && shouldBindToContainer && container) {
|
||||
mutateElement(container, {
|
||||
|
|
|
@ -439,7 +439,7 @@ const repairContainerElement = (
|
|||
// if defined, lest boundElements is stale
|
||||
!boundElement.containerId
|
||||
) {
|
||||
(boundElement as Mutable<ExcalidrawTextElement>).containerId =
|
||||
(boundElement as Mutable<typeof boundElement>).containerId =
|
||||
container.id;
|
||||
}
|
||||
}
|
||||
|
@ -464,6 +464,10 @@ const repairBoundElement = (
|
|||
? elementsMap.get(boundElement.containerId)
|
||||
: null;
|
||||
|
||||
(boundElement as Mutable<typeof boundElement>).angle = (
|
||||
isArrowElement(container) ? 0 : container?.angle ?? 0
|
||||
) as Radians;
|
||||
|
||||
if (!container) {
|
||||
boundElement.containerId = null;
|
||||
return;
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
mockBoundingClientRect,
|
||||
restoreOriginalGetBoundingClientRect,
|
||||
} from "../tests/test-utils";
|
||||
import { actionBindText } from "../actions";
|
||||
|
||||
unmountComponent();
|
||||
|
||||
|
@ -1568,5 +1569,101 @@ describe("textWysiwyg", () => {
|
|||
expect(text.containerId).toBe(null);
|
||||
expect(text.text).toBe("Excalidraw");
|
||||
});
|
||||
|
||||
it("should reset the text element angle to the container's when binding to rotated non-arrow container", async () => {
|
||||
const text = API.createElement({
|
||||
type: "text",
|
||||
text: "Hello World!",
|
||||
angle: 45,
|
||||
});
|
||||
const rectangle = API.createElement({
|
||||
type: "rectangle",
|
||||
width: 90,
|
||||
height: 75,
|
||||
angle: 30,
|
||||
});
|
||||
|
||||
API.setElements([rectangle, text]);
|
||||
|
||||
API.setSelectedElements([rectangle, text]);
|
||||
|
||||
h.app.actionManager.executeAction(actionBindText);
|
||||
|
||||
expect(text.angle).toBe(30);
|
||||
expect(rectangle.angle).toBe(30);
|
||||
});
|
||||
|
||||
it("should reset the text element angle to 0 when binding to rotated arrow container", async () => {
|
||||
const text = API.createElement({
|
||||
type: "text",
|
||||
text: "Hello World!",
|
||||
angle: 45,
|
||||
});
|
||||
const arrow = API.createElement({
|
||||
type: "arrow",
|
||||
width: 90,
|
||||
height: 75,
|
||||
angle: 30,
|
||||
});
|
||||
|
||||
API.setElements([arrow, text]);
|
||||
|
||||
API.setSelectedElements([arrow, text]);
|
||||
|
||||
h.app.actionManager.executeAction(actionBindText);
|
||||
|
||||
expect(text.angle).toBe(0);
|
||||
expect(arrow.angle).toBe(30);
|
||||
});
|
||||
|
||||
it("should keep the text label at 0 degrees when used as an arrow label", async () => {
|
||||
const arrow = API.createElement({
|
||||
type: "arrow",
|
||||
width: 90,
|
||||
height: 75,
|
||||
angle: 30,
|
||||
});
|
||||
|
||||
API.setElements([arrow]);
|
||||
API.setSelectedElements([arrow]);
|
||||
|
||||
mouse.doubleClickAt(
|
||||
arrow.x + arrow.width / 2,
|
||||
arrow.y + arrow.height / 2,
|
||||
);
|
||||
|
||||
const editor = await getTextEditor(textEditorSelector, true);
|
||||
|
||||
updateTextEditor(editor, "Hello World!");
|
||||
|
||||
Keyboard.exitTextEditor(editor);
|
||||
|
||||
expect(h.elements[1].angle).toBe(0);
|
||||
});
|
||||
|
||||
it("should keep the text label at the same degrees when used as a non-arrow label", async () => {
|
||||
const rectangle = API.createElement({
|
||||
type: "rectangle",
|
||||
width: 90,
|
||||
height: 75,
|
||||
angle: 30,
|
||||
});
|
||||
|
||||
API.setElements([rectangle]);
|
||||
API.setSelectedElements([rectangle]);
|
||||
|
||||
mouse.doubleClickAt(
|
||||
rectangle.x + rectangle.width / 2,
|
||||
rectangle.y + rectangle.height / 2,
|
||||
);
|
||||
|
||||
const editor = await getTextEditor(textEditorSelector, true);
|
||||
|
||||
updateTextEditor(editor, "Hello World!");
|
||||
|
||||
Keyboard.exitTextEditor(editor);
|
||||
|
||||
expect(h.elements[1].angle).toBe(30);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue