fix(palette): the ⌘K search box typed black on black (BEA-54) (#106)

This commit is contained in:
Snow Lee (Sungwon)
2026-07-31 17:38:12 +09:00
committed by GitHub
parent a84fe444f5
commit 9a52aed3bb
7 changed files with 53 additions and 28 deletions
@@ -153,6 +153,24 @@ test("palette (⌘K) fuzzy-jumps to a file", async ({ page }) => {
await expect(page.locator("#content h1")).toHaveText("Topic");
});
// BEA-54: cmdk overwrites the `id` we pass its primitives, so every palette
// rule anchored on one was dead — the input lost its only author `color` and
// fell back to the UA's black. Anchors here are ours (#palette) or cmdk's own
// attributes, which is exactly what the fix relies on.
test("palette renders in the dark palette, not UA black (BEA-54)", async ({ page }) => {
await login(page);
await wikiId(page);
await page.keyboard.press("ControlOrMeta+k");
const input = page.locator("#palette input");
await input.fill("topic");
await expect(input).toHaveCSS("color", "rgb(238, 240, 243)"); // --text, was rgb(0, 0, 0)
const sel = page.locator("#palette [cmdk-item][data-selected='true']");
await expect(sel.locator(".plabel")).toHaveCSS("color", "rgb(255, 207, 133)"); // --accent-bright
await expect(sel.locator(".pkind")).toHaveCSS("text-transform", "uppercase");
await expect(sel).toHaveCSS("background-color", "rgba(245, 166, 35, 0.13)"); // --glow
await page.keyboard.press("Escape");
});
test("share mints a public link that serves the file, revoke kills it", async ({ page }) => {
await login(page);
const pid = await wikiId(page);
@@ -103,8 +103,10 @@ export function Palette({
<Command shouldFilter={false} loop>
<div id="palette-inputwrap">
<Icon name="search" />
{/* No id here (nor on CommandList): cmdk writes its own after our
props, so one never reaches the DOM. Style off #palette /
#palette-inputwrap or [cmdk-*] instead. (BEA-54) */}
<CommandInput
id="palette-input"
placeholder="Search file names, projects, actions…"
autoComplete="off"
spellCheck={false}
@@ -112,7 +114,7 @@ export function Palette({
onValueChange={setQuery}
/>
</div>
<CommandList id="palette-results">
<CommandList>
{items.length === 0 ? (
<div className="pempty">No matches search covers file names, projects, and actions</div>
) : (
+27 -22
View File
@@ -2,6 +2,11 @@
Design language: Linear-grade restraint; the one accent (honey) is spent
only on active state, the live/brand mark, and the palette selection. */
:root {
/* The app is dark-only. Without this, anything the UA paints itself —
scrollbars, autofill, select/date popups, and any control that loses its
author `color` — resolves in the light scheme. That trapdoor is how
BEA-54 turned one dead selector into black-on-black text. */
color-scheme: dark;
--bg: #0a0b0d; /* main ground */
--bg-side: #0c0e10; /* sidebar / panels */
--bg-raise: #15171b; /* palette, modals, elevated cards */
@@ -82,7 +87,7 @@ body {
[role="dialog"] input[aria-invalid="true"] { border-color: var(--del); }
[role="dialog"] input[aria-invalid="true"]:focus-visible { outline-color: var(--del); }
button:disabled, .btn:disabled { cursor: default; }
input[type="checkbox"] { accent-color: var(--accent); width: 20px; height: 20px; color-scheme: dark; }
input[type="checkbox"] { accent-color: var(--accent); width: 20px; height: 20px; }
.sr-only {
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
@@ -721,27 +726,27 @@ a.ai-main:hover { color: var(--accent); }
#palette-inputwrap { display: flex; align-items: center; gap: 11px; padding: 14px 16px; border-bottom: 1px solid var(--border); }
#palette-inputwrap [data-slot="command-input-wrapper"] { flex: 1; display: flex; border-bottom: 0; padding: 0; height: auto; }
#palette-inputwrap [data-slot="command-input-wrapper"] > svg:not(.ico) { display: none; }
#palette input, #palette input:focus { border: none; background: transparent; box-shadow: none; outline: none; padding: 0; }
/* Never anchor palette rules on an id handed to a cmdk primitive: cmdk
spreads caller props and then writes its own generated `id`, so
`#palette-input` / `#palette-results` silently stopped matching at the
cmdk migration (b7ce76b) and the input fell back to the UA's black
`fieldtext`. `#palette` / `#palette-inputwrap` are our own elements and
survive; `[cmdk-*]` are cmdk's documented styling hooks. (BEA-54) */
#palette input, #palette input:focus { flex: 1; width: 100%; border: none; background: transparent; box-shadow: none; color: var(--text); font: inherit; font-size: 15px; letter-spacing: -.01em; outline: none; padding: 0; }
#palette input::placeholder { color: var(--text-ghost); }
#palette-inputwrap .ico { width: 17px; height: 17px; color: var(--text-faint); }
#palette-input { flex: 1; width: 100%; border: none; background: transparent; color: var(--text); font: inherit; font-size: 15px; letter-spacing: -.01em; outline: none; padding: 0; }
#palette-input::placeholder { color: var(--text-ghost); }
#palette-results { list-style: none; margin: 0; padding: 8px; max-height: 46vh; overflow-y: auto; }
#palette-results [cmdk-item] { display: flex; align-items: center; gap: 11px; height: 38px; padding: 0 10px; border-radius: 9px; cursor: pointer; color: var(--text-dim); font-size: 13.5px; }
#palette-results [cmdk-item][data-selected="true"] { background: var(--glow); }
#palette-results [cmdk-item][data-selected="true"] .picon { color: var(--accent); }
#palette-results [cmdk-item][data-selected="true"] .plabel { color: var(--accent-bright); }
#palette-results [cmdk-item][data-selected="true"] .plabel b { color: var(--accent-bright); }
#palette-results li { display: flex; align-items: center; gap: 11px; height: 38px; padding: 0 10px; border-radius: 9px; cursor: pointer; color: var(--text-dim); font-size: 13.5px; }
#palette-results li.selected { background: var(--glow); }
#palette-results li.selected .picon { color: var(--accent); }
#palette-results li.selected .plabel { color: var(--accent-bright); }
#palette-results li.selected .plabel b { color: var(--accent-bright); }
#palette-results li .picon { width: 18px; flex: none; display: flex; justify-content: center; color: var(--text-faint); }
#palette-results li .picon .ico { width: 15px; height: 15px; }
#palette-results li .plabel { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
#palette-results li .plabel b { color: var(--accent-bright); font-weight: 600; }
#palette-results li .pkind { flex: none; font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-ghost); }
#palette-results .pempty { color: var(--text-faint); cursor: default; justify-content: center; height: auto; padding: 14px; }
#palette [cmdk-list] { list-style: none; margin: 0; padding: 8px; max-height: 46vh; overflow-y: auto; }
#palette [cmdk-item] { display: flex; align-items: center; gap: 11px; height: 38px; padding: 0 10px; border-radius: 9px; cursor: pointer; color: var(--text-dim); font-size: 13.5px; }
#palette [cmdk-item][data-selected="true"] { background: var(--glow); }
#palette [cmdk-item][data-selected="true"] .picon { color: var(--accent); }
#palette [cmdk-item][data-selected="true"] .plabel { color: var(--accent-bright); }
#palette [cmdk-item][data-selected="true"] .plabel b { color: var(--accent-bright); }
#palette [cmdk-item] .picon { width: 18px; flex: none; display: flex; justify-content: center; color: var(--text-faint); }
#palette [cmdk-item] .picon .ico { width: 15px; height: 15px; }
#palette [cmdk-item] .plabel { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
#palette [cmdk-item] .plabel b { color: var(--accent-bright); font-weight: 600; }
#palette [cmdk-item] .pkind { flex: none; font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-ghost); }
#palette [cmdk-list] .pempty { color: var(--text-faint); cursor: default; justify-content: center; height: auto; padding: 14px; }
#palette-hint { padding: 9px 16px; border-top: 1px solid var(--border); font-size: 11px; color: var(--text-ghost); }
/* ---- modal ---- */
@@ -878,7 +883,7 @@ a.ai-main:hover { color: var(--accent); }
.modal-actions button { height: auto; min-height: 44px; }
.modal-expiry select { height: 44px; }
.pbtn { height: auto; min-height: 44px; }
#palette-results li { height: auto; min-height: 44px; }
#palette [cmdk-item] { height: auto; min-height: 44px; }
.more-item { min-height: 44px; }
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -5,8 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>BearDrive</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='%23f5a623'><rect x='4' y='4' width='5.6' height='24'/><rect x='11.2' y='4' width='14.4' height='11.2'/><rect x='11.2' y='16.8' width='16.8' height='11.2'/></svg>">
<script type="module" crossorigin src="/assets/index-BlfX6Osf.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BZ355MrB.css">
<script type="module" crossorigin src="/assets/index-gtPH5RQg.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-qQY6rBYF.css">
</head>
<body>
<div id="root"></div>