Skip to content

Commit 92b2ca0

Browse files
authored
fix(app): stop :has() rules restyling every ancestor on DOM insertion (#60521)
1 parent 1e03c36 commit 92b2ca0

3 files changed

Lines changed: 15 additions & 4 deletions

File tree

‎packages/app/src/settings/settings.css‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -846,16 +846,22 @@
846846
justify-content: flex-end;
847847
}
848848

849-
[data-slot="settings-row-control"] > div:has([data-component="switch"]),
849+
/* The :has() belongs on the control, not on its div. Chromium checks a div:has() subject against every div in the
850+
document and flags each one, then restyles a flagged div whenever an element is inserted anywhere beneath it, which
851+
is every ancestor of a streaming answer. */
852+
[data-slot="settings-row-control"]:has(> div [data-component="switch"]) > div,
850853
[data-slot="settings-row-control"] > [data-component="switch"] {
851854
display: inline-flex;
852855
align-items: center;
853856
padding: 4px;
854857
}
855858

859+
[data-component="settings-list"][data-variant="catalog"]
860+
[data-slot="settings-row-control"]:has(> div [data-component="switch"])
861+
> div,
856862
[data-component="settings-list"][data-variant="catalog"]
857863
[data-slot="settings-row-control"]
858-
> :is(div:has([data-component="switch"]), [data-component="switch"]) {
864+
> [data-component="switch"] {
859865
padding: 0;
860866
}
861867

‎packages/ui/src/components/image-preview.css‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,9 @@
182182
}
183183

184184
/* A modal Kobalte dialog turns the body's pointer events off and only restores them when its content unmounts, which
185-
the closing flight above holds back; the page takes clicks again as soon as the close starts. */
186-
body:has([data-component="image-preview"] [data-slot="image-preview-content"][data-closed]) {
185+
the closing flight above holds back; the page takes clicks again as soon as the close starts. The preview marks the
186+
body itself: a body:has() rule made Chromium restyle the body on every DOM insertion anywhere in the page. */
187+
body[data-image-preview-closing] {
187188
pointer-events: auto !important;
188189
}
189190

‎packages/ui/src/components/image-preview.tsx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,12 +405,16 @@ export function ImagePreview(props: ImagePreviewProps) {
405405
settle()
406406
showOrigin()
407407
giveBack()
408+
document.body.removeAttribute("data-image-preview-closing")
408409
})
409410

410411
createEffect(
411412
on(
412413
() => dialog.isOpen(),
413414
(open) => {
415+
// See image-preview.css: the body takes clicks again while the closing flight holds the dialog mounted.
416+
document.body.toggleAttribute("data-image-preview-closing", !open)
417+
414418
if (!open) dismiss()
415419
},
416420
{ defer: true },

0 commit comments

Comments
 (0)