mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
fix(tabs): review fixes for the detailed rail — width-dialog default, compact wrap pass, rich-aware resets
Three review findings on the detailed-rows feature, all in its edge cases: - The App Settings width select consulted the handheld defaults blob (tabRailWidth: 256) BEFORE the rich-aware default, which the renderer never reads — so a tablet's unsized rich rail rendered 320 while the dialog said 256, and a routine Save persisted the 256 (below the 288px tight threshold, permanently). The chain now mirrors applyTabRailWidth()'s actual resolution. - _setTabRailWidth() re-rendered on a compact flip but never re-ran applyTabWrapSettings(), the one owner of the folder line, whose railRich input reads the compact class this function just toggled. A rich rail dragged below 240px kept emitting folder rows — persistently, for a stored width < 240, since the boot wrap pass runs before the class is first applied. The wrap pass now re-runs on the flip, with exactly one render either way. - Both reset affordances (handle dblclick, Enter on the handle) reset to the hardcoded 256 even on a rich rail, landing it below the tight threshold; both now resolve the rich-aware default (320), via a new optional defaultWidth input on resolveTabRailKeyboardWidth(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,10 @@ describe('tab rail width policy', () => {
|
||||
expect(policy.resolveKeyboardWidth({ ...base, key: 'Home' })).toBe(208);
|
||||
expect(policy.resolveKeyboardWidth({ ...base, key: 'End' })).toBe(360);
|
||||
expect(policy.resolveKeyboardWidth({ ...base, key: 'Enter' })).toBe(256);
|
||||
// Enter resets to the CALLER's effective default: a rich rail passes 320
|
||||
// (its unsized rendering width), so the reset cannot land it below the
|
||||
// 288px tight threshold the way a hardcoded 256 did.
|
||||
expect(policy.resolveKeyboardWidth({ ...base, key: 'Enter', defaultWidth: 320 })).toBe(320);
|
||||
expect(policy.resolveKeyboardWidth({ ...base, key: 'Escape' })).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -123,6 +127,61 @@ describe('tab rail resize wiring', () => {
|
||||
expect(app._tabRailResizeOwnsObserver).toBe(false);
|
||||
});
|
||||
|
||||
it('re-runs the wrap pass when the compact threshold flips, without double-rendering', () => {
|
||||
const controller = readPublic('tab-rail-resize.js');
|
||||
class FakeCodemanApp {}
|
||||
const classes = new Set<string>();
|
||||
const context = vm.createContext({
|
||||
CodemanApp: FakeCodemanApp,
|
||||
window: { CodemanTabRail: loadRailPolicy() },
|
||||
document: {
|
||||
documentElement: {
|
||||
style: { setProperty: () => {} },
|
||||
classList: {
|
||||
contains: (c: string) => classes.has(c),
|
||||
toggle: (c: string, force: boolean) => {
|
||||
if (force) classes.add(c);
|
||||
else classes.delete(c);
|
||||
return force;
|
||||
},
|
||||
},
|
||||
},
|
||||
getElementById: () => null,
|
||||
querySelector: () => null,
|
||||
},
|
||||
console,
|
||||
clearTimeout,
|
||||
setTimeout,
|
||||
});
|
||||
vm.runInContext(controller, context, { filename: 'tab-rail-resize.js' });
|
||||
const app = new FakeCodemanApp() as FakeCodemanApp & Record<string, any>;
|
||||
app._getTabRailBounds = () => ({});
|
||||
app.syncTabRailWidthSetting = vi.fn();
|
||||
app._fullRenderSessionTabs = vi.fn();
|
||||
|
||||
// Rich rail dragged below 240px: applyTabWrapSettings() owns the folder
|
||||
// line and reads the compact class this call just toggled, so it must be
|
||||
// re-consulted on the flip — and when its own conditional render fires
|
||||
// (the folder flag changed), the explicit render must not double it.
|
||||
app._tallTabsEnabled = true;
|
||||
app.applyTabWrapSettings = vi.fn(() => {
|
||||
app._tallTabsEnabled = false;
|
||||
app._fullRenderSessionTabs();
|
||||
});
|
||||
app._setTabRailWidth(210);
|
||||
expect(app.applyTabWrapSettings).toHaveBeenCalledOnce();
|
||||
expect(app._fullRenderSessionTabs).toHaveBeenCalledOnce();
|
||||
|
||||
// Flip back up with an unchanged folder flag (simple-detail rail): the
|
||||
// explicit render must still fire — the compact row-action affordance
|
||||
// changed even though the wrap pass rendered nothing.
|
||||
app.applyTabWrapSettings = vi.fn();
|
||||
app._fullRenderSessionTabs = vi.fn();
|
||||
app._setTabRailWidth(300);
|
||||
expect(app.applyTabWrapSettings).toHaveBeenCalledOnce();
|
||||
expect(app._fullRenderSessionTabs).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('keeps resize-observer ownership for pointer drags longer than the watchdog', async () => {
|
||||
vi.useFakeTimers();
|
||||
const controller = readPublic('tab-rail-resize.js');
|
||||
|
||||
Reference in New Issue
Block a user