From 46976b1f928a35b00fea4261bd7bb3b524f3ab3b Mon Sep 17 00:00:00 2001 From: Lucio Lelii Date: Wed, 22 Jul 2026 09:20:08 +0200 Subject: [PATCH] fix(nodes): fix the same backdrop containing-block bug in the shared .llm-modal popup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While verifying the dialog style convergence, found that generic-node's "Edit " popup and container-node's "Edit Name" popup have the same bug just fixed in bias-annotations: they render inside the node card, which rete.js positions with a CSS transform for pan/zoom, so their fixed-position .llm-modal-backdrop was trapped inside the node's own box instead of covering the page — confirmed live, the backdrop's bounding rect matched the node's box (280x533) rather than the viewport. This popup is the primary way to edit any short parameter on any node in the editor, so the bug was hit far more often than the bias one. Same fix: promote the backdrop to a native shown via showModal(), move the dimming to ::backdrop, and guard showModal() since jsdom doesn't implement it. Verified live: the backdrop's rect now spans the full viewport for both generic-node and container-node, and closing via a backdrop click still works. Co-Authored-By: Claude Sonnet 5 --- .../nodes/container-node/container-node.html | 4 +-- .../nodes/container-node/container-node.ts | 25 ++++++++++++++++++- .../nodes/generic-node/generic-node.html | 4 +-- .../shared/nodes/generic-node/generic-node.ts | 23 ++++++++++++++++- src/styles.css | 10 ++++++++ 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/app/shared/nodes/container-node/container-node.html b/src/app/shared/nodes/container-node/container-node.html index 7206654..5898787 100644 --- a/src/app/shared/nodes/container-node/container-node.html +++ b/src/app/shared/nodes/container-node/container-node.html @@ -76,7 +76,7 @@ @if (nameEditorOpen) { -
+
Edit Name
@@ -94,7 +94,7 @@
-
+
}
diff --git a/src/app/shared/nodes/container-node/container-node.ts b/src/app/shared/nodes/container-node/container-node.ts index 304e307..60b6288 100644 --- a/src/app/shared/nodes/container-node/container-node.ts +++ b/src/app/shared/nodes/container-node/container-node.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, HostListener, Input, OnDestroy, inject } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, HostListener, Input, OnDestroy, effect, inject, viewChild } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatTooltipModule } from '@angular/material/tooltip'; import { currentFlowPortValueKind, flowValueKindLabel, FlowData, FLOW_DEPENDANT_PORT_KEY, FLOW_DEPENDENCY_PORT_KEY } from '@models/flow'; @@ -109,6 +109,29 @@ export class ContainerNodeComponent implements OnDestroy { nameEditorOpen = false; draftName = ''; + /** + * This template renders inside a node card, which rete.js positions with a + * CSS `transform` for pan/zoom, so a plain fixed-position backdrop would be + * confined to the node's box. A native `` shown via `showModal()` + * escapes that via the browser's top layer, same fix as bias-annotations. + */ + private readonly nameEditorDialog = viewChild>('nameEditorDialog'); + + constructor() { + effect(() => { + const dialog = this.nameEditorDialog()?.nativeElement; + if (dialog && typeof dialog.showModal === 'function' && !dialog.open) { + dialog.showModal(); + } + }); + } + + onNameEditorDialogClick(event: MouseEvent) { + if (event.target === this.nameEditorDialog()?.nativeElement) { + this.cancelNameEditor(event); + } + } + get isSchemaLoading() { return this.schemaLoading; } diff --git a/src/app/shared/nodes/generic-node/generic-node.html b/src/app/shared/nodes/generic-node/generic-node.html index cca5630..3afd61e 100644 --- a/src/app/shared/nodes/generic-node/generic-node.html +++ b/src/app/shared/nodes/generic-node/generic-node.html @@ -534,7 +534,7 @@ (annotationsChange)="updateBiasAnnotations($event)" /> @if (localEditorOpen) { -
+
Edit {{ localEditorLabel }}
@if (localEditorBindableAsInput && localEditorPath !== 'name') { @@ -605,7 +605,7 @@
-
+ } diff --git a/src/app/shared/nodes/generic-node/generic-node.ts b/src/app/shared/nodes/generic-node/generic-node.ts index 4e13fe0..0af2bb4 100644 --- a/src/app/shared/nodes/generic-node/generic-node.ts +++ b/src/app/shared/nodes/generic-node/generic-node.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, effect, ElementRef, HostBinding, HostListener, inject, Input, OnDestroy } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, effect, ElementRef, HostBinding, HostListener, inject, Input, OnDestroy, viewChild } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatTooltipModule } from '@angular/material/tooltip'; import { BiasAnnotation, BiasAnnotationsDescriptor, BlockType, currentFlowPortValueKind, flowValueKindLabel, FlowBlock, FlowData, FlowPort, FlowValueKind, FLOW_DEPENDANT_PORT_KEY, FLOW_DEPENDENCY_PORT_KEY, isProbeExecutable, normalizeFlowPortValueKinds } from '@models/flow'; @@ -204,6 +204,14 @@ export class GenericNodeComponent implements OnDestroy { private conditionalRequiredByPath = new Map(); private refreshingConditionalRequirements = false; + /** + * This template renders inside a node card, which rete.js positions with a + * CSS `transform` for pan/zoom, so a plain fixed-position backdrop would be + * confined to the node's box. A native `` shown via `showModal()` + * escapes that via the browser's top layer, same fix as bias-annotations. + */ + private readonly simpleEditorDialog = viewChild>('simpleEditorDialog'); + constructor() { effect(() => { const descriptorSignal = (this.blocksService as BlocksService & { @@ -214,6 +222,19 @@ export class GenericNodeComponent implements OnDestroy { this.data.data.__biasAnnotationsProperty = property; } }); + + effect(() => { + const dialog = this.simpleEditorDialog()?.nativeElement; + if (dialog && typeof dialog.showModal === 'function' && !dialog.open) { + dialog.showModal(); + } + }); + } + + onSimpleEditorDialogClick(event: MouseEvent) { + if (event.target === this.simpleEditorDialog()?.nativeElement) { + this.closeSimpleParamEditor(event); + } } ngOnInit() { diff --git a/src/styles.css b/src/styles.css index a02bd28..1ae09f4 100644 --- a/src/styles.css +++ b/src/styles.css @@ -166,7 +166,17 @@ body.node-focus-modal-open { display: flex; align-items: center; justify-content: center; + width: 100vw; + height: 100vh; + max-width: 100vw; + max-height: 100vh; + margin: 0; padding: 12px; + border: none; + background: transparent; + color: inherit; +} +.llm-modal-backdrop::backdrop { background: rgba(15, 23, 42, 0.45); }