diff --git a/packages/ui-core/styles.css b/packages/ui-core/styles.css index 2e19022..a7b778e 100644 --- a/packages/ui-core/styles.css +++ b/packages/ui-core/styles.css @@ -2601,17 +2601,31 @@ textarea.nodedc-field__control { .nodedc-workspace-window { position: absolute; isolation: isolate; + box-sizing: border-box; display: grid; min-width: 0; min-height: 0; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; - border: 0; + border: 1px solid; + border-color: + rgb(255 255 255 / var(--nodedc-modal-glass-outline-opacity)) + rgb(255 255 255 / var(--nodedc-modal-glass-outline-soft-opacity)) + rgb(255 255 255 / var(--nodedc-modal-glass-outline-soft-opacity)) + rgb(255 255 255 / var(--nodedc-modal-glass-outline-opacity)); border-radius: var(--nodedc-radius-modal); animation: nodedc-window-in var(--nodedc-duration-normal) var(--nodedc-ease-standard); touch-action: none; } +/* Workspace windows repaint frequently while their body is selected, scrolled, + or switched between tabs. Keep their material rim on the element itself: + Chromium can briefly expose a full masked pseudo-element when it recomposites + several backdrop-filter surfaces above a WebGL canvas. */ +.nodedc-workspace-window.nodedc-glass-material::before { + content: none; +} + .nodedc-workspace-window[data-auto-height="true"]:not([data-interaction]) { transition: height var(--nodedc-duration-normal) var(--nodedc-ease-standard); } diff --git a/packages/ui-react/src/WorkspaceWindow.tsx b/packages/ui-react/src/WorkspaceWindow.tsx index 3cf706c..a03993e 100644 --- a/packages/ui-react/src/WorkspaceWindow.tsx +++ b/packages/ui-react/src/WorkspaceWindow.tsx @@ -321,7 +321,7 @@ export function WorkspaceWindow({ return (
{ assert.match(dropdownRule, /overflow:\s*auto;/); assert.match(dropdownRule, /overscroll-behavior:\s*contain;/); }); + +test("workspace windows keep their glass rim without masked compositor overlays", async () => { + const [workspace, styles] = await Promise.all([ + readFile(new URL("../packages/ui-react/src/WorkspaceWindow.tsx", import.meta.url), "utf8"), + readFile(new URL("../packages/ui-core/styles.css", import.meta.url), "utf8"), + ]); + const rootClass = workspace.match(/className=\{cn\("(?[^"]+)"/)?.groups?.classes ?? ""; + const windowRule = styles.match(/\.nodedc-workspace-window \{(?[\s\S]*?)\n\}/)?.groups?.body ?? ""; + const materialOverride = styles.match(/\.nodedc-workspace-window\.nodedc-glass-material::before \{(?[\s\S]*?)\n\}/)?.groups?.body ?? ""; + + assert.match(rootClass, /\bnodedc-glass-material\b/); + assert.doesNotMatch(rootClass, /\bnodedc-material-rim\b/); + assert.match(windowRule, /box-sizing:\s*border-box;/); + assert.match(windowRule, /border:\s*1px solid;/); + assert.match(windowRule, /border-color:[\s\S]*--nodedc-modal-glass-outline-opacity/); + assert.match(materialOverride, /content:\s*none;/); + assert.doesNotMatch(materialOverride, /mask/); +});