editing single element
This commit is contained in:
parent
30743ec726
commit
3fc89b716a
@ -9,8 +9,33 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
|
||||||
.section {
|
.sectionContent {
|
||||||
padding: 12px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.elementType {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statsItem {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
// margin-right: 8px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-right: 4px;
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 55px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { getCommonBounds } from "../element/bounds";
|
import { getCommonBounds } from "../element/bounds";
|
||||||
import { NonDeletedExcalidrawElement } from "../element/types";
|
import { mutateElement } from "../element/mutateElement";
|
||||||
|
import {
|
||||||
|
ExcalidrawElement,
|
||||||
|
NonDeletedExcalidrawElement,
|
||||||
|
} from "../element/types";
|
||||||
import { t } from "../i18n";
|
import { t } from "../i18n";
|
||||||
|
import { KEYS } from "../keys";
|
||||||
import { getTargetElements } from "../scene";
|
import { getTargetElements } from "../scene";
|
||||||
import { AppState, ExcalidrawProps } from "../types";
|
import { AppState, ExcalidrawProps } from "../types";
|
||||||
import { CloseIcon } from "./icons";
|
import { CloseIcon } from "./icons";
|
||||||
@ -19,9 +24,45 @@ export const Stats = (props: {
|
|||||||
const selectedElements = getTargetElements(props.elements, props.appState);
|
const selectedElements = getTargetElements(props.elements, props.appState);
|
||||||
const selectedBoundingBox = getCommonBounds(selectedElements);
|
const selectedBoundingBox = getCommonBounds(selectedElements);
|
||||||
|
|
||||||
|
const stats =
|
||||||
|
selectedElements.length === 1
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: "X",
|
||||||
|
value: Math.round(selectedBoundingBox[0]),
|
||||||
|
element: selectedElements[0],
|
||||||
|
property: "x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Y",
|
||||||
|
value: Math.round(selectedBoundingBox[1]),
|
||||||
|
element: selectedElements[0],
|
||||||
|
property: "y",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "W",
|
||||||
|
value: Math.round(selectedBoundingBox[2] - selectedBoundingBox[0]),
|
||||||
|
element: selectedElements[0],
|
||||||
|
property: "width",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "H",
|
||||||
|
value: Math.round(selectedBoundingBox[3] - selectedBoundingBox[1]),
|
||||||
|
element: selectedElements[0],
|
||||||
|
property: "height",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "A",
|
||||||
|
value: selectedElements[0].angle,
|
||||||
|
element: selectedElements[0],
|
||||||
|
property: "angle",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Stats">
|
<div className="Stats">
|
||||||
<Island>
|
<Island padding={3}>
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<div className="close" onClick={props.onClose}>
|
<div className="close" onClick={props.onClose}>
|
||||||
{CloseIcon}
|
{CloseIcon}
|
||||||
@ -54,75 +95,79 @@ export const Stats = (props: {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedElements.length > 0 && (
|
{selectedElements.length > 0 && (
|
||||||
<>
|
<div className="section">
|
||||||
<div className="divider"></div>
|
<h3>{t("stats.elementStats")}</h3>
|
||||||
|
|
||||||
<div className="section">
|
<div className="sectionContent">
|
||||||
<h3>{t("stats.elementStats")}</h3>
|
{selectedElements.length === 1 && (
|
||||||
|
<div className="elementType">
|
||||||
|
{t(`element.${selectedElements[0].type}`)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<table>
|
<div
|
||||||
<tbody>
|
style={{
|
||||||
{selectedElements.length === 1 && (
|
display: "grid",
|
||||||
<tr>
|
gridTemplateColumns: "repeat(2, 1fr)",
|
||||||
<th colSpan={2}>
|
gap: "4px 8px",
|
||||||
{t(`element.${selectedElements[0].type}`)}
|
}}
|
||||||
</th>
|
>
|
||||||
</tr>
|
{stats.map((statsItem) => (
|
||||||
)}
|
<label
|
||||||
|
className="color-input-container"
|
||||||
|
key={statsItem.property}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="color-picker-hash"
|
||||||
|
style={{
|
||||||
|
width: "30px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{statsItem.label}
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
id={statsItem.label}
|
||||||
|
defaultValue={statsItem.value}
|
||||||
|
className="color-picker-input"
|
||||||
|
style={{
|
||||||
|
width: "55px",
|
||||||
|
}}
|
||||||
|
autoComplete="off"
|
||||||
|
spellCheck="false"
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
const value = Number(event.target.value);
|
||||||
|
|
||||||
{selectedElements.length > 1 && (
|
if (event.key === KEYS.ENTER) {
|
||||||
<>
|
if (!isNaN(value)) {
|
||||||
<tr>
|
mutateElement(statsItem.element, {
|
||||||
<th colSpan={2}>{t("stats.selected")}</th>
|
[statsItem.property]: value,
|
||||||
</tr>
|
});
|
||||||
<tr>
|
}
|
||||||
<td>{t("stats.elements")}</td>
|
|
||||||
<td>{selectedElements.length}</td>
|
event.target.value = statsItem.element[
|
||||||
</tr>
|
statsItem.property as keyof ExcalidrawElement
|
||||||
</>
|
] as string;
|
||||||
)}
|
}
|
||||||
{selectedElements.length > 0 && (
|
}}
|
||||||
<>
|
onBlur={(event) => {
|
||||||
<tr>
|
const value = Number(event.target.value);
|
||||||
<td>{"x"}</td>
|
|
||||||
<td>{Math.round(selectedBoundingBox[0])}</td>
|
if (!isNaN(value)) {
|
||||||
</tr>
|
mutateElement(statsItem.element, {
|
||||||
<tr>
|
[statsItem.property]: value,
|
||||||
<td>{"y"}</td>
|
});
|
||||||
<td>{Math.round(selectedBoundingBox[1])}</td>
|
}
|
||||||
</tr>
|
|
||||||
<tr>
|
event.target.value = statsItem.element[
|
||||||
<td>{t("stats.width")}</td>
|
statsItem.property as keyof ExcalidrawElement
|
||||||
<td>
|
] as string;
|
||||||
{Math.round(
|
}}
|
||||||
selectedBoundingBox[2] - selectedBoundingBox[0],
|
></input>
|
||||||
)}
|
</label>
|
||||||
</td>
|
))}
|
||||||
</tr>
|
</div>
|
||||||
<tr>
|
|
||||||
<td>{t("stats.height")}</td>
|
|
||||||
<td>
|
|
||||||
{Math.round(
|
|
||||||
selectedBoundingBox[3] - selectedBoundingBox[1],
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{selectedElements.length === 1 && (
|
|
||||||
<tr>
|
|
||||||
<td>{t("stats.angle")}</td>
|
|
||||||
<td>
|
|
||||||
{`${Math.round(
|
|
||||||
(selectedElements[0].angle * 180) / Math.PI,
|
|
||||||
)}°`}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Island>
|
</Island>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user