修复并整理锚点预设 SVG 图标
提取 AnchorPresetIcon SVG 图标组件并区分定位与拉伸方向。 将 AnchorMode 统一为轴向无关的 start、center、end、stretch。 保留现有 4×4 锚点预设交互与数值语义。
This commit is contained in:
+142
@@ -0,0 +1,142 @@
|
||||
export type AnchorMode = 'start' | 'center' | 'end' | 'stretch';
|
||||
|
||||
const PRESET_ICON_BOUNDARY = 3.5;
|
||||
const PRESET_ICON_CENTER = 10;
|
||||
const PRESET_ICON_EDGE = 16.5;
|
||||
|
||||
function anchorCoordinate(mode: Exclude<AnchorMode, 'stretch'>): number {
|
||||
return mode === 'start'
|
||||
? PRESET_ICON_BOUNDARY
|
||||
: mode === 'center'
|
||||
? PRESET_ICON_CENTER
|
||||
: PRESET_ICON_EDGE;
|
||||
}
|
||||
|
||||
export function AnchorPresetIcon({ x, y }: { x: AnchorMode; y: AnchorMode }) {
|
||||
const xStretch = x === 'stretch';
|
||||
const yStretch = y === 'stretch';
|
||||
const xPosition = xStretch ? PRESET_ICON_CENTER : anchorCoordinate(x);
|
||||
const yPosition = yStretch ? PRESET_ICON_CENTER : anchorCoordinate(y);
|
||||
|
||||
return (
|
||||
<svg aria-hidden="true" className="size-5" viewBox="0 0 20 20" fill="none">
|
||||
<rect
|
||||
x="2.5"
|
||||
y="2.5"
|
||||
width="15"
|
||||
height="15"
|
||||
rx="0.5"
|
||||
stroke="currentColor"
|
||||
strokeOpacity="0.38"
|
||||
/>
|
||||
|
||||
{!xStretch ? (
|
||||
<line
|
||||
x1={xPosition}
|
||||
y1={PRESET_ICON_BOUNDARY}
|
||||
x2={xPosition}
|
||||
y2={PRESET_ICON_EDGE}
|
||||
stroke="#d8665f"
|
||||
strokeWidth="1.15"
|
||||
/>
|
||||
) : null}
|
||||
{!yStretch ? (
|
||||
<line
|
||||
x1={PRESET_ICON_BOUNDARY}
|
||||
y1={yPosition}
|
||||
x2={PRESET_ICON_EDGE}
|
||||
y2={yPosition}
|
||||
stroke="#d8665f"
|
||||
strokeWidth="1.15"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{xStretch ? (
|
||||
<>
|
||||
<line
|
||||
x1={PRESET_ICON_BOUNDARY}
|
||||
y1={PRESET_ICON_CENTER}
|
||||
x2={PRESET_ICON_EDGE}
|
||||
y2={PRESET_ICON_CENTER}
|
||||
stroke="#3b82f6"
|
||||
strokeWidth="1.2"
|
||||
/>
|
||||
<path
|
||||
d="M3.5 10 5.5 8.6v2.8L3.5 10Zm13 0-2-1.4v2.8l2-1.4Z"
|
||||
fill="#3b82f6"
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
{yStretch ? (
|
||||
<>
|
||||
<line
|
||||
x1={PRESET_ICON_CENTER}
|
||||
y1={PRESET_ICON_BOUNDARY}
|
||||
x2={PRESET_ICON_CENTER}
|
||||
y2={PRESET_ICON_EDGE}
|
||||
stroke="#3b82f6"
|
||||
strokeWidth="1.2"
|
||||
/>
|
||||
<path
|
||||
d="m10 3.5-1.4 2h2.8L10 3.5Zm0 13 1.4-2H8.6l1.4 2Z"
|
||||
fill="#3b82f6"
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{!xStretch && !yStretch ? (
|
||||
<circle cx={xPosition} cy={yPosition} r="1.25" fill="#eab308" />
|
||||
) : null}
|
||||
{xStretch && !yStretch ? (
|
||||
<>
|
||||
<circle
|
||||
cx={PRESET_ICON_BOUNDARY}
|
||||
cy={yPosition}
|
||||
r="1"
|
||||
fill="#eab308"
|
||||
/>
|
||||
<circle cx={PRESET_ICON_EDGE} cy={yPosition} r="1" fill="#eab308" />
|
||||
</>
|
||||
) : null}
|
||||
{!xStretch && yStretch ? (
|
||||
<>
|
||||
<circle
|
||||
cx={xPosition}
|
||||
cy={PRESET_ICON_BOUNDARY}
|
||||
r="1"
|
||||
fill="#eab308"
|
||||
/>
|
||||
<circle cx={xPosition} cy={PRESET_ICON_EDGE} r="1" fill="#eab308" />
|
||||
</>
|
||||
) : null}
|
||||
{xStretch && yStretch ? (
|
||||
<>
|
||||
<circle
|
||||
cx={PRESET_ICON_BOUNDARY}
|
||||
cy={PRESET_ICON_BOUNDARY}
|
||||
r="1"
|
||||
fill="#eab308"
|
||||
/>
|
||||
<circle
|
||||
cx={PRESET_ICON_EDGE}
|
||||
cy={PRESET_ICON_BOUNDARY}
|
||||
r="1"
|
||||
fill="#eab308"
|
||||
/>
|
||||
<circle
|
||||
cx={PRESET_ICON_BOUNDARY}
|
||||
cy={PRESET_ICON_EDGE}
|
||||
r="1"
|
||||
fill="#eab308"
|
||||
/>
|
||||
<circle
|
||||
cx={PRESET_ICON_EDGE}
|
||||
cy={PRESET_ICON_EDGE}
|
||||
r="1"
|
||||
fill="#eab308"
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
+11
-21
@@ -5,7 +5,6 @@ import {
|
||||
Crosshair,
|
||||
Info,
|
||||
LockKeyhole,
|
||||
Maximize2,
|
||||
Move,
|
||||
SlidersHorizontal,
|
||||
Unlock,
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import type { Transform } from '../../../../../features/ui-editor/types/Transform';
|
||||
import { type AnchorMode, AnchorPresetIcon } from './AnchorPresetIcon';
|
||||
|
||||
export type TransformEditorParentSize = {
|
||||
width: number;
|
||||
@@ -27,7 +27,6 @@ export type TransformEditorProps = {
|
||||
};
|
||||
|
||||
type Axis = 0 | 1;
|
||||
type AnchorMode = 'left' | 'center' | 'right' | 'stretch';
|
||||
type AnchorPreset = {
|
||||
id: string;
|
||||
label: string;
|
||||
@@ -37,19 +36,19 @@ type AnchorPreset = {
|
||||
|
||||
const AXIS_LABELS = ['X', 'Y'] as const;
|
||||
const AXIS_MODE_LABELS: Record<AnchorMode, string> = {
|
||||
left: '左侧',
|
||||
start: '左侧',
|
||||
center: '居中',
|
||||
right: '右侧',
|
||||
end: '右侧',
|
||||
stretch: '拉伸',
|
||||
};
|
||||
const ROW_MODE_LABELS: Record<AnchorMode, string> = {
|
||||
left: '顶部',
|
||||
start: '顶部',
|
||||
center: '居中',
|
||||
right: '底部',
|
||||
end: '底部',
|
||||
stretch: '拉伸',
|
||||
};
|
||||
const COLUMN_MODES: AnchorMode[] = ['left', 'center', 'right', 'stretch'];
|
||||
const ROW_MODES: AnchorMode[] = ['left', 'center', 'right', 'stretch'];
|
||||
const COLUMN_MODES: AnchorMode[] = ['start', 'center', 'end', 'stretch'];
|
||||
const ROW_MODES: AnchorMode[] = ['start', 'center', 'end', 'stretch'];
|
||||
|
||||
const PRESETS: AnchorPreset[] = ROW_MODES.flatMap((y) =>
|
||||
COLUMN_MODES.map((x) => ({
|
||||
@@ -63,8 +62,8 @@ const PRESETS: AnchorPreset[] = ROW_MODES.flatMap((y) =>
|
||||
const CUSTOM_PRESET: AnchorPreset = {
|
||||
id: 'custom',
|
||||
label: '自定义',
|
||||
x: 'left',
|
||||
y: 'left',
|
||||
x: 'start',
|
||||
y: 'start',
|
||||
};
|
||||
|
||||
const FIELD_HINTS = {
|
||||
@@ -91,7 +90,7 @@ function modeAnchors(mode: AnchorMode): [number, number] {
|
||||
if (mode === 'stretch') {
|
||||
return [0, 1];
|
||||
}
|
||||
const value = mode === 'left' ? 0 : mode === 'center' ? 0.5 : 1;
|
||||
const value = mode === 'start' ? 0 : mode === 'center' ? 0.5 : 1;
|
||||
return [value, value];
|
||||
}
|
||||
|
||||
@@ -501,16 +500,7 @@ export function TransformEditor({
|
||||
setPresetOpen(false);
|
||||
}}
|
||||
>
|
||||
<span className="relative grid size-5 place-items-center rounded border border-current/35">
|
||||
<span className="size-1 rounded-full bg-current" />
|
||||
{column === 'stretch' || row === 'stretch' ? (
|
||||
<Maximize2
|
||||
size={12}
|
||||
className="absolute"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
) : null}
|
||||
</span>
|
||||
<AnchorPresetIcon x={column} y={row} />
|
||||
</button>
|
||||
);
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user