diff --git a/web/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsx b/web/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsx index 90e2bf80ee..0d943a1480 100644 --- a/web/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsx +++ b/web/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsx @@ -217,6 +217,10 @@ const PlaygroundVariantConfig: React.FC< revisionId={variantId} onRefinePrompt={handleRefinePrompt} viewMode={viewMode} + // Embedded (drawer) renders the variant config + // header non-sticky, so the section headers have + // nothing to clear — pin them at the scroll top. + stickyHeaderTop={embedded ? 0 : 48} /> diff --git a/web/packages/agenta-entity-ui/src/DrillInView/components/PlaygroundConfigSection.tsx b/web/packages/agenta-entity-ui/src/DrillInView/components/PlaygroundConfigSection.tsx index 0618b14bd8..a77bcad86e 100644 --- a/web/packages/agenta-entity-ui/src/DrillInView/components/PlaygroundConfigSection.tsx +++ b/web/packages/agenta-entity-ui/src/DrillInView/components/PlaygroundConfigSection.tsx @@ -451,6 +451,15 @@ export interface PlaygroundConfigSectionProps { onRefinePrompt?: (promptKey: string) => void /** View mode controlled from parent (form/json/yaml) */ viewMode?: ConfigViewMode + /** + * Top offset (px) for the sticky section headers. Defaults to 48 to clear + * the sticky `PlaygroundVariantConfigHeader` (h-[48px], `sticky top-0`) that + * sits above the config in the full playground. In the embedded drawer that + * header is rendered non-sticky (`grow`), so there is nothing to clear — + * pass 0 there to keep the section headers flush with the scroll top instead + * of floating 48px down into the editor content. + */ + stickyHeaderTop?: number } function PlaygroundConfigSection({ @@ -461,6 +470,7 @@ function PlaygroundConfigSection({ moleculeAdapter, onRefinePrompt, viewMode: externalViewMode, + stickyHeaderTop = 48, }: PlaygroundConfigSectionProps) { const {llmProviderConfig} = useDrillInUI() @@ -1362,7 +1372,8 @@ function PlaygroundConfigSection({ return (
toggleSection(fieldKey)} >
@@ -1578,7 +1589,10 @@ function PlaygroundConfigSection({ ) : ( <> {!hasTopLevelObjectSection && ( -
+
Config
)} diff --git a/web/packages/agenta-ui/src/Editor/plugins/code/utils/pasteUtils.ts b/web/packages/agenta-ui/src/Editor/plugins/code/utils/pasteUtils.ts index 39c12219d0..10f0055617 100644 --- a/web/packages/agenta-ui/src/Editor/plugins/code/utils/pasteUtils.ts +++ b/web/packages/agenta-ui/src/Editor/plugins/code/utils/pasteUtils.ts @@ -117,8 +117,13 @@ export function $insertLinesWithSelectionAndIndent({ } } - // Clone trailing lines before removal - const clonedTrailingLines = linesAfter.map((l) => $copyNode(l)) + // Capture trailing-line TEXT before removal, then rebuild fresh nodes after + // insertion (see re-insertion below). We can't element-clone these lines: + // `$copyNode` assigns the clone a fresh key, and Lexical's ElementNode only + // carries child pointers when the key is unchanged — so a cloned CodeLineNode + // comes back EMPTY, wiping every line below the paste point. Rebuilding from + // text mirrors the large-paste fast path and preserves the content faithfully. + const trailingLineTexts = linesAfter.map((l) => l.getTextContent()) linesAfter.forEach((l) => l.remove()) // Remove current line currentLine.remove() @@ -174,11 +179,12 @@ export function $insertLinesWithSelectionAndIndent({ insertIdx++ } - // Add trailing lines (use clones) - clonedTrailingLines.forEach((l, i) => { + // Add trailing lines (rebuilt from captured text — see note above) + const trailingLanguage = parentBlock.getLanguage() + trailingLineTexts.forEach((text, i) => { const prevChild = $getLineAtIndex(parentBlock, insertIdx - 1 + i) if (prevChild) { - prevChild.insertAfter(l) + prevChild.insertAfter($createNodeForLineWithTabs(text, trailingLanguage)) } }) diff --git a/web/packages/agenta-ui/src/SharedEditor/SharedEditorImpl.tsx b/web/packages/agenta-ui/src/SharedEditor/SharedEditorImpl.tsx index 8c6a2e027f..ab93140354 100644 --- a/web/packages/agenta-ui/src/SharedEditor/SharedEditorImpl.tsx +++ b/web/packages/agenta-ui/src/SharedEditor/SharedEditorImpl.tsx @@ -453,12 +453,24 @@ const SharedEditor = ({ style={ { ...props.style, - interpolateSize: "allow-keywords", height: "var(--editor-h, auto)", overflow: "hidden", - transitionProperty: "height", - transitionDuration: "300ms", - transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)", + // The height transition exists only to animate the collapse + // toggle (which sets `--editor-h` to a fixed px ↔ auto). Code + // editors never use that toggle, so `--editor-h` stays `auto` + // and `interpolate-size: allow-keywords` would instead animate + // EVERY content-height change while typing/pasting — making the + // editor grow over 300ms and lurching the surrounding drawer's + // scroll. Disable the animation for codeOnly so growth is + // instant; keep it for the collapsible rich-text/prompt editors. + ...(editorProps?.codeOnly + ? {} + : { + interpolateSize: "allow-keywords", + transitionProperty: "height", + transitionDuration: "300ms", + transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)", + }), } as React.CSSProperties } onPasteCapture={handlePasteCapture}