mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Fix virtual scrolling MenuList font family dropdowns shrinking when wider content is unmounted (#3987)
* Fix virtual scrolling MenuList dropdowns shrinking when wider content goes away * Code review fixes * Fix small CI workflow bug * Stop scrolling in dropdowns from horizontally scrolling the control bar * Use more robust way of getting commit hash in CI workflow
This commit is contained in:
@@ -47,6 +47,8 @@
|
||||
let virtualScrollingEntriesStart = 0;
|
||||
let keydownListenerAdded = false;
|
||||
let destroyed = false;
|
||||
let maxMenuWidth = 0;
|
||||
let resizeObserver: ResizeObserver | undefined = undefined;
|
||||
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- `loadedFonts` reactivity is driven by `loadedFontsGeneration`, not the Set itself
|
||||
let loadedFonts = new Set<string>();
|
||||
let loadedFontsGeneration = 0;
|
||||
@@ -77,6 +79,7 @@
|
||||
});
|
||||
onDestroy(() => {
|
||||
removeEventListener("keydown", keydown);
|
||||
resizeObserver?.disconnect();
|
||||
// Set the destroyed status in the closure kept by the awaited `tick()` in `onMount` in case that delayed run occurs after the component is destroyed
|
||||
destroyed = true;
|
||||
});
|
||||
@@ -144,6 +147,15 @@
|
||||
keydownListenerAdded = false;
|
||||
}
|
||||
|
||||
// For virtual scrolling menus, observe width changes so the menu only grows and never shrinks while open
|
||||
if (open && virtualScrolling) {
|
||||
startMenuWidthObserver();
|
||||
} else if (resizeObserver) {
|
||||
resizeObserver.disconnect();
|
||||
resizeObserver = undefined;
|
||||
maxMenuWidth = 0;
|
||||
}
|
||||
|
||||
highlighted = activeEntry;
|
||||
dispatch("open", open);
|
||||
|
||||
@@ -156,14 +168,38 @@
|
||||
});
|
||||
}
|
||||
|
||||
function watchEntriesHash(_entriesHash: bigint) {
|
||||
function watchEntriesHash(_: bigint) {
|
||||
reactiveEntries = entries;
|
||||
}
|
||||
|
||||
function watchRemeasureWidth(_: MenuListEntry[][], __: boolean) {
|
||||
// Skip re-measurement for virtual scrolling menus since ResizeObserver handles their width
|
||||
if (virtualScrolling) return;
|
||||
|
||||
self?.measureAndEmitNaturalWidth();
|
||||
}
|
||||
|
||||
async function startMenuWidthObserver() {
|
||||
await tick();
|
||||
// Guard against the menu having closed during the tick
|
||||
if (!open) return;
|
||||
|
||||
const floatingMenuContentDiv = self?.div()?.querySelector("[data-floating-menu-content]");
|
||||
if (!(floatingMenuContentDiv instanceof HTMLElement)) return;
|
||||
|
||||
maxMenuWidth = 0;
|
||||
|
||||
resizeObserver?.disconnect();
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
const width = floatingMenuContentDiv.scrollWidth;
|
||||
if (width > maxMenuWidth) {
|
||||
maxMenuWidth = width;
|
||||
floatingMenuContentDiv.style.minWidth = `${maxMenuWidth}px`;
|
||||
}
|
||||
});
|
||||
resizeObserver.observe(floatingMenuContentDiv);
|
||||
}
|
||||
|
||||
function onScroll(e: Event) {
|
||||
if (!virtualScrollingEntryHeight) return;
|
||||
virtualScrollingEntriesStart = e.target instanceof HTMLElement ? e.target.scrollTop : 0;
|
||||
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="tail" bind:this={tail}></div>
|
||||
{/if}
|
||||
{#if displayContainer}
|
||||
<div class="floating-menu-container" bind:this={floatingMenuContainer}>
|
||||
<div class="floating-menu-container" bind:this={floatingMenuContainer} on:wheel|stopPropagation>
|
||||
<LayoutCol class="floating-menu-content" styles={{ "min-width": minWidthStyleValue }} {scrollableY} bind:this={floatingMenuContent} data-floating-menu-content>
|
||||
<slot />
|
||||
</LayoutCol>
|
||||
|
||||
@@ -225,7 +225,7 @@ export function onWheelScroll(e: WheelEvent, editor: EditorWrapper) {
|
||||
|
||||
// Redirect vertical scroll wheel movement into a horizontal scroll on a horizontally scrollable element
|
||||
// There seems to be no possible way to properly employ the browser's smooth scrolling interpolation
|
||||
const horizontalScrollableElement = e.target instanceof Element && e.target.closest("[data-scrollable-x]");
|
||||
const horizontalScrollableElement = e.target instanceof Element && !e.target.closest("[data-scrollable-y]") && e.target.closest("[data-scrollable-x]");
|
||||
if (horizontalScrollableElement && e.deltaY !== 0) {
|
||||
horizontalScrollableElement.scrollTo(horizontalScrollableElement.scrollLeft + e.deltaY, 0);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user