稳定组件面板展开与移除交互

仅在组件存在性变化时自动展开面板

为移除组件增加确认并保留失败弹窗
This commit is contained in:
2026-09-12 02:08:56 +08:00
parent e04075fd95
commit 560422286b
@@ -1,5 +1,5 @@
import { ChevronDown, ChevronRight, Plus, Trash2 } from 'lucide-react';
import { useEffect, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { ThemedModal } from '../../../../../components/modal/ThemedModal';
import type { Component } from '../../../../../features/ui-editor/types/Component';
@@ -19,9 +19,15 @@ export function ComponentPanel(props: ComponentPanelProps) {
const [expanded, setExpanded] = useState(Boolean(component));
const [error, setError] = useState<string | null>(null);
const [replaceConfirmationOpen, setReplaceConfirmationOpen] = useState(false);
const [removeConfirmationOpen, setRemoveConfirmationOpen] = useState(false);
const previousComponentRef = useRef(component);
useEffect(() => {
setExpanded(Boolean(component));
const previous = previousComponentRef.current;
previousComponentRef.current = component;
if (Boolean(component) !== Boolean(previous)) {
setExpanded(Boolean(component));
}
}, [component]);
function setComponent(next: Component | null) {
@@ -48,8 +54,15 @@ export function ComponentPanel(props: ComponentPanelProps) {
function applyReplacement() {
const result = setComponent(createComponent());
if (result?.ok) setExpanded(true);
setReplaceConfirmationOpen(false);
if (result?.ok) {
setExpanded(true);
setReplaceConfirmationOpen(false);
}
}
function removeComponent() {
const result = setComponent(null);
if (result?.ok) setRemoveConfirmationOpen(false);
}
return (
@@ -107,7 +120,7 @@ export function ComponentPanel(props: ComponentPanelProps) {
type="button"
className="grid size-7 place-items-center rounded-lg border border-red-200 bg-red-50 text-red-700 disabled:cursor-not-allowed disabled:opacity-35"
disabled={readOnly}
onClick={() => setComponent(null)}
onClick={() => setRemoveConfirmationOpen(true)}
aria-label="移除组件"
title="移除组件"
>
@@ -153,6 +166,33 @@ export function ComponentPanel(props: ComponentPanelProps) {
</button>
</div>
</ThemedModal>
<ThemedModal
open={removeConfirmationOpen}
ariaLabel="确认移除组件"
onClose={() => setRemoveConfirmationOpen(false)}
panelClassName="w-full max-w-sm rounded-2xl p-5"
>
<h2 className="m-0 text-base font-semibold"></h2>
<p className="mt-3 text-sm text-(--platform-text-soft)">
</p>
<div className="mt-5 flex justify-end gap-2">
<button
type="button"
className="rounded-lg border border-(--platform-subpanel-border) px-3 py-2 text-xs"
onClick={() => setRemoveConfirmationOpen(false)}
>
</button>
<button
type="button"
className="rounded-lg bg-red-600 px-3 py-2 text-xs font-semibold text-white"
onClick={removeComponent}
>
</button>
</div>
</ThemedModal>
</section>
);
}