Merge branch 'master' into zsviczian-loop-lock

# Conflicts:
#	packages/excalidraw/actions/actionProperties.tsx
#	packages/excalidraw/components/RadioSelection.tsx
This commit is contained in:
dwelle 2025-05-15 13:23:41 +02:00
commit d645e0ed13
23 changed files with 481 additions and 449 deletions

View File

@ -52,7 +52,7 @@
transform: none;
}
.excalidraw .panelColumn {
.excalidraw .selected-shape-actions {
text-align: left;
}

View File

@ -13,7 +13,7 @@
"default": "./dist/prod/index.js"
},
"./*": {
"types": "./../common/dist/types/common/src/*.d.ts"
"types": "./dist/types/common/src/*.d.ts"
}
},
"files": [

View File

@ -10,6 +10,7 @@ export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
export const isWindows = /^Win/.test(navigator.platform);
export const isAndroid = /\b(android)\b/i.test(navigator.userAgent);
export const isFirefox =
typeof window !== "undefined" &&
"netscape" in window &&
navigator.userAgent.indexOf("rv:") > 1 &&
navigator.userAgent.indexOf("Gecko") > 1;
@ -255,7 +256,7 @@ export const EXPORT_DATA_TYPES = {
excalidrawClipboardWithAPI: "excalidraw-api/clipboard",
} as const;
export const EXPORT_SOURCE =
export const getExportSource = () =>
window.EXCALIDRAW_EXPORT_SOURCE || window.location.origin;
// time in milliseconds

View File

@ -46,7 +46,7 @@ export const FONT_METADATA: Record<number, FontMetadata> = {
unitsPerEm: 1000,
ascender: 1011,
descender: -353,
lineHeight: 1.35,
lineHeight: 1.25,
},
},
[FONT_FAMILY["Lilita One"]]: {
@ -116,7 +116,7 @@ export const FONT_METADATA: Record<number, FontMetadata> = {
unitsPerEm: 1000,
ascender: 880,
descender: -144,
lineHeight: 1.15,
lineHeight: 1.25,
},
fallback: true,
},

View File

