恢复最终预览框线开关
在最终预览恢复 Show frame 控件 开关启用后显示节点框线、标签和调整控件 补充最终预览框线回归测试
This commit is contained in:
@@ -45,6 +45,7 @@ export function PreviewWorkspace({
|
||||
const [spaceHeld, setSpaceHeld] = useState(false);
|
||||
const [renderMode, setRenderMode] =
|
||||
useState<UiEditorRenderMode>('editor-overlay');
|
||||
const [showFrame, setShowFrame] = useState(false);
|
||||
const tree = controller.treeForActiveImage ?? null;
|
||||
const logicalSize = useMemo(() => {
|
||||
if (!activeImage) return null;
|
||||
@@ -293,6 +294,16 @@ export function PreviewWorkspace({
|
||||
最终预览
|
||||
</button>
|
||||
</div>
|
||||
{renderMode === 'final-preview' ? (
|
||||
<button
|
||||
type="button"
|
||||
className={`rounded-md border px-2 py-1 text-[10px] ${showFrame ? 'border-orange-500 bg-orange-50 text-orange-700' : 'border-(--platform-subpanel-border) text-(--platform-text-soft)'}`}
|
||||
aria-pressed={showFrame}
|
||||
onClick={() => setShowFrame((current) => !current)}
|
||||
>
|
||||
Show frame
|
||||
</button>
|
||||
) : null}
|
||||
<span className="text-[10px] text-(--platform-text-soft)">
|
||||
{Object.keys(controller.images).length} 张界面图 ·{' '}
|
||||
{Object.keys(controller.sprites).length} 项素材
|
||||
@@ -352,6 +363,7 @@ export function PreviewWorkspace({
|
||||
<UiTreeRenderer
|
||||
tree={tree}
|
||||
renderMode={renderMode}
|
||||
showFrame={showFrame}
|
||||
hiddenNodeIds={controller.hiddenNodeIds}
|
||||
selectedNodeId={controller.selectedNodeId}
|
||||
resources={{
|
||||
|
||||
@@ -20,6 +20,7 @@ type NodePointerDown = (
|
||||
type UiTreeRendererProps = {
|
||||
tree: UITree | null;
|
||||
renderMode: UiEditorRenderMode;
|
||||
showFrame: boolean;
|
||||
hiddenNodeIds: ReadonlySet<NodeId>;
|
||||
selectedNodeId: NodeId | null;
|
||||
resources: PreviewComponentResources;
|
||||
@@ -57,6 +58,7 @@ function RenderNode({
|
||||
node,
|
||||
isRoot,
|
||||
renderMode,
|
||||
showFrame,
|
||||
hiddenNodeIds,
|
||||
selectedNodeId,
|
||||
resources,
|
||||
@@ -80,6 +82,7 @@ function RenderNode({
|
||||
}
|
||||
|
||||
const isEditorOverlay = renderMode === 'editor-overlay';
|
||||
const isFrameVisible = isEditorOverlay || showFrame;
|
||||
const exclusiveVisibleChildId =
|
||||
node.children_display_mode === 'Exclusive'
|
||||
? (node.children.find((child) => !hiddenNodeIds.has(child.id))?.id ??
|
||||
@@ -91,7 +94,7 @@ function RenderNode({
|
||||
className={`absolute min-h-0 min-w-0 ${isRoot ? 'cursor-default' : 'cursor-move'}`}
|
||||
style={{
|
||||
...geometry,
|
||||
...(isEditorOverlay
|
||||
...(isFrameVisible
|
||||
? {
|
||||
outline:
|
||||
selectedNodeId === node.id
|
||||
@@ -113,9 +116,9 @@ function RenderNode({
|
||||
onPointerMove={onNodePointerMove}
|
||||
onPointerUp={onNodePointerUp}
|
||||
onPointerCancel={onNodePointerUp}
|
||||
title={isEditorOverlay ? node.metadata.name || undefined : undefined}
|
||||
title={isFrameVisible ? node.metadata.name || undefined : undefined}
|
||||
>
|
||||
{isEditorOverlay && node.metadata.name ? (
|
||||
{isFrameVisible && node.metadata.name ? (
|
||||
<span className="pointer-events-none absolute left-0 top-0 max-w-full truncate bg-blue-600/80 px-1 text-[9px] leading-4 text-white">
|
||||
{node.metadata.name}
|
||||
</span>
|
||||
@@ -134,6 +137,7 @@ function RenderNode({
|
||||
key={child.id}
|
||||
node={child}
|
||||
renderMode={renderMode}
|
||||
showFrame={showFrame}
|
||||
hiddenNodeIds={hiddenNodeIds}
|
||||
selectedNodeId={selectedNodeId}
|
||||
resources={resources}
|
||||
@@ -148,7 +152,7 @@ function RenderNode({
|
||||
/>
|
||||
),
|
||||
)}
|
||||
{isEditorOverlay && !isRoot && selectedNodeId === node.id
|
||||
{isFrameVisible && !isRoot && selectedNodeId === node.id
|
||||
? RESIZE_HANDLES.map((handle) => (
|
||||
<div
|
||||
key={handle.id}
|
||||
|
||||
@@ -51,13 +51,15 @@ const resources = {
|
||||
function renderTree(
|
||||
renderMode: 'editor-overlay' | 'final-preview',
|
||||
hiddenNodeIds: ReadonlySet<string>,
|
||||
options: { showFrame?: boolean; selectedNodeId?: string | null } = {},
|
||||
) {
|
||||
return render(
|
||||
<UiTreeRenderer
|
||||
tree={tree}
|
||||
renderMode={renderMode}
|
||||
showFrame={options.showFrame ?? false}
|
||||
hiddenNodeIds={hiddenNodeIds}
|
||||
selectedNodeId={null}
|
||||
selectedNodeId={options.selectedNodeId ?? null}
|
||||
resources={resources}
|
||||
onSelectNode={vi.fn()}
|
||||
onNodePointerDown={vi.fn()}
|
||||
@@ -72,6 +74,29 @@ function renderTree(
|
||||
}
|
||||
|
||||
describe('UI tree preview visibility', () => {
|
||||
it('shows final-preview node frames and resize handles only when requested', () => {
|
||||
const withoutFrames = renderTree('final-preview', new Set(), {
|
||||
selectedNodeId: 'child',
|
||||
});
|
||||
const plainChild = withoutFrames.container.querySelector(
|
||||
'[data-node-id="child"]',
|
||||
) as HTMLDivElement;
|
||||
expect(plainChild.style.outline).toBe('');
|
||||
expect(screen.queryByLabelText('nw 调整控制点')).toBeNull();
|
||||
withoutFrames.unmount();
|
||||
|
||||
const withFrames = renderTree('final-preview', new Set(), {
|
||||
showFrame: true,
|
||||
selectedNodeId: 'child',
|
||||
});
|
||||
const framedChild = withFrames.container.querySelector(
|
||||
'[data-node-id="child"]',
|
||||
) as HTMLDivElement;
|
||||
expect(framedChild.style.outline).toBe('2px solid rgb(249 115 22)');
|
||||
expect(screen.getByText('child')).toBeTruthy();
|
||||
expect(screen.getAllByLabelText(/调整控制点$/)).toHaveLength(8);
|
||||
});
|
||||
|
||||
it('hides a node subtree in editor overlay and final preview', () => {
|
||||
const editorOverlay = renderTree('editor-overlay', new Set(['child']));
|
||||
expect(
|
||||
@@ -98,6 +123,7 @@ describe('UI tree preview visibility', () => {
|
||||
<UiTreeRenderer
|
||||
tree={exclusiveTree}
|
||||
renderMode="final-preview"
|
||||
showFrame={false}
|
||||
hiddenNodeIds={hiddenNodeIds}
|
||||
selectedNodeId={null}
|
||||
resources={resources}
|
||||
|
||||
Reference in New Issue
Block a user