mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-21 02:48:11 +08:00
Refactor the TypeScript data flow for full type safety and auto-generation of Rust types (#3865)
* Migrate Specta to Tsify to auto-generate messages.ts, working except colors and widgets * Adopt the generated FillColor/Color/GradientStops * Fix widget typing * Separate WidgetGroup enum variants into wrapper structs * Small rename * Simplify widgets further * Clean up message type references * Switch type imports to the auto-generated file * Remove lowercase serde rename * Fix FillChoice deserialization * Fix small regression from #3837 * Improve type safety * Make WidgetSpan type-safe * More cleanup and type safety * More type safety * More type safety * Get the rest to type-check without errors; improve widget builder macro to have optional icons; improve Svelte 5 configs * Cargo fmt * Fix imports * Update outdated readme info * Fix lint command rename references * Fix typos * One more typos fix * Remove unnecessary dep: prefix from the edited Cargo.toml files * Remove excess parts from Cargo.toml * Fix compiling on desktop * Revert "Remove excess parts from Cargo.toml" This reverts commit 6b711117b3a5d5d8a3ee20f36a43bc74930b7c82. * Update dev docs with simpler, more accurate instructions
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
|
||||
import { isPlatformNative } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { AppWindowState } from "@graphite/state-providers/app-window";
|
||||
import type { DialogState } from "@graphite/state-providers/dialog";
|
||||
import type { TooltipState } from "@graphite/state-providers/tooltip";
|
||||
import { isDesktop } from "@graphite/utility-functions/platform";
|
||||
|
||||
import Dialog from "@graphite/components/floating-menus/Dialog.svelte";
|
||||
import Tooltip from "@graphite/components/floating-menus/Tooltip.svelte";
|
||||
@@ -31,7 +31,7 @@
|
||||
{#if $tooltip.visible}
|
||||
<Tooltip />
|
||||
{/if}
|
||||
{#if isDesktop() && new Date() > new Date("2026-03-15")}
|
||||
{#if isPlatformNative() && new Date() > new Date("2026-03-15")}
|
||||
<LayoutCol class="release-candidate-expiry">
|
||||
<TextLabel>
|
||||
<p>
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
<script lang="ts" context="module">
|
||||
<script lang="ts">
|
||||
import { getContext, tick } from "svelte";
|
||||
|
||||
import type { Editor } from "@graphite/editor";
|
||||
|
||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||
import Data from "@graphite/components/panels/Data.svelte";
|
||||
import Document from "@graphite/components/panels/Document.svelte";
|
||||
import Layers from "@graphite/components/panels/Layers.svelte";
|
||||
import Properties from "@graphite/components/panels/Properties.svelte";
|
||||
import Welcome from "@graphite/components/panels/Welcome.svelte";
|
||||
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
|
||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||
|
||||
type PanelType = keyof typeof PANEL_COMPONENTS;
|
||||
|
||||
const PANEL_COMPONENTS = {
|
||||
Welcome,
|
||||
@@ -12,20 +22,6 @@
|
||||
Properties,
|
||||
Data,
|
||||
};
|
||||
type PanelType = keyof typeof PANEL_COMPONENTS;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, tick } from "svelte";
|
||||
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import { isEventSupported } from "@graphite/utility-functions/platform";
|
||||
|
||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
|
||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||
|
||||
const BUTTON_LEFT = 0;
|
||||
const BUTTON_MIDDLE = 1;
|
||||
|
||||
@@ -80,16 +76,6 @@
|
||||
closeAction?.(tabIndex);
|
||||
}
|
||||
}}
|
||||
on:mouseup={(e) => {
|
||||
// Middle mouse button click fallback for Safari:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event#browser_compatibility
|
||||
// The downside of using mouseup is that the mousedown didn't have to originate in the same element.
|
||||
// A possible future improvement could save the target element during mousedown and check if it's the same here.
|
||||
if (!isEventSupported("auxclick") && e.button === BUTTON_MIDDLE) {
|
||||
e.stopPropagation();
|
||||
closeAction?.(tabIndex);
|
||||
}
|
||||
}}
|
||||
bind:this={tabElements[tabIndex]}
|
||||
>
|
||||
<LayoutRow class="name">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from "svelte";
|
||||
|
||||
import type { Layout } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { Layout } from "@graphite/messages";
|
||||
import { patchLayout } from "@graphite/utility-functions/widgets";
|
||||
|
||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from "svelte";
|
||||
|
||||
import { isPlatformNative } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Layout } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { Layout } from "@graphite/messages";
|
||||
import type { AppWindowState } from "@graphite/state-providers/app-window";
|
||||
import type { FullscreenState } from "@graphite/state-providers/fullscreen";
|
||||
import type { TooltipState } from "@graphite/state-providers/tooltip";
|
||||
@@ -11,7 +12,6 @@
|
||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
|
||||
import WidgetLayout from "@graphite/components/widgets/WidgetLayout.svelte";
|
||||
import { isDesktop } from "/src/utility-functions/platform";
|
||||
|
||||
const appWindow = getContext<AppWindowState>("appWindow");
|
||||
const editor = getContext<Editor>("editor");
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
let menuBarLayout: Layout = [];
|
||||
|
||||
$: showFullscreenButton = $appWindow.platform === "Web" || $fullscreen.windowFullscreen || (isDesktop() && $appWindow.fullscreen);
|
||||
$: isFullscreen = isDesktop() ? $appWindow.fullscreen : $fullscreen.windowFullscreen;
|
||||
$: showFullscreenButton = $appWindow.platform === "Web" || $fullscreen.windowFullscreen || (isPlatformNative() && $appWindow.fullscreen);
|
||||
$: isFullscreen = isPlatformNative() ? $appWindow.fullscreen : $fullscreen.windowFullscreen;
|
||||
// On Mac, the menu bar height needs to be scaled by the inverse of the UI scale to fit its native window buttons
|
||||
$: height = $appWindow.platform === "Mac" ? 28 * (1 / $appWindow.uiScale) : 28;
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
: undefined}
|
||||
tooltipShortcut={$tooltip.fullscreenShortcut}
|
||||
on:click={() => {
|
||||
if (isDesktop()) editor.handle.appWindowFullscreen();
|
||||
if (isPlatformNative()) editor.handle.appWindowFullscreen();
|
||||
else ($fullscreen.windowFullscreen ? fullscreen.exitFullscreen : fullscreen.enterFullscreen)();
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
|
||||
import type { OpenDocument } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import type { Editor } from "@graphite/editor";
|
||||
import type { OpenDocument } from "@graphite/messages";
|
||||
import type { PortfolioState } from "@graphite/state-providers/portfolio";
|
||||
|
||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
@@ -18,9 +18,9 @@
|
||||
/* └─ */ details: 20,
|
||||
/* ├─ */ properties: 45,
|
||||
/* └─ */ layers: 55,
|
||||
};
|
||||
} as const;
|
||||
|
||||
let panelSizes = PANEL_SIZES;
|
||||
let panelSizes: Record<string, number> = PANEL_SIZES;
|
||||
let documentPanel: Panel | undefined;
|
||||
let gutterResizeRestore: [number, number] | undefined = undefined;
|
||||
let pointerCaptureId: number | undefined = undefined;
|
||||
@@ -40,15 +40,19 @@
|
||||
const portfolio = getContext<PortfolioState>("portfolio");
|
||||
|
||||
function resizePanel(e: PointerEvent) {
|
||||
const gutter = (e.target || undefined) as HTMLDivElement | undefined;
|
||||
const nextSibling = (gutter?.nextElementSibling || undefined) as HTMLDivElement | undefined;
|
||||
const prevSibling = (gutter?.previousElementSibling || undefined) as HTMLDivElement | undefined;
|
||||
const parentElement = (gutter?.parentElement || undefined) as HTMLDivElement | undefined;
|
||||
const gutter = e.target;
|
||||
if (!(gutter instanceof HTMLDivElement)) return;
|
||||
|
||||
const nextSiblingName = (nextSibling?.getAttribute("data-subdivision-name") || undefined) as keyof typeof PANEL_SIZES;
|
||||
const prevSiblingName = (prevSibling?.getAttribute("data-subdivision-name") || undefined) as keyof typeof PANEL_SIZES;
|
||||
const nextSibling = gutter.nextElementSibling;
|
||||
const prevSibling = gutter.previousElementSibling;
|
||||
|
||||
if (!gutter || !nextSibling || !prevSibling || !parentElement || !nextSiblingName || !prevSiblingName) return;
|
||||
const parentElement = gutter.parentElement;
|
||||
if (!(nextSibling instanceof HTMLDivElement) || !(prevSibling instanceof HTMLDivElement) || !(parentElement instanceof HTMLDivElement)) return;
|
||||
|
||||
const nextSiblingName = nextSibling.getAttribute("data-subdivision-name") || undefined;
|
||||
const prevSiblingName = prevSibling.getAttribute("data-subdivision-name") || undefined;
|
||||
|
||||
if (!nextSiblingName || !prevSiblingName || !(nextSiblingName in PANEL_SIZES) || !(prevSiblingName in PANEL_SIZES)) return;
|
||||
|
||||
// Are we resizing horizontally?
|
||||
const isHorizontal = gutter.getAttribute("data-gutter-horizontal") !== null;
|
||||
|
||||
Reference in New Issue
Block a user