fix(ui): keep a callee row hidden until the rail has been measured (CG-44)
A row's position comes from measuring the laid-out DOM, so between Svelte creating it and the first relayout it has no place to be. Drawing it at top: 0 stacks the whole rail at its head for a frame; keeping the previous symbol's coordinates is worse. It stays invisible until it has been placed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5cecaabfc2
commit
e9596af1cf
@@ -22,6 +22,8 @@
|
|||||||
tops: number[];
|
tops: number[];
|
||||||
foldTop: number;
|
foldTop: number;
|
||||||
noteTop: number;
|
noteTop: number;
|
||||||
|
/** False until the view has measured the rail — see SymbolView. */
|
||||||
|
placed: boolean;
|
||||||
/** The focal symbol's file — a callee in it reads "same file", not a path. */
|
/** The focal symbol's file — a callee in it reads "same file", not a path. */
|
||||||
focalFile: string;
|
focalFile: string;
|
||||||
/** The symbol this one was reached from, when it is a callee. */
|
/** The symbol this one was reached from, when it is a callee. */
|
||||||
@@ -31,7 +33,7 @@
|
|||||||
onstepDown: (node: WireNodeRef) => void;
|
onstepDown: (node: WireNodeRef) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { model, tops, foldTop, noteTop, focalFile, originId, emptyReason, onstepDown }: Props =
|
let { model, tops, foldTop, noteTop, placed, focalFile, originId, emptyReason, onstepDown }: Props =
|
||||||
$props();
|
$props();
|
||||||
|
|
||||||
function rowTitle(row: CalleeRow): string {
|
function rowTitle(row: CalleeRow): string {
|
||||||
@@ -51,6 +53,7 @@
|
|||||||
class:origin={node.id === originId}
|
class:origin={node.id === originId}
|
||||||
class:hot={hot.is(node.id)}
|
class:hot={hot.is(node.id)}
|
||||||
class:sel={railFocus.at('right', i)}
|
class:sel={railFocus.at('right', i)}
|
||||||
|
class:unplaced={!placed}
|
||||||
style:top={`${tops[i] ?? 0}px`}
|
style:top={`${tops[i] ?? 0}px`}
|
||||||
data-target={node.id}
|
data-target={node.id}
|
||||||
role="button"
|
role="button"
|
||||||
@@ -84,7 +87,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if model.uncertain.length > 0}
|
{#if model.uncertain.length > 0}
|
||||||
<details class="rfold" data-rail-fold style:top={`${foldTop}px`}>
|
<details class="rfold" class:unplaced={!placed} data-rail-fold style:top={`${foldTop}px`}>
|
||||||
<summary>
|
<summary>
|
||||||
Uncertain <span class="dim"
|
Uncertain <span class="dim"
|
||||||
>· {model.uncertain.length} name-only match{model.uncertain.length === 1 ? '' : 'es'},
|
>· {model.uncertain.length} name-only match{model.uncertain.length === 1 ? '' : 'es'},
|
||||||
@@ -128,7 +131,7 @@
|
|||||||
{#if model.rows.length === 0 && model.uncertain.length === 0}
|
{#if model.rows.length === 0 && model.uncertain.length === 0}
|
||||||
<div class="rnote" style:top="60px">{emptyReason}</div>
|
<div class="rnote" style:top="60px">{emptyReason}</div>
|
||||||
{:else if model.outsideCalls > 0 || model.outsideTypeRefs > 0 || model.hiddenGroups > 0}
|
{:else if model.outsideCalls > 0 || model.outsideTypeRefs > 0 || model.hiddenGroups > 0}
|
||||||
<div class="rnote" style:top={`${noteTop}px`}>
|
<div class="rnote" class:unplaced={!placed} style:top={`${noteTop}px`}>
|
||||||
{#if model.outsideCalls > 0}
|
{#if model.outsideCalls > 0}
|
||||||
+{plural(model.outsideCalls, 'more call')} into symbols outside the index{#if model.outsideTypeRefs > 0}{' '}·
|
+{plural(model.outsideCalls, 'more call')} into symbols outside the index{#if model.outsideTypeRefs > 0}{' '}·
|
||||||
{plural(model.outsideTypeRefs, 'type reference')}{/if}.
|
{plural(model.outsideTypeRefs, 'type reference')}{/if}.
|
||||||
@@ -167,6 +170,11 @@
|
|||||||
font-size: 11.5px;
|
font-size: 11.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Positioned by measurement, so it must not paint before it is measured. */
|
||||||
|
.unplaced {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.rrow {
|
.rrow {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
|
|||||||
@@ -73,6 +73,14 @@
|
|||||||
let stageMinHeight = $state(0);
|
let stageMinHeight = $state(0);
|
||||||
let connectors = $state<Connector[]>([]);
|
let connectors = $state<Connector[]>([]);
|
||||||
let overlay = $state({ width: 0, height: 0 });
|
let overlay = $state({ width: 0, height: 0 });
|
||||||
|
/**
|
||||||
|
* The rail has been measured at least once for the symbol on screen.
|
||||||
|
*
|
||||||
|
* Until it has, a row has no place to be: drawing it at `top: 0` would stack
|
||||||
|
* every row at the head of the rail for a frame, and drawing it at the
|
||||||
|
* PREVIOUS symbol's coordinates would be worse. It stays hidden instead.
|
||||||
|
*/
|
||||||
|
let placed = $state(false);
|
||||||
|
|
||||||
/* ---------------------------------------------------------------- data -- */
|
/* ---------------------------------------------------------------- data -- */
|
||||||
|
|
||||||
@@ -90,6 +98,7 @@
|
|||||||
source = null;
|
source = null;
|
||||||
railFocus.reset();
|
railFocus.reset();
|
||||||
hot.set(null);
|
hot.set(null);
|
||||||
|
placed = false;
|
||||||
void project.ensure();
|
void project.ensure();
|
||||||
|
|
||||||
let node: WireSymbolPayload;
|
let node: WireSymbolPayload;
|
||||||
@@ -322,6 +331,7 @@
|
|||||||
});
|
});
|
||||||
connectors = next;
|
connectors = next;
|
||||||
overlay = { width: inner.scrollWidth, height: Math.max(inner.offsetHeight, stageMinHeight) };
|
overlay = { width: inner.scrollWidth, height: Math.max(inner.offsetHeight, stageMinHeight) };
|
||||||
|
placed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let scheduled = false;
|
let scheduled = false;
|
||||||
@@ -460,6 +470,7 @@
|
|||||||
{tops}
|
{tops}
|
||||||
{foldTop}
|
{foldTop}
|
||||||
{noteTop}
|
{noteTop}
|
||||||
|
{placed}
|
||||||
focalFile={payload.node.file}
|
focalFile={payload.node.file}
|
||||||
originId={originRight}
|
originId={originRight}
|
||||||
emptyReason={emptyCalleeReason}
|
emptyReason={emptyCalleeReason}
|
||||||
|
|||||||
Reference in New Issue
Block a user