Files
dbx/apps/desktop/src/lib/tabs/editorToolbarLayout.ts
T

61 lines
2.9 KiB
TypeScript

/**
* Progressive condensation for the per-group SQL editor toolbar.
*
* The tier is NOT derived from fixed width breakpoints — the control set
* 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 0: full layout.
* - Tier 1: secondary edit/entry actions (compress, keyword case, semantic
* diagnostics, open SQL, import archive, paste-in-condition, multi-execute)
* move into the overflow menu.
* - Tier 2: format and the database helper buttons (clear / set-default) join
* the overflow menu.
* - Tier 3: the explain-analyze toggle and the schema/catalog selectors leave
* the row; the row keeps execute, explain, save, transaction controls, the
* connection and database selectors (hard-truncated), and the overflow menu.
*/
export type EditorToolbarTier = 0 | 1 | 2 | 3;
export const EDITOR_TOOLBAR_MAX_TIER = 3;
/** Slack (px) required before giving a tier back — absorbs rendering jitter. */
export const EDITOR_TOOLBAR_STEP_DOWN_SLACK_PX = 48;
/** How much wider the pane must grow (px) vs the last condensation before stepping down. */
export const EDITOR_TOOLBAR_STEP_DOWN_MIN_GROWTH_PX = 64;
export interface EditorToolbarTierInput {
tier: EditorToolbarTier;
/** Measured inner width of the toolbar row. */
availableWidth: number;
/** Measured extent of the row's content (scrollWidth), including overflow. */
contentWidth: number;
/** Toolbar width when the current tier was condensed into; anchors step-down hysteresis. */
condensedAtWidth?: 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.
*/
export function resolveNextEditorToolbarTier(input: EditorToolbarTierInput): EditorToolbarTier {
const { tier, availableWidth, contentWidth, condensedAtWidth = 0 } = input;
if (!Number.isFinite(availableWidth) || !Number.isFinite(contentWidth) || availableWidth <= 0 || contentWidth <= 0) {
// Unmeasured (first paint, hosts without ResizeObserver) keeps the current tier.
return tier;
}
if (contentWidth > availableWidth && tier < EDITOR_TOOLBAR_MAX_TIER) {
return (tier + 1) 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;
}
return tier;
}