diff --git a/frontend/src/lib/components/common/tabs/Tab.svelte b/frontend/src/lib/components/common/tabs/Tab.svelte index a652525b45..edb1135bbc 100644 --- a/frontend/src/lib/components/common/tabs/Tab.svelte +++ b/frontend/src/lib/components/common/tabs/Tab.svelte @@ -99,6 +99,7 @@ }} {disabled} {id} + data-tab-selected={isSelected ? 'true' : undefined} >
('[data-tab-selected="true"]') + bar = el ? { x: el.offsetLeft, w: el.offsetWidth } : { x: bar.x, w: 0 } + } + + // Placing the bar for the first paint. Every later move comes from the observers below: a + // Tab marks itself selected in its own update, which has not run when an effect here does, + // so measuring from this side alone lands the bar on the tab that was selected before. + $effect(() => { + if (!slidingIndicator) return + void row + measureBar() + }) + + $effect(() => { + if (!slidingIndicator || !row) return + const ro = new ResizeObserver(measureBar) + ro.observe(row) + // The mark moving is the selection changing; a tab added or removed, or one that grows a + // count as its content arrives, changes what the bar has to sit on. + const mo = new MutationObserver(measureBar) + mo.observe(row, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ['data-tab-selected'] + }) + return () => { + ro.disconnect() + mo.disconnect() + } + }) + let hashValues = $derived(values ? values.map((x) => '#' + x) : undefined) function hashChange() { @@ -79,8 +129,26 @@ -
+
{@render children?.({ selected })} + {#if slidingIndicator} + + {/if}
{/if} diff --git a/frontend/src/lib/components/copilot/chat/RunScriptCard.svelte b/frontend/src/lib/components/copilot/chat/RunScriptCard.svelte index 4ae3cc9b3d..23e66e7d43 100644 --- a/frontend/src/lib/components/copilot/chat/RunScriptCard.svelte +++ b/frontend/src/lib/components/copilot/chat/RunScriptCard.svelte @@ -1,4 +1,7 @@