@ -13,7 +13,7 @@
"default": "./dist/prod/index.js"
},
"./*": {
"types": "./../element/dist/types/element/src/*.d.ts"
"types": "./dist/types/element/src/*.d.ts"
}
},
"files": [

View File

@ -33,6 +33,8 @@ const RE_GH_GIST = /^https:\/\/gist\.github\.com\/([\w_-]+)\/([\w_-]+)/;
const RE_GH_GIST_EMBED =
/^<script[\s\S]*?\ssrc=["'](https:\/\/gist\.github\.com\/.*?)\.js["']/i;
const RE_MSFORMS = /^(?:https?:\/\/)?forms\.microsoft\.com\//;
// not anchored to start to allow <blockquote> twitter embeds
const RE_TWITTER =
/(?:https?:\/\/)?(?:(?:w){3}\.)?(?:twitter|x)\.com\/[^/]+\/status\/(\d+)/;
@ -69,6 +71,7 @@ const ALLOWED_DOMAINS = new Set([
"val.town",
"giphy.com",
"reddit.com",
"forms.microsoft.com",
]);
const ALLOW_SAME_ORIGIN = new Set([
@ -82,6 +85,7 @@ const ALLOW_SAME_ORIGIN = new Set([
"*.simplepdf.eu",
"stackblitz.com",
"reddit.com",
"forms.microsoft.com",
]);
export const createSrcDoc = (body: string) => {
@ -206,6 +210,10 @@ export const getEmbedLink = (
};
}
if (RE_MSFORMS.test(link) && !link.includes("embed=true")) {
link += link.includes("?") ? "&embed=true" : "?embed=true";
}
if (RE_TWITTER.test(link)) {
const postId = link.match(RE_TWITTER)![1];
// the embed srcdoc still supports twitter.com domain only.

View File

@ -351,12 +351,20 @@ const generateElementCanvas = (
export const DEFAULT_LINK_SIZE = 14;
const IMAGE_PLACEHOLDER_IMG = document.createElement("img");
const IMAGE_PLACEHOLDER_IMG =
typeof document !== "undefined"
? document.createElement("img")
: ({ src: "" } as HTMLImageElement); // mock image element outside of browser
IMAGE_PLACEHOLDER_IMG.src = `data:${MIME_TYPES.svg},${encodeURIComponent(
`<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="image" class="svg-inline--fa fa-image fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#888" d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>`,
)}`;
const IMAGE_ERROR_PLACEHOLDER_IMG = document.createElement("img");
const IMAGE_ERROR_PLACEHOLDER_IMG =
typeof document !== "undefined"
? document.createElement("img")
: ({ src: "" } as HTMLImageElement); // mock image element outside of browser
IMAGE_ERROR_PLACEHOLDER_IMG.src = `data:${MIME_TYPES.svg},${encodeURIComponent(
`<svg viewBox="0 0 668 668" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48ZM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56ZM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.81709 0 0 .81709 124.825 145.825)"/><path d="M256 8C119.034 8 8 119.033 8 256c0 136.967 111.034 248 248 248s248-111.034 248-248S392.967 8 256 8Zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676ZM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.30366 0 0 .30366 506.822 60.065)"/></svg>`,
)}`;

View File

@ -78,7 +78,7 @@ import type { Scene } from "@excalidraw/element";
import type { CaptureUpdateActionType } from "@excalidraw/element";
import { trackEvent } from "../analytics";
import { ButtonIconSelect } from "../components/ButtonIconSelect";
import { RadioSelection } from "../components/RadioSelection";
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
import { FontPicker } from "../components/FontPicker/FontPicker";
import { IconPicker } from "../components/IconPicker";
@ -457,7 +457,8 @@ export const actionChangeFillStyle = register({
return (
<fieldset>
<legend>{t("labels.fill")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
type="button"
options={[
{
@ -501,6 +502,7 @@ export const actionChangeFillStyle = register({
updateData(nextValue);
}}
/>
</div>
</fieldset>
);
},
@ -524,7 +526,8 @@ export const actionChangeStrokeWidth = register({
PanelComponent: ({ elements, appState, updateData, app }) => (
<fieldset>
<legend>{t("labels.strokeWidth")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="stroke-width"
options={[
{
@ -556,6 +559,7 @@ export const actionChangeStrokeWidth = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
),
});
@ -579,7 +583,8 @@ export const actionChangeSloppiness = register({
PanelComponent: ({ elements, appState, updateData, app }) => (
<fieldset>
<legend>{t("labels.sloppiness")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="sloppiness"
options={[
{
@ -608,6 +613,7 @@ export const actionChangeSloppiness = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
),
});
@ -630,7 +636,8 @@ export const actionChangeStrokeStyle = register({
PanelComponent: ({ elements, appState, updateData, app }) => (
<fieldset>
<legend>{t("labels.strokeStyle")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="strokeStyle"
options={[
{
@ -659,6 +666,7 @@ export const actionChangeStrokeStyle = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
),
});
@ -697,7 +705,8 @@ export const actionChangeFontSize = register({
PanelComponent: ({ elements, appState, updateData, app }) => (
<fieldset>
<legend>{t("labels.fontSize")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="font-size"
options={[
{
@ -754,6 +763,7 @@ export const actionChangeFontSize = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
),
});
@ -1225,7 +1235,8 @@ export const actionChangeTextAlign = register({
return (
<fieldset>
<legend>{t("labels.textAlign")}</legend>
<ButtonIconSelect<TextAlign | false>
<div className="buttonList">
<RadioSelection<TextAlign | false>
group="text-align"
options={[
{
@ -1271,6 +1282,7 @@ export const actionChangeTextAlign = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
);
},
@ -1313,7 +1325,8 @@ export const actionChangeVerticalAlign = register({
PanelComponent: ({ elements, appState, updateData, app }) => {
return (
<fieldset>
<ButtonIconSelect<VerticalAlign | false>
<div className="buttonList">
<RadioSelection<VerticalAlign | false>
group="text-align"
options={[
{
@ -1361,6 +1374,7 @@ export const actionChangeVerticalAlign = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
);
},
@ -1408,7 +1422,8 @@ export const actionChangeRoundness = register({
return (
<fieldset>
<legend>{t("labels.edges")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="edges"
options={[
{
@ -1426,16 +1441,20 @@ export const actionChangeRoundness = register({
elements,
app,
(element) =>
hasLegacyRoundness ? null : element.roundness ? "round" : "sharp",
hasLegacyRoundness
? null
: element.roundness
? "round"
: "sharp",
(element) =>
!isArrowElement(element) && element.hasOwnProperty("roundness"),
(hasSelection) =>
hasSelection ? null : appState.currentItemRoundness,
)}
onChange={(value) => updateData(value)}
>
/>
{renderAction("togglePolygon")}
</ButtonIconSelect>
</div>
</fieldset>
);
},
@ -1798,7 +1817,8 @@ export const actionChangeArrowType = register({
return (
<fieldset>
<legend>{t("labels.arrowtypes")}</legend>
<ButtonIconSelect
<div className="buttonList">
<RadioSelection
group="arrowtypes"
options={[
{
@ -1840,6 +1860,7 @@ export const actionChangeArrowType = register({
)}
onChange={(value) => updateData(value)}
/>
</div>
</fieldset>
);
},

View File

@ -154,7 +154,7 @@ export const SelectedShapeActions = ({
!isSingleElementBoundContainer && alignActionsPredicate(appState, app);
return (
<div className="panelColumn">
<div className="selected-shape-actions">
<div>
{canChangeStrokeColor(appState, targetElements) &&
renderAction("changeStrokeColor")}

View File

@ -7276,8 +7276,13 @@ class App extends React.Component<AppProps, AppState> {
});
// If we click on something
} else if (hitElement != null) {
// == deep selection ==
// on CMD/CTRL, drill down to hit element regardless of groups etc.
if (event[KEYS.CTRL_OR_CMD]) {
if (event.altKey) {
// ctrl + alt means we're lasso selecting
return false;
}
if (!this.state.selectedElementIds[hitElement.id]) {
pointerDownState.hit.wasAddedToSelection = true;
}
@ -8636,6 +8641,7 @@ class App extends React.Component<AppProps, AppState> {
pointerDownState.lastCoords.x = pointerCoords.x;
pointerDownState.lastCoords.y = pointerCoords.y;
if (event.altKey) {
flushSync(() => {
this.setActiveTool(
{ type: "lasso", fromSelection: true },
event.shiftKey,
@ -8648,6 +8654,7 @@ class App extends React.Component<AppProps, AppState> {
this.setAppState({
selectionElement: null,
});
});
} else {
this.maybeDragNewGenericElement(pointerDownState, event);
}
@ -9521,7 +9528,10 @@ class App extends React.Component<AppProps, AppState> {
// if we're editing a line, pointerup shouldn't switch selection if
// box selected
(!this.state.editingLinearElement ||
!pointerDownState.boxSelection.hasOccurred)
!pointerDownState.boxSelection.hasOccurred) &&
// hitElement can be set when alt + ctrl to toggle lasso and we will
// just respect the selected elements from lasso instead
this.state.activeTool.type !== "lasso"
) {
// when inside line editor, shift selects points instead
if (childEvent.shiftKey && !this.state.editingLinearElement) {

View File

@ -1,30 +0,0 @@
import clsx from "clsx";
export const ButtonSelect = <T extends Object>({
options,
value,
onChange,
group,
}: {
options: { value: T; text: string }[];
value: T | null;
onChange: (value: T) => void;
group: string;
}) => (
<div className="buttonList">
{options.map((option) => (
<label
key={option.text}
className={clsx({ active: value === option.value })}
>
<input
type="radio"
name={group}
onChange={() => onChange(option.value)}
checked={value === option.value}
/>
{option.text}
</label>
))}
</div>
);

View File

@ -6,7 +6,7 @@ import { FONT_FAMILY } from "@excalidraw/common";
import type { FontFamilyValues } from "@excalidraw/element/types";
import { t } from "../../i18n";
import { ButtonIconSelect } from "../ButtonIconSelect";
import { RadioSelection } from "../RadioSelection";
import { ButtonSeparator } from "../ButtonSeparator";
import {
FontFamilyCodeIcon,
@ -82,12 +82,14 @@ export const FontPicker = React.memo(
return (
<div role="dialog" aria-modal="true" className="FontPicker__container">
<ButtonIconSelect<FontFamilyValues | false>
<div className="buttonList">
<RadioSelection<FontFamilyValues | false>
type="button"
options={defaultFonts}
value={selectedFontFamily}
onClick={onSelectCallback}
/>
</div>
<ButtonSeparator />
<Popover.Root open={isOpened} onOpenChange={onPopupChange}>
<FontPickerTrigger selectedFontFamily={selectedFontFamily} />

View File

@ -5,10 +5,10 @@ import { useCallback, useEffect, useRef, useState } from "react";
import {
EDITOR_LS_KEYS,
EXPORT_DATA_TYPES,
EXPORT_SOURCE,
MIME_TYPES,
VERSIONS,
chunk,
getExportSource,
} from "@excalidraw/common";
import { EditorLocalStorage } from "../data/EditorLocalStorage";
@ -281,7 +281,7 @@ const PublishLibrary = ({
const libContent: ExportedLibraryData = {
type: EXPORT_DATA_TYPES.excalidrawLibrary,
version: VERSIONS.excalidrawLibrary,
source: EXPORT_SOURCE,
source: getExportSource(),
libraryItems: clonedLibItems,
};
const content = JSON.stringify(libContent, null, 2);

View File

@ -4,8 +4,7 @@ import { ButtonIcon } from "./ButtonIcon";
import type { JSX } from "react";
// TODO: It might be "clever" to add option.icon to the existing component <ButtonSelect />
export const ButtonIconSelect = <T extends Object>(
export const RadioSelection = <T extends Object>(
props: {
options: {
value: T;
@ -17,7 +16,6 @@ export const ButtonIconSelect = <T extends Object>(
}[];
value: T | null;
type?: "radio" | "button";
children?: React.ReactNode;
} & (
| { type?: "radio"; group: string; onChange: (value: T) => void }
| {
@ -29,7 +27,7 @@ export const ButtonIconSelect = <T extends Object>(
}
),
) => (
<div className="buttonList">
<>
{props.options.map((option) =>
props.type === "button" ? (
<ButtonIcon
@ -57,6 +55,5 @@ export const ButtonIconSelect = <T extends Object>(
</label>
),
)}
{props.children}
</div>
</>
);

View File

@ -4,8 +4,6 @@ import { MIME_TYPES } from "@excalidraw/common";
import { getElementAbsoluteCoords } from "@excalidraw/element";
import { hitElementBoundingBox } from "@excalidraw/element";
import { DEFAULT_LINK_SIZE } from "@excalidraw/element";
import type { GlobalPoint, Radians } from "@excalidraw/math";
import type { Bounds } from "@excalidraw/element";
@ -16,9 +14,11 @@ import type {
import type { AppState, UIAppState } from "../../types";
export const DEFAULT_LINK_SIZE = 12;
export const EXTERNAL_LINK_IMG = document.createElement("img");
EXTERNAL_LINK_IMG.src = `data:${MIME_TYPES.svg}, ${encodeURIComponent(
`<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#1971c2" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>`,
`<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#1971c2" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>`,
)}`;
export const ELEMENT_LINK_IMG = document.createElement("img");
@ -32,13 +32,14 @@ export const getLinkHandleFromCoords = (
appState: Pick<UIAppState, "zoom">,
): Bounds => {
const size = DEFAULT_LINK_SIZE;
const linkWidth = size / appState.zoom.value;
const linkHeight = size / appState.zoom.value;
const linkMarginY = size / appState.zoom.value;
const zoom = appState.zoom.value > 1 ? appState.zoom.value : 1;
const linkWidth = size / zoom;
const linkHeight = size / zoom;
const linkMarginY = size / zoom;
const centerX = (x1 + x2) / 2;
const centerY = (y1 + y2) / 2;
const centeringOffset = (size - 8) / (2 * appState.zoom.value);
const dashedLineMargin = 4 / appState.zoom.value;
const centeringOffset = (size - 8) / (2 * zoom);
const dashedLineMargin = 4 / zoom;
// Same as `ne` resize handle
const x = x2 + dashedLineMargin - centeringOffset;

View File

@ -140,7 +140,7 @@ body.excalidraw-cursor-resize * {
justify-content: space-between;
}
.panelColumn {
.selected-shape-actions {
display: flex;
flex-direction: column;
row-gap: 0.75rem;
@ -245,10 +245,6 @@ body.excalidraw-cursor-resize * {
left: 0;
right: 0;
--bar-padding: calc(4 * var(--space-factor));
padding-top: #{"max(var(--bar-padding), var(--sat,0))"};
padding-right: var(--sar, 0);
padding-bottom: var(--sab, 0);
padding-left: var(--sal, 0);
z-index: 4;
display: flex;
align-items: flex-end;
@ -263,10 +259,6 @@ body.excalidraw-cursor-resize * {
display: flex;
flex-direction: column;
pointer-events: var(--ui-pointerEvents);
.panelColumn {
padding: 8px 8px 0 8px;
}
}
}
@ -302,6 +294,10 @@ body.excalidraw-cursor-resize * {
overflow-y: auto;
box-sizing: border-box;
margin-bottom: var(--bar-padding);
.selected-shape-actions {
padding: 8px 8px 0 8px;
}
}
.App-menu {

View File

@ -1,7 +1,7 @@
import {
DEFAULT_FILENAME,
EXPORT_DATA_TYPES,
EXPORT_SOURCE,
getExportSource,
MIME_TYPES,
VERSIONS,
} from "@excalidraw/common";
@ -56,7 +56,7 @@ export const serializeAsJSON = (
const data: ExportedDataState = {
type: EXPORT_DATA_TYPES.excalidraw,
version: VERSIONS.excalidraw,
source: EXPORT_SOURCE,
source: getExportSource(),
elements:
type === "local"
? clearElementsForExport(elements)
@ -142,7 +142,7 @@ export const serializeLibraryAsJSON = (libraryItems: LibraryItems) => {
const data: ExportedLibraryData = {
type: EXPORT_DATA_TYPES.excalidrawLibrary,
version: VERSIONS.excalidrawLibrary,
source: EXPORT_SOURCE,
source: getExportSource(),
libraryItems,
};
return JSON.stringify(data, null, 2);

View File

@ -17,7 +17,7 @@ import { selectGroupsForSelectedElements } from "@excalidraw/element";
import { getContainerElement } from "@excalidraw/element";
import { arrayToMap, easeOut } from "@excalidraw/common";
import { arrayToMap, easeOut, isShallowEqual } from "@excalidraw/common";
import type {
ExcalidrawElement,
@ -33,11 +33,18 @@ import { getLassoSelectedElementIds } from "./utils";
import type App from "../components/App";
type CanvasTranslate = {
scrollX: number;
scrollY: number;
zoom: number;
};
export class LassoTrail extends AnimatedTrail {
private intersectedElements: Set<ExcalidrawElement["id"]> = new Set();
private enclosedElements: Set<ExcalidrawElement["id"]> = new Set();
private elementsSegments: Map<string, LineSegment<GlobalPoint>[]> | null =
null;
private canvasTranslate: CanvasTranslate | null = null;
private keepPreviousSelection: boolean = false;
constructor(animationFrameHandler: AnimationFrameHandler, app: App) {
@ -169,7 +176,17 @@ export class LassoTrail extends AnimatedTrail {
.getCurrentTrail()
?.originalPoints?.map((p) => pointFrom<GlobalPoint>(p[0], p[1]));
if (!this.elementsSegments) {
const currentCanvasTranslate: CanvasTranslate = {
scrollX: this.app.state.scrollX,
scrollY: this.app.state.scrollY,
zoom: this.app.state.zoom.value,
};
if (
!this.elementsSegments ||
!isShallowEqual(currentCanvasTranslate, this.canvasTranslate ?? {})
) {
this.canvasTranslate = currentCanvasTranslate;
this.elementsSegments = new Map();
const visibleElementsMap = arrayToMap(this.app.visibleElements);
for (const element of this.app.visibleElements) {

View File

@ -188,7 +188,7 @@ const renderLinkIcon = (
window.devicePixelRatio * appState.zoom.value,
window.devicePixelRatio * appState.zoom.value,
);
linkCanvasCacheContext.fillStyle = "#fff";
linkCanvasCacheContext.fillStyle = appState.viewBackgroundColor || "#fff";
linkCanvasCacheContext.fillRect(0, 0, width, height);
if (canvasKey === "elementLink") {

View File

@ -170,10 +170,11 @@ export const isSnappingEnabled = ({
}) => {
if (event) {
return (
(app.state.objectsSnapModeEnabled && !event[KEYS.CTRL_OR_CMD]) ||
app.state.activeTool.type !== "lasso" &&
((app.state.objectsSnapModeEnabled && !event[KEYS.CTRL_OR_CMD]) ||
(!app.state.objectsSnapModeEnabled &&
event[KEYS.CTRL_OR_CMD] &&
!isGridModeEnabled(app))
!isGridModeEnabled(app)))
);
}

View File

@ -1324,7 +1324,7 @@ describe("textWysiwyg", () => {
).toEqual(FONT_FAMILY.Nunito);
expect(
(h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight,
).toEqual(1.35);
).toEqual(1.25);
});
describe("should align correctly", () => {

View File

@ -13,7 +13,7 @@
"default": "./dist/prod/index.js"
},
"./*": {
"types": "./../math/dist/types/math/src/*.d.ts"
"types": "./dist/types/math/src/*.d.ts"
}
},
"files": [

View File

@ -13,7 +13,7 @@
"default": "./dist/prod/index.js"
},
"./*": {
"types": "./../utils/dist/types/utils/src/*.d.ts"
"types": "./dist/types/utils/src/*.d.ts"
}
},
"files": [