mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-03 06:48:12 +08:00
Fix frontend HMR so the page doesn't break upon saving TS files and restructure frontend architecture (#3871)
* Clean up component setup/tear-down side effects * Clean up more component setup/tear-down side effects * Remove nonfunctional debouncer * Clean up even more component setup/tear-down side effects * Reuse backend state * Fix HMR for IO Managers and for State Providers * Rename IO Managers -> Managers and State Providers -> Stores * Restructure and partially flatten managers/stores * Code review fixes * Review fixes
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount, afterUpdate, createEventDispatcher, tick } from "svelte";
|
||||
import { onMount, onDestroy, afterUpdate, createEventDispatcher, tick } from "svelte";
|
||||
|
||||
import type { MenuDirection } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import { browserVersion } from "@graphite/utility-functions/platform";
|
||||
@@ -54,9 +54,11 @@
|
||||
// tell the floating menu content to use it as a min-width so the floating menu is at least the width of the parent element's floating menu spawner.
|
||||
// This is the opposite concern of the natural width measurement system, which gets the natural width of the floating menu content in order for the
|
||||
// spawner widget to optionally set its min-size to the floating menu's natural width.
|
||||
let containerResizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {
|
||||
const containerResizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {
|
||||
resizeObserverCallback(entries);
|
||||
});
|
||||
|
||||
let dialogResizeObserver: ResizeObserver | undefined;
|
||||
let wasOpen = open;
|
||||
let measuringOngoing = false;
|
||||
let measuringOngoingGuard = false;
|
||||
@@ -79,16 +81,7 @@
|
||||
|
||||
// Called only when `open` is changed from outside this component
|
||||
async function watchOpenChange(isOpen: boolean) {
|
||||
// Mitigate a Safari rendering bug which clips the floating menu extending beyond a scrollable container.
|
||||
// The bug is possibly related to <https://bugs.webkit.org/show_bug.cgi?id=160953>, but in our case it happens when `overflow` of a parent is `auto` rather than `hidden`.
|
||||
if (browserVersion().toLowerCase().includes("safari")) {
|
||||
const scrollable = self?.closest("[data-scrollable-x], [data-scrollable-y]");
|
||||
if (scrollable instanceof HTMLElement) {
|
||||
// The issue exists when the container is set to `overflow: auto` but fine when `overflow: hidden`. So this workaround temporarily sets
|
||||
// the scrollable container to `overflow: hidden`, thus removing the scrollbars and ability to scroll until the floating menu is closed.
|
||||
scrollable.style.overflow = isOpen ? "hidden" : "";
|
||||
}
|
||||
}
|
||||
setSafariScrollableOverflow(isOpen);
|
||||
|
||||
// Switching from closed to open
|
||||
if (isOpen && !wasOpen) {
|
||||
@@ -129,12 +122,22 @@
|
||||
wasOpen = isOpen;
|
||||
}
|
||||
|
||||
// Mitigate a Safari rendering bug which clips the floating menu extending beyond a scrollable container. The bug is possibly related to
|
||||
// <https://bugs.webkit.org/show_bug.cgi?id=160953>, but in our case it happens when `overflow` of a parent is `auto` rather than `hidden`.
|
||||
// The issue exists when the container is set to `overflow: auto` but fine when `overflow: hidden`. So this workaround temporarily sets
|
||||
// the scrollable container to `overflow: hidden`, thus removing the scrollbars and ability to scroll until the floating menu is closed.
|
||||
function setSafariScrollableOverflow(hidden: boolean) {
|
||||
if (!browserVersion().toLowerCase().includes("safari")) return;
|
||||
const scrollable = self?.closest("[data-scrollable-x], [data-scrollable-y]");
|
||||
if (scrollable instanceof HTMLElement) scrollable.style.overflow = hidden ? "hidden" : "";
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Measure the content and round up its width and height to the nearest even integer.
|
||||
// This solves antialiasing issues when the content isn't cleanly divisible by 2 and gets translated by (-50%, -50%) causing all its content to be blurry.
|
||||
const floatingMenuContentDiv = floatingMenuContent?.div?.();
|
||||
if (type === "Dialog" && floatingMenuContentDiv) {
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
dialogResizeObserver = new ResizeObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
const existingWidth = Number(floatingMenuContentDiv.style.getPropertyValue("--even-integer-subpixel-expansion-x"));
|
||||
const existingHeight = Number(floatingMenuContentDiv.style.getPropertyValue("--even-integer-subpixel-expansion-y"));
|
||||
@@ -153,10 +156,23 @@
|
||||
floatingMenuContentDiv.style.setProperty("--even-integer-subpixel-expansion-y", `${targetHeight - height}`);
|
||||
});
|
||||
});
|
||||
resizeObserver.observe(floatingMenuContentDiv);
|
||||
dialogResizeObserver.observe(floatingMenuContentDiv);
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
containerResizeObserver.disconnect();
|
||||
dialogResizeObserver?.disconnect();
|
||||
window.removeEventListener("pointermove", pointerMoveHandler);
|
||||
window.removeEventListener("keydown", keyDownHandler);
|
||||
window.removeEventListener("pointerdown", pointerDownHandler);
|
||||
window.removeEventListener("pointerup", pointerUpHandler);
|
||||
window.removeEventListener("click", clickHandlerCapture, true);
|
||||
|
||||
// Revert Safari overflow workaround if the menu was open when destroyed
|
||||
if (open) setSafariScrollableOverflow(false);
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
// Gets the client bounds of the elements and apply relevant styles to them.
|
||||
// TODO: Use DOM attribute bindings more whilst not causing recursive updates. Turning measuring on and off both causes the component to change,
|
||||
|
||||
Reference in New Issue
Block a user