fix(rail): keep the inline rename editor unclamped in the detailed rail

The card-row rule (line-clamp: 3) out-ranked the shared unclamp-while-renaming
override. Restate it at the same weight; the test now covers both rail layouts.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Devvyn
2026-10-05 07:02:47 +08:00
co-authored by Claude Sonnet 5.5
parent ffaa5ee80c
commit 6944f842c7
3 changed files with 73 additions and 45 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"aicodeman": patch
---
Renaming a session in the detailed vertical tab rail no longer leaves the 3-line name clamp on the inline editor: the card-row rule out-ranked the "unclamp while renaming" override.
+11
View File
@@ -18815,6 +18815,17 @@ html[data-tab-orientation='vertical'][data-tab-rail-detail='rich']:not(.tab-rail
line-clamp: 3; line-clamp: 3;
} }
/* The rule above out-ranks the shared "unclamp while renaming" override (it carries four more
selectors of specificity), so a detailed-rail row kept its 3-line clamp around the inline
editor. Restate the override at the same weight; it must stay AFTER the rule it beats. */
html[data-tab-orientation='vertical'][data-tab-rail-detail='rich']:not(.tab-rail-compact)
.tab-rail
.session-tab
.tab-name.tab-name-renaming {
-webkit-line-clamp: unset;
line-clamp: unset;
}
html[data-tab-orientation='vertical'][data-tab-rail-detail='rich']:not(.tab-rail-compact) .tab-rail .session-tab .tab-folder { html[data-tab-orientation='vertical'][data-tab-rail-detail='rich']:not(.tab-rail-compact) .tab-rail .session-tab .tab-folder {
font-size: 0.66rem; font-size: 0.66rem;
margin-top: 0.1rem; margin-top: 0.1rem;
+57 -45
View File
@@ -581,54 +581,66 @@ describe('Inline rename input', () => {
expect(await input.evaluate((node) => node.getBoundingClientRect().width)).toBeGreaterThan(0); expect(await input.evaluate((node) => node.getBoundingClientRect().width)).toBeGreaterThan(0);
}); });
it('Vertical rail paints typing in an unclamped editor and restores the clamp on cancel', async () => { // Both rail layouts: the simple rows clamp a name to 2 lines, the detailed (default) card rows to 3.
await resetState(); // The detailed rule out-ranks the shared "unclamp while renaming" override unless it is restated.
const id = 'vertical-live-input'; it.each([
['simple', '2'],
['rich', '3'],
])(
'Vertical %s rail paints typing in an unclamped editor and restores its clamp on cancel',
async (detail, clamp) => {
await resetState();
const id = `vertical-live-input-${detail}`;
await page.evaluate((sessionId) => { await page.evaluate(
const app = ( ({ sessionId, railDetail }) => {
window as unknown as { const app = (
app: { window as unknown as {
sessions: Map<string, { id: string; name: string }>; app: {
startInlineRename: (id: string) => void; sessions: Map<string, { id: string; name: string }>;
}; startInlineRename: (id: string) => void;
} };
).app; }
document.documentElement.dataset.tabOrientation = 'vertical'; ).app;
const rail = document.getElementById('tabRail') as HTMLElement; document.documentElement.dataset.tabOrientation = 'vertical';
const tab = document.createElement('div'); document.documentElement.dataset.tabRailDetail = railDetail;
tab.setAttribute('data-test-tab', '1'); const rail = document.getElementById('tabRail') as HTMLElement;
tab.className = 'session-tab'; const tab = document.createElement('div');
tab.innerHTML = tab.setAttribute('data-test-tab', '1');
`<span class="tab-name" data-session-id="${sessionId}">` + tab.className = 'session-tab';
'<span class="tab-name-prefix">w9-case: </span>old</span>'; tab.innerHTML =
rail.appendChild(tab); `<span class="tab-name" data-session-id="${sessionId}">` +
app.sessions.set(sessionId, { id: sessionId, name: 'w9-case: old' }); '<span class="tab-name-prefix">w9-case: </span>old</span>';
app.startInlineRename(sessionId); rail.appendChild(tab);
}, id); app.sessions.set(sessionId, { id: sessionId, name: 'w9-case: old' });
app.startInlineRename(sessionId);
},
{ sessionId: id, railDetail: detail }
);
const label = page.locator(`.tab-name[data-session-id="${id}"]`); const label = page.locator(`.tab-name[data-session-id="${id}"]`);
const input = label.locator('input.tab-rename-input'); const input = label.locator('input.tab-rename-input');
await input.press(process.platform === 'darwin' ? 'Meta+A' : 'Control+A'); await input.press(process.platform === 'darwin' ? 'Meta+A' : 'Control+A');
await page.keyboard.type('edited title'); await page.keyboard.type('edited title');
expect(await input.inputValue()).toBe('edited title'); expect(await input.inputValue()).toBe('edited title');
expect(await input.evaluate((node) => document.activeElement === node)).toBe(true); expect(await input.evaluate((node) => document.activeElement === node)).toBe(true);
expect(await label.evaluate((node) => node.classList.contains('tab-name-renaming'))).toBe(true); expect(await label.evaluate((node) => node.classList.contains('tab-name-renaming'))).toBe(true);
expect(await label.evaluate((node) => getComputedStyle(node).webkitLineClamp)).toBe('none'); expect(await label.evaluate((node) => getComputedStyle(node).webkitLineClamp)).toBe('none');
expect(await input.evaluate((node) => node.getBoundingClientRect().width)).toBeGreaterThan(0); expect(await input.evaluate((node) => node.getBoundingClientRect().width)).toBeGreaterThan(0);
const settled = await page.evaluate((sessionId) => { const settled = await page.evaluate((sessionId) => {
const app = (window as unknown as { app: { _activeRename: { cancel: () => void } | null } }).app; const app = (window as unknown as { app: { _activeRename: { cancel: () => void } | null } }).app;
app._activeRename?.cancel(); app._activeRename?.cancel();
const label = document.querySelector(`.tab-name[data-session-id="${sessionId}"]`) as HTMLElement; const label = document.querySelector(`.tab-name[data-session-id="${sessionId}"]`) as HTMLElement;
return { return {
classActive: label.classList.contains('tab-name-renaming'), classActive: label.classList.contains('tab-name-renaming'),
inputPresent: !!label.querySelector('input.tab-rename-input'), inputPresent: !!label.querySelector('input.tab-rename-input'),
webkitLineClamp: getComputedStyle(label).webkitLineClamp, webkitLineClamp: getComputedStyle(label).webkitLineClamp,
}; };
}, id); }, id);
expect(settled).toEqual({ classActive: false, inputPresent: false, webkitLineClamp: '2' }); expect(settled).toEqual({ classActive: false, inputPresent: false, webkitLineClamp: clamp });
}); }
);
}); });