fix(design): the saved-view chip on one line, one Escape per layer, the /watch action row (E28 S3d)

- SelectTrigger lays its toolbar value out as a row; the saved-view chip passes its glyph and
  modified dot through the icon/trailing slots (an <svg> is display:block and broke the chip in two).
- One Escape in a dialog's open list closed the list AND the dialog: the list's close flushes
  synchronously and pops its layer before the dialog's window listener runs. takeEscape() is the one
  close-on-Escape test (topmost AND not yet taken); Modal, the Welcome lightbox and useLayer use it,
  and keymap.dispatch ignores a taken Escape.
- /watch: the Download sits on the toolbar rung, level with the Repeat chip.
This commit is contained in:
2026-09-25 01:40:45 +02:00
parent 1833f594cb
commit b4a6569d0d
12 changed files with 144 additions and 26 deletions
+2 -2
View File
@@ -3,7 +3,7 @@ import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import { X } from "lucide-react";
import { useBackToClose } from "../../lib/history";
import { anyBlockingLayerAbove, pushLayer, removeLayer, isTopmost } from "../../lib/layerStack";
import { anyBlockingLayerAbove, pushLayer, removeLayer, takeEscape } from "../../lib/layerStack";
import { useFullscreenPortalHost } from "../../lib/fullscreen";
import { trapTab, useDialogChrome } from "./dialogFocus";
import { IconButton } from "./IconButton";
@@ -63,7 +63,7 @@ export default function Modal({
useEffect(() => {
const id = pushLayer();
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape" && isTopmost(id)) {
if (takeEscape(e, id)) {
e.stopPropagation();
onCloseRef.current();
return;