优化 Inspector 组件:

- 调整输入框样式以提升可读性。
- 新增上下按钮与键盘上下箭头支持,用于调整数值变换。
- 修复数值格式化逻辑,提升输入精度控制。
- 增强只读模式的视觉提示与操作不可用状态。
This commit is contained in:
2026-08-14 13:13:51 +08:00
parent 9ea3b3cfe6
commit a213f5b503
@@ -1,6 +1,7 @@
import {
AlertTriangle,
ChevronDown,
ChevronUp,
Crosshair,
LockKeyhole,
Maximize2,
@@ -170,7 +171,7 @@ function formatValue(value: number): string {
if (Object.is(value, -0)) {
return '0';
}
return String(Number(value.toFixed(4)));
return String(Number(value.toFixed(2)));
}
function VectorInputRow({
@@ -234,6 +235,17 @@ function ScalarInput({
setDraft(formatValue(next));
};
const adjust = (direction: -1 | 1) => {
if (readOnly) {
return;
}
const current = Number(draft);
const base = Number.isFinite(current) ? current : value;
const next = Number((base + direction * step).toFixed(4));
setDraft(formatValue(next));
onCommit(next);
};
return (
<label className="relative">
<span className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 text-[9px] font-bold text-(--platform-text-soft)">
@@ -246,7 +258,7 @@ function ScalarInput({
value={draft}
aria-label={ariaLabel}
readOnly={readOnly}
className="h-9 w-full rounded-lg border border-(--platform-subpanel-border) bg-white/75 pl-6 pr-2 text-xs tabular-nums text-(--platform-text-strong) outline-none transition focus:ring-2 focus:ring-orange-100 read-only:cursor-default"
className="h-11 w-full appearance-none rounded-lg border border-(--platform-subpanel-border) bg-white/75 pl-6 pr-8 text-sm tabular-nums text-(--platform-text-strong) outline-none transition focus:ring-2 focus:ring-orange-100 read-only:cursor-default read-only:bg-slate-100 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [-moz-appearance:textfield]"
onChange={(event) => setDraft(event.target.value)}
onBlur={commit}
onKeyDown={(event) => {
@@ -255,9 +267,34 @@ function ScalarInput({
} else if (event.key === 'Escape') {
setDraft(formatValue(value));
event.currentTarget.blur();
} else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
event.preventDefault();
adjust(event.key === 'ArrowUp' ? 1 : -1);
}
}}
/>
<span className="absolute right-1 top-1/2 flex -translate-y-1/2 flex-col gap-0.5">
<button
type="button"
aria-label={`${ariaLabel} increase`}
disabled={readOnly}
className="grid size-5 place-items-center rounded text-(--platform-text-soft) transition hover:bg-orange-100 hover:text-orange-700 disabled:cursor-default disabled:opacity-40"
onMouseDown={(event) => event.preventDefault()}
onClick={() => adjust(1)}
>
<ChevronUp size={14} aria-hidden="true" />
</button>
<button
type="button"
aria-label={`${ariaLabel} decrease`}
disabled={readOnly}
className="grid size-5 place-items-center rounded text-(--platform-text-soft) transition hover:bg-orange-100 hover:text-orange-700 disabled:cursor-default disabled:opacity-40"
onMouseDown={(event) => event.preventDefault()}
onClick={() => adjust(-1)}
>
<ChevronDown size={14} aria-hidden="true" />
</button>
</span>
</label>
);
}
@@ -314,7 +351,10 @@ export function TransformEditor({
geometry?.invalid;
return (
<section className="w-full min-w-72.5 max-w-90 overflow-visible rounded-2xl border border-(--platform-subpanel-border) bg-(--platform-subpanel-fill) text-(--platform-text-strong) shadow-[0_16px_40px_rgb(91_62_45/10%)]">
<section
aria-readonly={readOnly}
className={`w-full min-w-72.5 max-w-none overflow-visible rounded-2xl border text-(--platform-text-strong) shadow-[0_16px_40px_rgb(91_62_45/10%)] ${readOnly ? 'border-slate-300 bg-slate-100/90' : 'border-(--platform-subpanel-border) bg-(--platform-subpanel-fill)'}`}
>
<header className="flex items-center justify-between border-b border-(--platform-subpanel-border) px-4 py-3">
<div className="flex items-center gap-2">
<span className="grid size-8 place-items-center rounded-xl bg-orange-100 text-orange-600">
@@ -328,17 +368,15 @@ export function TransformEditor({
</div>
</div>
{readOnly ? (
<LockKeyhole
size={14}
className="text-(--platform-text-soft)"
aria-label="Read only"
/>
<span className="inline-flex items-center gap-1 rounded-full border border-slate-300 bg-slate-200 px-2 py-1 text-[10px] font-semibold text-slate-600">
<LockKeyhole size={12} aria-hidden="true" />
Read only
</span>
) : (
<Unlock
size={14}
className="text-emerald-500"
aria-label="Editable"
/>
<span className="inline-flex items-center gap-1 rounded-full border border-emerald-200 bg-emerald-50 px-2 py-1 text-[10px] font-semibold text-emerald-600">
<Unlock size={12} aria-hidden="true" />
Editable
</span>
)}
</header>
@@ -374,12 +412,12 @@ export function TransformEditor({
{presetOpen ? (
<div
className="absolute inset-x-0 top-[calc(100%+0.5rem)] z-30 rounded-2xl border border-(--platform-subpanel-border) bg-white p-3 shadow-[0_18px_42px_rgb(41_31_24_/_18%)]"
className="absolute inset-x-0 top-[calc(100%+0.5rem)] z-30 rounded-2xl border border-(--platform-subpanel-border) bg-white p-3 shadow-[0_18px_42px_rgb(41_31_24/18%)]"
role="dialog"
aria-label="Anchor presets"
>
<div className="mb-2 flex items-center justify-between px-1">
<span className="text-[10px] font-bold uppercase tracking-[0.1em] text-(--platform-text-soft)">
<span className="text-[10px] font-bold uppercase tracking-widest text-(--platform-text-soft)">
Anchor
</span>
<span className="font-mono text-[10px] text-(--platform-text-soft)">
@@ -498,17 +536,6 @@ export function TransformEditor({
) : null}
<div className="grid gap-2">
<div className="grid grid-cols-[5.6rem_minmax(0,1fr)_minmax(0,1fr)] gap-2 px-0.5">
<span />
{AXIS_LABELS.map((axis) => (
<span
key={axis}
className="text-[9px] font-bold text-(--platform-text-soft)"
>
{axis}
</span>
))}
</div>
<VectorInputRow
label="Offset Min"
values={transform.offset_min}