mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-06 00:56:58 +02:00
Compare commits
6 Commits
v0.13.0
...
zsviczian-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
56d1653d97 | ||
![]() |
4d26993c8f | ||
![]() |
1e69609ce4 | ||
![]() |
f5379d1563 | ||
![]() |
c8f6e3faa8 | ||
![]() |
36bf17cf59 |
@@ -74,9 +74,6 @@
|
||||
"prettier": "2.6.2",
|
||||
"rewire": "6.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@typescript-eslint/typescript-estree": "5.10.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
|
@@ -2,7 +2,7 @@ import { ColorPicker } from "../components/ColorPicker";
|
||||
import { eraser, zoomIn, zoomOut } from "../components/icons";
|
||||
import { ToolButton } from "../components/ToolButton";
|
||||
import { DarkModeToggle } from "../components/DarkModeToggle";
|
||||
import { THEME, ZOOM_STEP } from "../constants";
|
||||
import { MIN_ZOOM, THEME, ZOOM_STEP } from "../constants";
|
||||
import { getCommonBounds, getNonDeletedElements } from "../element";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { t } from "../i18n";
|
||||
@@ -206,7 +206,7 @@ const zoomValueToFitBoundsOnViewport = (
|
||||
const zoomAdjustedToSteps =
|
||||
Math.floor(smallestZoomValue / ZOOM_STEP) * ZOOM_STEP;
|
||||
const clampedZoomValueToFitElements = Math.min(
|
||||
Math.max(zoomAdjustedToSteps, ZOOM_STEP),
|
||||
Math.max(zoomAdjustedToSteps, MIN_ZOOM),
|
||||
1,
|
||||
);
|
||||
return clampedZoomValueToFitElements as NormalizedZoomValue;
|
||||
|
@@ -76,6 +76,7 @@ import {
|
||||
THEME,
|
||||
TOUCH_CTX_MENU_TIMEOUT,
|
||||
VERTICAL_ALIGN,
|
||||
ZOOM_STEP,
|
||||
} from "../constants";
|
||||
import { loadFromBlob } from "../data";
|
||||
import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
|
||||
@@ -168,6 +169,7 @@ import {
|
||||
isArrowKey,
|
||||
KEYS,
|
||||
isAndroid,
|
||||
isDarwin,
|
||||
} from "../keys";
|
||||
import { distance2d, getGridPoint, isPathALoop } from "../math";
|
||||
import { renderScene } from "../renderer/renderScene";
|
||||
@@ -5977,7 +5979,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
} else {
|
||||
ContextMenu.push({
|
||||
options: [
|
||||
this.device.isMobile &&
|
||||
(this.device.isTouchScreen || isDarwin) &&
|
||||
navigator.clipboard && {
|
||||
trackEvent: false,
|
||||
name: "paste",
|
||||
@@ -5989,7 +5991,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
contextItemLabel: "labels.paste",
|
||||
},
|
||||
this.device.isMobile && navigator.clipboard && separator,
|
||||
(this.device.isTouchScreen || isDarwin) &&
|
||||
navigator.clipboard &&
|
||||
separator,
|
||||
probablySupportsClipboardBlob &&
|
||||
elements.length > 0 &&
|
||||
actionCopyAsPng,
|
||||
@@ -6034,9 +6038,11 @@ class App extends React.Component<AppProps, AppState> {
|
||||
} else {
|
||||
ContextMenu.push({
|
||||
options: [
|
||||
this.device.isMobile && actionCut,
|
||||
this.device.isMobile && navigator.clipboard && actionCopy,
|
||||
this.device.isMobile &&
|
||||
(this.device.isTouchScreen || isDarwin) && actionCut,
|
||||
(this.device.isTouchScreen || isDarwin) &&
|
||||
navigator.clipboard &&
|
||||
actionCopy,
|
||||
(this.device.isTouchScreen || isDarwin) &&
|
||||
navigator.clipboard && {
|
||||
name: "paste",
|
||||
trackEvent: false,
|
||||
@@ -6048,7 +6054,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
contextItemLabel: "labels.paste",
|
||||
},
|
||||
this.device.isMobile && separator,
|
||||
(this.device.isTouchScreen || isDarwin) && separator,
|
||||
...options,
|
||||
separator,
|
||||
actionCopyStyles,
|
||||
@@ -6097,7 +6103,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
// note that event.ctrlKey is necessary to handle pinch zooming
|
||||
if (event.metaKey || event.ctrlKey) {
|
||||
const sign = Math.sign(deltaY);
|
||||
const MAX_STEP = 10;
|
||||
const MAX_STEP = ZOOM_STEP * 100;
|
||||
const absDelta = Math.abs(deltaY);
|
||||
let delta = deltaY;
|
||||
if (absDelta > MAX_STEP) {
|
||||
|
@@ -122,6 +122,7 @@ export const TITLE_TIMEOUT = 10000;
|
||||
export const VERSION_TIMEOUT = 30000;
|
||||
export const SCROLL_TIMEOUT = 100;
|
||||
export const ZOOM_STEP = 0.1;
|
||||
export const MIN_ZOOM = 0.1;
|
||||
export const HYPERLINK_TOOLTIP_DELAY = 300;
|
||||
|
||||
// Report a user inactive after IDLE_THRESHOLD milliseconds
|
||||
|
@@ -14,6 +14,7 @@ import {
|
||||
getNonDeletedElements,
|
||||
getNormalizedDimensions,
|
||||
isInvisiblySmallElement,
|
||||
refreshTextDimensions,
|
||||
} from "../element";
|
||||
import { isLinearElementType } from "../element/typeChecks";
|
||||
import { randomId } from "../random";
|
||||
@@ -138,6 +139,7 @@ const restoreElementWithProperties = <
|
||||
|
||||
const restoreElement = (
|
||||
element: Exclude<ExcalidrawElement, ExcalidrawSelectionElement>,
|
||||
refreshDimensions = true,
|
||||
): typeof element | null => {
|
||||
switch (element.type) {
|
||||
case "text":
|
||||
@@ -150,7 +152,7 @@ const restoreElement = (
|
||||
fontSize = parseInt(fontPx, 10);
|
||||
fontFamily = getFontFamilyByName(_fontFamily);
|
||||
}
|
||||
return restoreElementWithProperties(element, {
|
||||
element = restoreElementWithProperties(element, {
|
||||
fontSize,
|
||||
fontFamily,
|
||||
text: element.text ?? "",
|
||||
@@ -160,6 +162,11 @@ const restoreElement = (
|
||||
containerId: element.containerId ?? null,
|
||||
originalText: element.originalText || element.text,
|
||||
});
|
||||
|
||||
if (refreshDimensions) {
|
||||
element = { ...element, ...refreshTextDimensions(element) };
|
||||
}
|
||||
return element;
|
||||
case "freedraw": {
|
||||
return restoreElementWithProperties(element, {
|
||||
points: element.points,
|
||||
@@ -232,13 +239,17 @@ export const restoreElements = (
|
||||
elements: ImportedDataState["elements"],
|
||||
/** NOTE doesn't serve for reconciliation */
|
||||
localElements: readonly ExcalidrawElement[] | null | undefined,
|
||||
refreshDimensions = true,
|
||||
): ExcalidrawElement[] => {
|
||||
const localElementsMap = localElements ? arrayToMap(localElements) : null;
|
||||
return (elements || []).reduce((elements, element) => {
|
||||
// filtering out selection, which is legacy, no longer kept in elements,
|
||||
// and causing issues if retained
|
||||
if (element.type !== "selection" && !isInvisiblySmallElement(element)) {
|
||||
let migratedElement: ExcalidrawElement | null = restoreElement(element);
|
||||
let migratedElement: ExcalidrawElement | null = restoreElement(
|
||||
element,
|
||||
refreshDimensions,
|
||||
);
|
||||
if (migratedElement) {
|
||||
const localElement = localElementsMap?.get(element.id);
|
||||
if (localElement && localElement.version > migratedElement.version) {
|
||||
@@ -376,7 +387,7 @@ export const restore = (
|
||||
localElements: readonly ExcalidrawElement[] | null | undefined,
|
||||
): RestoredDataState => {
|
||||
return {
|
||||
elements: restoreElements(data?.elements, localElements),
|
||||
elements: restoreElements(data?.elements, localElements, true),
|
||||
appState: restoreAppState(data?.appState, localAppState || null),
|
||||
files: data?.files || {},
|
||||
};
|
||||
|
@@ -22,7 +22,7 @@ const _ce = ({
|
||||
backgroundColor: "#000",
|
||||
fillStyle: "solid",
|
||||
strokeWidth: 1,
|
||||
roughness: 1,
|
||||
roughness: 0,
|
||||
opacity: 1,
|
||||
x,
|
||||
y,
|
||||
@@ -106,7 +106,7 @@ describe("getElementBounds", () => {
|
||||
} as ExcalidrawLinearElement);
|
||||
expect(x1).toEqual(360.3176068760539);
|
||||
expect(y1).toEqual(185.90654264413516);
|
||||
expect(x2).toEqual(473.8171188951176);
|
||||
expect(y2).toEqual(320.391865303557);
|
||||
expect(x2).toEqual(480.87005902729743);
|
||||
expect(y2).toEqual(320.4751269334226);
|
||||
});
|
||||
});
|
||||
|
@@ -387,34 +387,49 @@ export const getArrowheadPoints = (
|
||||
return [x2, y2, x3, y3, x4, y4];
|
||||
};
|
||||
|
||||
const generateLinearElementShape = (
|
||||
element: ExcalidrawLinearElement,
|
||||
): Drawable => {
|
||||
const generator = rough.generator();
|
||||
const options = generateRoughOptions(element);
|
||||
|
||||
const method = (() => {
|
||||
if (element.strokeSharpness !== "sharp") {
|
||||
return "curve";
|
||||
}
|
||||
if (options.fill) {
|
||||
return "polygon";
|
||||
}
|
||||
return "linearPath";
|
||||
})();
|
||||
|
||||
return generator[method](element.points as Mutable<Point>[], options);
|
||||
};
|
||||
|
||||
const getLinearElementRotatedBounds = (
|
||||
element: ExcalidrawLinearElement,
|
||||
cx: number,
|
||||
cy: number,
|
||||
): [number, number, number, number] => {
|
||||
if (element.points.length < 2 || !getShapeForElement(element)) {
|
||||
// XXX this is just a poor estimate and not very useful
|
||||
const { minX, minY, maxX, maxY } = element.points.reduce(
|
||||
(limits, [x, y]) => {
|
||||
[x, y] = rotate(element.x + x, element.y + y, cx, cy, element.angle);
|
||||
limits.minY = Math.min(limits.minY, y);
|
||||
limits.minX = Math.min(limits.minX, x);
|
||||
limits.maxX = Math.max(limits.maxX, x);
|
||||
limits.maxY = Math.max(limits.maxY, y);
|
||||
return limits;
|
||||
},
|
||||
{ minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity },
|
||||
if (element.points.length < 2) {
|
||||
const [pointX, pointY] = element.points[0];
|
||||
const [x, y] = rotate(
|
||||
element.x + pointX,
|
||||
element.y + pointY,
|
||||
cx,
|
||||
cy,
|
||||
element.angle,
|
||||
);
|
||||
return [minX, minY, maxX, maxY];
|
||||
return [x, y, x, y];
|
||||
}
|
||||
|
||||
const shape = getShapeForElement(element)!;
|
||||
|
||||
// first element is always the curve
|
||||
const ops = getCurvePathOps(shape[0]);
|
||||
|
||||
const cachedShape = getShapeForElement(element)?.[0];
|
||||
const shape = cachedShape ?? generateLinearElementShape(element);
|
||||
const ops = getCurvePathOps(shape);
|
||||
const transformXY = (x: number, y: number) =>
|
||||
rotate(element.x + x, element.y + y, cx, cy, element.angle);
|
||||
|
||||
return getMinMaxXYFromCurvePathOps(ops, transformXY);
|
||||
};
|
||||
|
||||
@@ -538,6 +553,7 @@ export const getResizedElementAbsoluteCoords = (
|
||||
points as [number, number][],
|
||||
generateRoughOptions(element),
|
||||
);
|
||||
|
||||
const ops = getCurvePathOps(curve);
|
||||
bounds = getMinMaxXYFromCurvePathOps(ops);
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ export {
|
||||
newElement,
|
||||
newTextElement,
|
||||
updateTextElement,
|
||||
refreshTextDimensions,
|
||||
newLinearElement,
|
||||
newImageElement,
|
||||
duplicateElement,
|
||||
|
@@ -252,6 +252,23 @@ const getAdjustedDimensions = (
|
||||
};
|
||||
};
|
||||
|
||||
export const refreshTextDimensions = (
|
||||
textElement: ExcalidrawTextElement,
|
||||
text = textElement.text,
|
||||
) => {
|
||||
const container = getContainerElement(textElement);
|
||||
if (container) {
|
||||
// text = wrapText(text, getFontString(textElement), container.width);
|
||||
text = wrapText(
|
||||
text,
|
||||
getFontString(textElement),
|
||||
getMaxContainerWidth(container),
|
||||
);
|
||||
}
|
||||
const dimensions = getAdjustedDimensions(textElement, text);
|
||||
return { text, ...dimensions };
|
||||
};
|
||||
|
||||
export const getMaxContainerWidth = (container: ExcalidrawElement) => {
|
||||
return getContainerDims(container).width - BOUND_TEXT_PADDING * 2;
|
||||
};
|
||||
@@ -272,20 +289,10 @@ export const updateTextElement = (
|
||||
originalText: string;
|
||||
},
|
||||
): ExcalidrawTextElement => {
|
||||
const container = getContainerElement(textElement);
|
||||
if (container) {
|
||||
text = wrapText(
|
||||
originalText,
|
||||
getFontString(textElement),
|
||||
getMaxContainerWidth(container),
|
||||
);
|
||||
}
|
||||
const dimensions = getAdjustedDimensions(textElement, text);
|
||||
return newElementWith(textElement, {
|
||||
text,
|
||||
originalText,
|
||||
isDeleted: isDeleted ?? textElement.isDeleted,
|
||||
...dimensions,
|
||||
...refreshTextDimensions(textElement, originalText),
|
||||
});
|
||||
};
|
||||
|
||||
|
@@ -721,7 +721,7 @@ const resizeMultipleElements = (
|
||||
(pointerSideY * Math.abs(pointerY - anchorY)) / (maxY - minY),
|
||||
) * (shouldResizeFromCenter ? 2 : 1);
|
||||
|
||||
if (scale === 1) {
|
||||
if (scale === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -766,21 +766,26 @@ const resizeMultipleElements = (
|
||||
width - optionalPadding,
|
||||
height - optionalPadding,
|
||||
);
|
||||
if (textMeasurements) {
|
||||
if (isTextElement(element.orig)) {
|
||||
update.fontSize = textMeasurements.size;
|
||||
update.baseline = textMeasurements.baseline;
|
||||
}
|
||||
|
||||
if (boundTextElement) {
|
||||
boundTextUpdates = {
|
||||
fontSize: textMeasurements.size,
|
||||
baseline: textMeasurements.baseline,
|
||||
};
|
||||
}
|
||||
if (!textMeasurements) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTextElement(element.orig)) {
|
||||
update.fontSize = textMeasurements.size;
|
||||
update.baseline = textMeasurements.baseline;
|
||||
}
|
||||
|
||||
if (boundTextElement) {
|
||||
boundTextUpdates = {
|
||||
fontSize: textMeasurements.size,
|
||||
baseline: textMeasurements.baseline,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
updateBoundElements(element.latest, { newSize: { width, height } });
|
||||
|
||||
mutateElement(element.latest, update);
|
||||
|
||||
if (boundTextElement && boundTextUpdates) {
|
||||
|
@@ -583,7 +583,7 @@ class Collab extends PureComponent<Props, CollabState> {
|
||||
const localElements = this.getSceneElementsIncludingDeleted();
|
||||
const appState = this.excalidrawAPI.getAppState();
|
||||
|
||||
remoteElements = restoreElements(remoteElements, null);
|
||||
remoteElements = restoreElements(remoteElements, null, false);
|
||||
|
||||
const reconciledElements = _reconcileElements(
|
||||
localElements,
|
||||
|
@@ -17,11 +17,12 @@ Please add the latest change on the top under the correct section.
|
||||
|
||||
#### Features
|
||||
|
||||
- `restoreElements()` now takes an optional parameter to indicate whether we should also recalculate text element dimensions. Defaults to `true`, but since this is a potentially costly operation, you may want to disable it if you restore elements in tight loops, such as during collaboration [#5432](https://github.com/excalidraw/excalidraw/pull/5432).
|
||||
- Support rendering custom sidebar using [`renderSidebar`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#renderSidebar) prop ([#5663](https://github.com/excalidraw/excalidraw/pull/5663)).
|
||||
- Add [`toggleMenu`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#onMenuToggle) prop to toggle specific menu open/close state ([#5663](https://github.com/excalidraw/excalidraw/pull/5663)).
|
||||
- Add [`toggleMenu`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#toggleMenu) prop to toggle specific menu open/close state ([#5663](https://github.com/excalidraw/excalidraw/pull/5663)).
|
||||
- Support [theme](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#theme) to be semi-controlled [#5660](https://github.com/excalidraw/excalidraw/pull/5660).
|
||||
- Added support for storing [`customData`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#storing-custom-data-to-excalidraw-elements) on Excalidraw elements [#5592].
|
||||
- Added `exportPadding?: number;` to [exportToCanvas](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exporttocanvas) and [exportToBlob](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exporttoblob). The default value of the padding is 10.
|
||||
- Added support for storing [`customData`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#storing-custom-data-on-excalidraw-elements) on Excalidraw elements [#5592].
|
||||
- Added `exportPadding?: number;` to [exportToCanvas](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exporttocanvas) and [exportToBlob](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exporttoblob). The default value of the padding is `10`.
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
|
@@ -915,7 +915,11 @@ When `localAppState` is supplied, it's used in place of values that are missing
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
restoreElements(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L16">ImportedDataState["elements"]</a>, localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L16">ExcalidrawElement[]</a> | null | undefined): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L106">ExcalidrawElement[]</a>
|
||||
restoreElements(
|
||||
elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L16">ImportedDataState["elements"]</a>,
|
||||
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L16">ExcalidrawElement[]</a> | null | undefined): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L106">ExcalidrawElement[]</a>,
|
||||
refreshDimensions: boolean
|
||||
)
|
||||
</pre>
|
||||
|
||||
**_How to use_**
|
||||
@@ -928,12 +932,18 @@ This function will make sure all properties of element is correctly set and if a
|
||||
|
||||
When `localElements` are supplied, they are used to ensure that existing restored elements reuse `version` (and increment it), and regenerate `versionNonce`. Use this when you import elements which may already be present in the scene to ensure that you do not disregard the newly imported elements if you're using element version to detect the updates.
|
||||
|
||||
Parameter `refreshDimensions` indicates whether we should also recalculate text element dimensions. Defaults to `true`, but since this is a potentially costly operation, you may want to disable it if you restore elements in tight loops, such as during collaboration.
|
||||
|
||||
#### `restore`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
restoreElements(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L12">ImportedDataState</a>, localAppState: Partial<<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L79">AppState</a>> | null | undefined, localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L16">ExcalidrawElement[]</a> | null | undefined): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L4">DataState</a>
|
||||
restoreElements(
|
||||
data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L12">ImportedDataState</a>,
|
||||
localAppState: Partial<<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L79">AppState</a>> | null | undefined,
|
||||
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L16">ExcalidrawElement[]</a> | null | undefined): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L4">DataState</a>
|
||||
)
|
||||
</pre>
|
||||
|
||||
See [`restoreAppState()`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#restoreAppState) about `localAppState`, and [`restoreElements()`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#restoreElements) about `localElements`.
|
||||
|
@@ -1,7 +1,8 @@
|
||||
import { MIN_ZOOM } from "../constants";
|
||||
import { AppState, NormalizedZoomValue } from "../types";
|
||||
|
||||
export const getNormalizedZoom = (zoom: number): NormalizedZoomValue => {
|
||||
return Math.max(0.1, Math.min(zoom, 30)) as NormalizedZoomValue;
|
||||
return Math.max(MIN_ZOOM, Math.min(zoom, 30)) as NormalizedZoomValue;
|
||||
};
|
||||
|
||||
export const getStateForZoom = (
|
||||
|
@@ -275,7 +275,7 @@ Object {
|
||||
"fontFamily": 1,
|
||||
"fontSize": 14,
|
||||
"groupIds": Array [],
|
||||
"height": 100,
|
||||
"height": 0,
|
||||
"id": "id-text01",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -295,7 +295,7 @@ Object {
|
||||
"version": 1,
|
||||
"versionNonce": 0,
|
||||
"verticalAlign": "middle",
|
||||
"width": 100,
|
||||
"width": 1,
|
||||
"x": -0.5,
|
||||
"y": 0,
|
||||
}
|
||||
@@ -312,7 +312,7 @@ Object {
|
||||
"fontFamily": 1,
|
||||
"fontSize": 10,
|
||||
"groupIds": Array [],
|
||||
"height": 100,
|
||||
"height": 0,
|
||||
"id": "id-text01",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
@@ -332,7 +332,7 @@ Object {
|
||||
"version": 1,
|
||||
"versionNonce": 0,
|
||||
"verticalAlign": "top",
|
||||
"width": 100,
|
||||
"width": 1,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
}
|
||||
|
Reference in New Issue
Block a user