fix(ui): responsive table info sidebar and SQL toolbar layout

This commit is contained in:
zipg authored and GitHub committed 2026-09-07 21:26:11 +08:00
1 parent e3b9bae67e
commit 96a3dc052a
5 files changed
+60 -10

No files matched your search

@@ -22,6 +22,40 @@ describe("editor toolbar measured condensation", () => {
expect(resolveNextEditorToolbarTier({ tier: 2, availableWidth: grown, contentWidth: grown - EDITOR_TOOLBAR_STEP_DOWN_SLACK_PX - 10, condensedAtWidth: 400 })).toBe(1);
});
it("restores the fullest measured tier that fits after the pane expands", () => {
expect(
resolveNextEditorToolbarTier({
tier: 3,
availableWidth: 920,
contentWidth: 920,
condensedAtWidth: 420,
expandedTierRequiredWidths: { 0: 840, 1: 700, 2: 560 },
}),
).toBe(0);
expect(
resolveNextEditorToolbarTier({
tier: 3,
availableWidth: 760,
contentWidth: 760,
condensedAtWidth: 420,
expandedTierRequiredWidths: { 0: 840, 1: 700, 2: 560 },
}),
).toBe(1);
});
it("does not use the condensed flex row width to restore a tier that cannot fit", () => {
expect(
resolveNextEditorToolbarTier({
tier: 2,
availableWidth: 720,
contentWidth: 720,
condensedAtWidth: 420,
expandedTierRequiredWidths: { 0: 840, 1: 700 },
}),
).toBe(2);
});
it("never oscillates: slack alone without pane growth keeps the condensed tier", () => {
// The row fits with plenty of slack, but the pane barely grew since the
// toolbar condensed at this width — stepping down would overflow again.
@@ -5,9 +5,9 @@
* changes per database type, transaction state, and feature flags, so any
* static guess would over- or under-condense. Instead the toolbar measures its
* own row: while the content overflows the available width it steps up one
* tier (moving controls into the overflow menu); it only steps back down when
* there is real slack AND the pane has grown meaningfully since the last
* condensation, so a static narrow layout can never oscillate.
* tier (moving controls into the overflow menu). Each expanded tier's measured
* requirement is retained, so the toolbar can restore the fullest tier that
* fits without relying on scrollWidth from the already-condensed flex row.
*
* - Tier 0: full layout.
* - Tier 1: secondary edit/entry actions (compress, keyword case, semantic
@@ -36,16 +36,18 @@ export interface EditorToolbarTierInput {
contentWidth: number;
/** Toolbar width when the current tier was condensed into; anchors step-down hysteresis. */
condensedAtWidth?: number;
/** Required widths captured immediately before each tier was condensed. */
expandedTierRequiredWidths?: Partial<Record<EditorToolbarTier, number>>;
}
/**
* Resolves the next toolbar tier from real measurements. Monotonic per
* measurement — repeated calls after a tier change converge instead of
* oscillating, because stepping down additionally requires the pane to have
* grown by EDITOR_TOOLBAR_STEP_DOWN_MIN_GROWTH_PX since the last step up.
* measurement. Known expanded-tier widths allow a widened pane to restore the
* best fitting tier in one render; the growth-based branch remains as a safe
* fallback for callers without historical measurements.
*/
export function resolveNextEditorToolbarTier(input: EditorToolbarTierInput): EditorToolbarTier {
const { tier, availableWidth, contentWidth, condensedAtWidth = 0 } = input;
const { tier, availableWidth, contentWidth, condensedAtWidth = 0, expandedTierRequiredWidths } = input;
if (!Number.isFinite(availableWidth) || !Number.isFinite(contentWidth) || availableWidth <= 0 || contentWidth <= 0) {
// Unmeasured (first paint, hosts without ResizeObserver) keeps the current tier.
return tier;
@@ -53,6 +55,14 @@ export function resolveNextEditorToolbarTier(input: EditorToolbarTierInput): Edi
if (contentWidth > availableWidth && tier < EDITOR_TOOLBAR_MAX_TIER) {
return (tier + 1) as EditorToolbarTier;
}
if (tier > 0 && expandedTierRequiredWidths) {
for (let candidate = 0; candidate < tier; candidate += 1) {
const requiredWidth = expandedTierRequiredWidths[candidate as EditorToolbarTier];
if (requiredWidth && availableWidth >= requiredWidth + EDITOR_TOOLBAR_STEP_DOWN_SLACK_PX) {
return candidate as EditorToolbarTier;
}
}
}
if (tier > 0 && availableWidth - contentWidth >= EDITOR_TOOLBAR_STEP_DOWN_SLACK_PX && availableWidth - condensedAtWidth >= EDITOR_TOOLBAR_STEP_DOWN_MIN_GROWTH_PX) {
return (tier - 1) as EditorToolbarTier;
}