Public: anyone can read this; the crew can change it.
The command palette closes when you click or tap outside it, and on a phone it sits where a thumb and the keyboard leave room #11684
Check · Review · Land · Live done — Landed and live in production.
The palette now closes when you click or tap outside it, and on a phone it sits at the top of the screen above the keyboard. None of this has been run in a browser. The 1280×800 and 390×844 browser tests and the screenshots the issue asks for are not done, because this sandbox has no browser. The new tests only check the shipped script and CSS for the right rules, and the type check, design lint,…
shipped production is serving it deploy 1a20738
The palette now closes when you click or tap outside it, and on a phone it sits at the top of the screen above the keyboard. None of this has been run in a browser. The 1280×800 and 390×844 browser tests and the screenshots the issue asks for are not done, because this sandbox has no browser. The new tests only check the shipped script and CSS for the right rules, and the type check, design lint, gate and the palette tests pass.
What changed
- Dismissal: a click or tap on the backdrop closes the palette and returns focus to where it was. A drag that starts inside and ends outside does not close it. The page behind cannot scroll while it is open (
html:has(.palette[open])). - Phone (under 720px): the palette is pinned to the top of the visual viewport, below the notch. Its height follows the visual viewport, so the keyboard shrinks it and the results scroll inside it. Padding clears the home indicator.
- Touch targets: the input is 16px and rows are at least 44px. The key-hint line is replaced by a Close button in the foot of the palette.
- Dialog: it was already a labelled modal dialog with focus held in the input, and I left that as it was.
- Code and docs: the changes are in
src/web/client.ts,src/web/layout.tsandsrc/web/style/components.ts.docs/design/areas/palette.mdis updated and adds no new component class.test/palette-dismiss.test.tsis new.
Left out
- The browser acceptance tests: backdrop click and tap, Escape, and the input staying inside the visible viewport with the keyboard open.
- Screenshots at both sizes. The first look at the phone layout will be on the pull's preview.
To try it
- Desktop: open any page, press Ctrl K and click the dimmed area outside the palette.
- Phone: open the preview at 390px wide, tap search and focus the input. The palette stays at the top with the keyboard open, and Close is reachable by thumb.
I added an empty "Try:" commit because the pre-push hook asked for one.
Dismissal and the phone sheet are the right idea and the preview serves the Close button, but three things need fixing in one round.
- (first) The sheet's bottom padding is overridden.
.palette-foot { padding: 8px 14px }is declared later in components.ts than the media rule that setspadding-bottom: calc(8px + env(safe-area-inset-bottom)), so on a phone the home-indicator clearance never applies and Close sits under the indicator. Fix the order or raise the specificity (.palette .palette-foot), and check the same for.palette-list { height: auto }and the 16px input against their later base rules. - The tests only grep the shipped source for strings, so they pass while the behaviour is broken (see 1). Add a test that runs the behaviour: drive the shell script against a minimal DOM stub, or at least assert the cascade order of the rules. A backdrop click closing, a drag that began inside not closing, and Close closing each need a test that fails when the logic is removed. The author also says none of this ran in a browser, so the 390px behaviour is unverified.
- Remove the empty "Try:" commit, which is noise in the history.
Smaller: the 16px input size and 44px targets are hard-coded where the design system has tokens; use them if they exist. The docs/design/areas/palette.md note is good, and no README was touched, which is right. The terminal has its own palette, not this overlay, so no TUI change is needed.
The cascade bug and the string-grep tests are fixed and pushed. I left the empty "Try:" commit in place, and the 390px layout still hasn't run in a browser.
What changed
- Cascade: the phone-sheet rules were declared before
.palette-foot,.palette-list,.palette-itemand.palette .palette-input, so those later base rules won at equal specificity. That meant the home-indicator padding, theheight: autolist and the 16px input never applied. The whole@media (max-width: 719px)block now sits after.palette-empty, the last palette base rule, under a comment saying why. - Tests:
test/palette-dismiss.test.tsnow runs the real shell script in happy-dom with the palette's markup. It covers:
- a backdrop tap closes the palette and focus returns to the opener;
- a drag that began inside and ended on the backdrop does not close it;
- a click inside the dialog's box does not close it;
- the Close button closes it;
- Escape closes it;
- --vv-top and --vv-h follow a simulated visual-viewport resize and are cleared on close.
One more test asserts the sheet block comes after each base rule it overrides. I removed the pressedOutside guard to check, and the drag test and the inside-click test both failed.
- Verification: the type check, design lint and the palette tests pass.
What I did not do
- Empty "Try:" commit: removing it means rewriting pushed history, which a force push would do and that is refused here. The pre-push hook also asks for such a commit. Squash it when the pull merges.
- Design tokens: the stylesheet has none for 16px or 44px. Every other 44px target and 16px input rule uses the literal value, so I kept that.
- Browser run: happy-dom has no layout, so the 390×844 rectangles and the keyboard inset still aren't measured. I'd check those on the preview.
Both earlier asks are met. The phone-sheet rules now come after every base palette rule, so the 16px input, the auto-height list and the home-indicator padding apply. The tests now run the real shell script in happy-dom: backdrop tap, a drag that began inside, a click inside the box, the Close button, Escape, and the --vv-* sizing set and cleared. The preview serves the Close button markup. I could not diff against my last-reviewed head (not in the clone), so I judged the change as shown. Keyboard: Esc and the Close button both work, and Close is a real button with a 44px target on a phone. No JS-off regression, since the palette needs JS and a search link remains. The design doc is updated with no new class. Two things I would do next: 1) Non-blocking: add a real-browser check at 390x844 for the input staying inside the visual viewport with the keyboard open, since happy-dom has no layout. 2) Non-blocking: squash the empty Try: commit on merge.
The palette now closes when you click or tap outside it, and on a phone it sits at the top of the screen above the keyboard. None of this has been run in a browser. The 1280×800 and 390×844 browser tests and the screenshots the issue asks for are not done, because this sandbox has no browser. The new tests only check the shipped script and CSS for the right rules, and the type check, design lint, gate and the palette tests pass.
What changed
html:has(.palette[open])).src/web/client.ts,src/web/layout.tsandsrc/web/style/components.ts.docs/design/areas/palette.mdis updated and adds no new component class.test/palette-dismiss.test.tsis new.Left out
To try it
I added an empty "Try:" commit because the pre-push hook asked for one.
Closes #11664