Расширил возможности и поправил границы фигур
This commit is contained in:
+75
-34
@@ -3,6 +3,8 @@ import { Button } from "@consta/uikit/Button";
|
||||
import { TextField } from "@consta/uikit/TextField";
|
||||
import { ColorPicker, hexModel } from "@consta/uikit/ColorPicker";
|
||||
import { Text } from "@consta/uikit/Text";
|
||||
import { IconCancel } from "@consta/icons/IconCancel";
|
||||
import { TRANSPARENT_COLOR, toPickerHex } from "./colors";
|
||||
import {
|
||||
DEFAULT_CAPTION_TEXT_COLOR,
|
||||
DEFAULT_NODE_BACKGROUND,
|
||||
@@ -16,7 +18,12 @@ import {
|
||||
TASK_SUBTYPE_ICON,
|
||||
TASK_SUBTYPE_LABEL,
|
||||
} from "./nodes";
|
||||
import type { DiagramNodeData, EventSubtype, NodeKind, TaskSubtype } from "./types";
|
||||
import type {
|
||||
DiagramNodeData,
|
||||
EventSubtype,
|
||||
NodeKind,
|
||||
TaskSubtype,
|
||||
} from "./types";
|
||||
|
||||
const TASK_SUBTYPES: TaskSubtype[] = [
|
||||
"none",
|
||||
@@ -77,7 +84,11 @@ const TYPE_LABELS: Record<NodeKind, string> = {
|
||||
dataObject: "Документ (Data Object)",
|
||||
};
|
||||
|
||||
const EVENT_KINDS = new Set<NodeKind>(["startEvent", "intermediateEvent", "endEvent"]);
|
||||
const EVENT_KINDS = new Set<NodeKind>([
|
||||
"startEvent",
|
||||
"intermediateEvent",
|
||||
"endEvent",
|
||||
]);
|
||||
|
||||
interface NodeInspectorProps {
|
||||
nodeId: string;
|
||||
@@ -111,13 +122,9 @@ export function NodeInspector({
|
||||
const colorButtonRef = useRef<HTMLDivElement>(
|
||||
null,
|
||||
) as RefObject<HTMLDivElement>;
|
||||
// data.color can be a `var(--gradient-x)` reference from the preset row —
|
||||
// hexModel tries to parse that as a hex color and produces NaN, so the
|
||||
// hex-only ColorControl/ColorPicker always need a real flat hex fallback.
|
||||
const flatColor =
|
||||
data.color && !data.color.startsWith("var(") ?
|
||||
data.color
|
||||
: DEFAULT_NODE_COLOR[nodeType];
|
||||
// data.color бывает не-hex: `var(--gradient-x)` от пресета-градиента или
|
||||
// `transparent` — hexModel такое не разбирает, нужен hex-дефолт.
|
||||
const flatColor = toPickerHex(data.color, DEFAULT_NODE_COLOR[nodeType]);
|
||||
|
||||
const [textColorPickerOpen, setTextColorPickerOpen] = useState(false);
|
||||
const textColorButtonRef = useRef<HTMLDivElement>(
|
||||
@@ -132,11 +139,13 @@ export function NodeInspector({
|
||||
if (mode === "view") {
|
||||
const hasMeta = Boolean(data.responsible || data.duration);
|
||||
const subtypeLabel =
|
||||
nodeType === "task"
|
||||
? TASK_SUBTYPE_LABEL[(data.subtype as TaskSubtype | undefined) ?? "none"]
|
||||
: EVENT_KINDS.has(nodeType)
|
||||
? EVENT_SUBTYPE_LABEL[(data.subtype as EventSubtype | undefined) ?? "none"]
|
||||
: undefined;
|
||||
nodeType === "task" ?
|
||||
TASK_SUBTYPE_LABEL[(data.subtype as TaskSubtype | undefined) ?? "none"]
|
||||
: EVENT_KINDS.has(nodeType) ?
|
||||
EVENT_SUBTYPE_LABEL[
|
||||
(data.subtype as EventSubtype | undefined) ?? "none"
|
||||
]
|
||||
: undefined;
|
||||
return (
|
||||
<div className="node-inspector">
|
||||
<div className="node-inspector__header">
|
||||
@@ -245,7 +254,9 @@ export function NodeInspector({
|
||||
className={`node-inspector__subtype${isActive ? " node-inspector__subtype--active" : ""}`}
|
||||
onClick={() => onChange({ subtype })}
|
||||
>
|
||||
{Icon ? <Icon size="s" /> : <Text size="xs">—</Text>}
|
||||
{Icon ?
|
||||
<Icon size="s" />
|
||||
: <Text size="xs">—</Text>}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -259,24 +270,26 @@ export function NodeInspector({
|
||||
Тип триггера
|
||||
</Text>
|
||||
<div className="node-inspector__presets">
|
||||
{EVENT_SUBTYPES_BY_KIND[nodeType as "startEvent" | "intermediateEvent" | "endEvent"].map(
|
||||
(subtype: EventSubtype) => {
|
||||
const Icon = EVENT_SUBTYPE_ICON[subtype];
|
||||
const isActive = (data.subtype ?? "none") === subtype;
|
||||
return (
|
||||
<button
|
||||
key={subtype}
|
||||
type="button"
|
||||
title={EVENT_SUBTYPE_LABEL[subtype]}
|
||||
aria-label={EVENT_SUBTYPE_LABEL[subtype]}
|
||||
className={`node-inspector__subtype${isActive ? " node-inspector__subtype--active" : ""}`}
|
||||
onClick={() => onChange({ subtype })}
|
||||
>
|
||||
{Icon ? <Icon size="s" /> : <Text size="xs">—</Text>}
|
||||
</button>
|
||||
);
|
||||
},
|
||||
)}
|
||||
{EVENT_SUBTYPES_BY_KIND[
|
||||
nodeType as "startEvent" | "intermediateEvent" | "endEvent"
|
||||
].map((subtype: EventSubtype) => {
|
||||
const Icon = EVENT_SUBTYPE_ICON[subtype];
|
||||
const isActive = (data.subtype ?? "none") === subtype;
|
||||
return (
|
||||
<button
|
||||
key={subtype}
|
||||
type="button"
|
||||
title={EVENT_SUBTYPE_LABEL[subtype]}
|
||||
aria-label={EVENT_SUBTYPE_LABEL[subtype]}
|
||||
className={`node-inspector__subtype${isActive ? " node-inspector__subtype--active" : ""}`}
|
||||
onClick={() => onChange({ subtype })}
|
||||
>
|
||||
{Icon ?
|
||||
<Icon size="s" />
|
||||
: <Text size="xs">—</Text>}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -302,6 +315,19 @@ export function NodeInspector({
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<button
|
||||
type="button"
|
||||
title="Прозрачный"
|
||||
aria-label="Прозрачный"
|
||||
className={`node-inspector__preset node-inspector__preset--none${
|
||||
data.color === TRANSPARENT_COLOR ?
|
||||
" node-inspector__preset--active"
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => onChange({ color: TRANSPARENT_COLOR })}
|
||||
>
|
||||
<IconCancel size="xs" />
|
||||
</button>
|
||||
</div>
|
||||
<div ref={colorButtonRef} className="node-inspector__color-trigger">
|
||||
<Button
|
||||
@@ -319,6 +345,7 @@ export function NodeInspector({
|
||||
anchorRef={colorButtonRef}
|
||||
open={colorPickerOpen}
|
||||
onOpen={setColorPickerOpen}
|
||||
style={{ zIndex: 100 }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -339,6 +366,19 @@ export function NodeInspector({
|
||||
onClick={() => onChange({ textColor: hex })}
|
||||
/>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
title="Прозрачный"
|
||||
aria-label="Прозрачный"
|
||||
className={`node-inspector__preset node-inspector__preset--none${
|
||||
currentTextColor === TRANSPARENT_COLOR ?
|
||||
" node-inspector__preset--active"
|
||||
: ""
|
||||
}`}
|
||||
onClick={() => onChange({ textColor: TRANSPARENT_COLOR })}
|
||||
>
|
||||
<IconCancel size="xs" />
|
||||
</button>
|
||||
</div>
|
||||
<div ref={textColorButtonRef} className="node-inspector__color-trigger">
|
||||
<Button
|
||||
@@ -351,11 +391,12 @@ export function NodeInspector({
|
||||
{textColorPickerOpen && (
|
||||
<ColorPicker
|
||||
model={hexModel}
|
||||
value={currentTextColor}
|
||||
value={toPickerHex(currentTextColor, defaultTextColor)}
|
||||
onChange={(value) => onChange({ textColor: value })}
|
||||
anchorRef={textColorButtonRef}
|
||||
open={textColorPickerOpen}
|
||||
onOpen={setTextColorPickerOpen}
|
||||
style={{ zIndex: 100 }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user