From 6f5e5870645d367f051d01d3bbdfa8d4d7ad3ffd Mon Sep 17 00:00:00 2001 From: clawdbot Date: Wed, 28 Jan 2026 01:40:49 +0800 Subject: [PATCH] refactor: unwrap goView components + improve context menu closing --- packages/editor/src/editor/Canvas.tsx | 14 ++++++++++- packages/sdk/src/core/goview/convert.ts | 31 ++++++++++++++++--------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/packages/editor/src/editor/Canvas.tsx b/packages/editor/src/editor/Canvas.tsx index 80305ed..4dfef9a 100644 --- a/packages/editor/src/editor/Canvas.tsx +++ b/packages/editor/src/editor/Canvas.tsx @@ -182,14 +182,26 @@ export function Canvas(props: CanvasProps) { if (e.key === 'Escape') setCtx(null); }; - const onAnyPointerDown = () => setCtx(null); + const close = () => setCtx(null); + + // Close on any outside interaction to keep UI parity with common editors. + const onAnyPointerDown = () => close(); + const onAnyWheel = () => close(); + const onScroll = () => close(); + const onBlur = () => close(); window.addEventListener('keydown', onKeyDown); window.addEventListener('pointerdown', onAnyPointerDown); + window.addEventListener('wheel', onAnyWheel, { passive: true }); + window.addEventListener('scroll', onScroll, true); + window.addEventListener('blur', onBlur); return () => { window.removeEventListener('keydown', onKeyDown); window.removeEventListener('pointerdown', onAnyPointerDown); + window.removeEventListener('wheel', onAnyWheel); + window.removeEventListener('scroll', onScroll, true); + window.removeEventListener('blur', onBlur); }; }, [ctx]); diff --git a/packages/sdk/src/core/goview/convert.ts b/packages/sdk/src/core/goview/convert.ts index e60cc5a..8f19c4f 100644 --- a/packages/sdk/src/core/goview/convert.ts +++ b/packages/sdk/src/core/goview/convert.ts @@ -63,17 +63,26 @@ export interface GoViewProjectLike { } function unwrapComponent(c: GoViewComponentLike): GoViewComponentLike { - // Prefer the nested component shape but keep outer fields as fallback. - // This handles exports like: { id, attr, component: { chartConfig, option } } - const inner = c.component; - if (!inner) return c; - return { - // Prefer outer for geometry/id, but prefer inner for identity/option when present. - ...c, - ...inner, - // ensure the nested component doesn't get lost - component: inner.component, - }; + // Prefer nested component shapes but keep outer fields as fallback. + // Some exports wrap components multiple times like: + // { id, attr, component: { component: { chartConfig, option } } } + // We unwrap iteratively to avoid recursion pitfalls. + let out: GoViewComponentLike = c; + let depth = 0; + + while (out.component && depth < 6) { + const inner = out.component; + out = { + // Prefer outer for geometry/id, but prefer inner for identity/option when present. + ...out, + ...inner, + // keep unwrapping if there are more layers + component: inner.component, + }; + depth++; + } + + return out; } function keyOf(cIn: GoViewComponentLike): string {