mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-28 04:16:50 +08:00
fix(web): let the docked assistant button collapse again
`shouldCollapseRail` was keyed on `!railExpanded`, mirroring the expand helper instead of negating it. Once a hover revealed the button it could never collapse back into the rail, so the collapse looked broken after the first restore. Key the predicate on `railExpanded` being true, restore the mirror relationship with `shouldExpandRail`, and add regression coverage for the expand -> leave -> collapse round trip. Also lengthen the rail strip.
This commit is contained in:
@@ -505,7 +505,7 @@ function AssistantPanel({ storageKey }: { storageKey: string }) {
|
||||
<span
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
className={`pointer-events-none absolute top-1/2 h-6 -translate-y-1/2 rounded-full bg-[#3b82f6] shadow-md ${
|
||||
className={`pointer-events-none absolute top-1/2 h-14 -translate-y-1/2 rounded-full bg-[#3b82f6] shadow-md ${
|
||||
dockedEdge === 'right' ? 'right-0' : 'left-0'
|
||||
}`}
|
||||
style={{ width: ASSISTANT_RAIL_WIDTH }}
|
||||
|
||||
@@ -55,25 +55,34 @@ export type AssistantHoverInput = {
|
||||
dragging: boolean;
|
||||
};
|
||||
|
||||
/** Hovering any part of the control must reveal the full button again. */
|
||||
/** Distance to the viewport edge that snaps the button into the rail. */
|
||||
|
||||
/**
|
||||
* Hovering any part of the control must reveal the full button again.
|
||||
* Only a docked *and still collapsed* button needs to expand, so a pointer that
|
||||
* merely jitters inside an already expanded button does no state churn.
|
||||
*/
|
||||
export function shouldExpandRail(input: AssistantHoverInput): boolean {
|
||||
if (input.dragging) return false;
|
||||
return !!input.dockedEdge && !input.railExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* A docked button collapses to the strip only when it is idle and the pointer
|
||||
* has left. The panel being open pins it, because the popover is anchored.
|
||||
* A docked button collapses to the strip when the pointer leaves. This is the
|
||||
* mirror of `shouldExpandRail` and is keyed on `railExpanded` being *true* —
|
||||
* the earlier `!railExpanded` form made a revealed button impossible to
|
||||
* re-collapse, which is the bug this guards against. The panel being open pins
|
||||
* it, because the popover stays anchored to the button.
|
||||
*/
|
||||
export function shouldCollapseRail(input: AssistantHoverInput): boolean {
|
||||
if (input.dragging) return false;
|
||||
return !!input.dockedEdge && !input.railExpanded;
|
||||
return !!input.dockedEdge && input.railExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* After a drop the button always starts collapsed, even though the pointer is
|
||||
* still over it. The next pointermove re-expands it, which avoids the
|
||||
* "drops under the cursor and never comes back" race.
|
||||
* still over it. The rail is then held collapsed until the pointer exits, which
|
||||
* avoids the "drops under the cursor and never comes back" race.
|
||||
*/
|
||||
export function restingRailExpanded(): boolean {
|
||||
return false;
|
||||
|
||||
@@ -102,15 +102,34 @@ test('a drag in progress never expands or collapses the rail', () => {
|
||||
assert.equal(shouldCollapseRail(dragging), false);
|
||||
});
|
||||
|
||||
test('a docked, idle button is the only state that collapses', () => {
|
||||
test('only an *expanded* docked button collapses when the pointer leaves', () => {
|
||||
// Regression: keying this on `!railExpanded` made a revealed button
|
||||
// impossible to collapse again, so it stayed open forever after one hover.
|
||||
assert.equal(
|
||||
shouldCollapseRail({ dockedEdge: 'left', railExpanded: false, dragging: false }),
|
||||
shouldCollapseRail({ dockedEdge: 'left', railExpanded: true, dragging: false }),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
shouldCollapseRail({ dockedEdge: null, railExpanded: false, dragging: false }),
|
||||
shouldCollapseRail({ dockedEdge: 'left', railExpanded: false, dragging: false }),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
shouldCollapseRail({ dockedEdge: null, railExpanded: true, dragging: false }),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test('expand then leave round-trips back to the collapsed rail', () => {
|
||||
const docked = { dockedEdge: 'right', railExpanded: false, dragging: false };
|
||||
// Hover: reveal the button.
|
||||
assert.equal(shouldExpandRail(docked), true);
|
||||
// Pointer leaves: the revealed button must collapse again.
|
||||
assert.equal(
|
||||
shouldCollapseRail({ ...docked, railExpanded: true }),
|
||||
true,
|
||||
);
|
||||
// A second hover re-reveals it, so the cycle is repeatable.
|
||||
assert.equal(shouldExpandRail(docked), true);
|
||||
});
|
||||
|
||||
test('dropping always starts collapsed so the rail is never stuck open', () => {
|
||||
|
||||
Reference in New Issue
Block a user