Wrap serialized gradient stops in a new GradientRamp struct and unify FillChoice (#4400)

* Introduce the GradientRamp exchange struct as the serialized TaggedValue::Gradient payload

* Unify FillChoice and FillChoiceUI into one enum generic over color format, carrying GradientRamp stops

* Rename the TaggedValue::Gradient variant to GradientRamp to match its payload

* Move the Color variant into the tagged_value macro list since its stored and wire forms match
This commit is contained in:
Keavon Chambers
2026-09-14 12:58:19 +02:00
committed by Dennis Kobert
parent 4d8729d87c
commit 360321e0ce
32 changed files with 411 additions and 288 deletions
@@ -26,7 +26,7 @@
import ShortcutLabel from "/src/components/widgets/labels/ShortcutLabel.svelte";
import TextLabel from "/src/components/widgets/labels/TextLabel.svelte";
import type { ColorPickerStore } from "/src/stores/color-picker";
import { parseFillChoiceUI } from "/src/utility-functions/colors";
import { parseFillChoice } from "/src/utility-functions/colors";
import type { EditorWrapper, LayoutTarget, Widget, WidgetInstance } from "/wrapper/pkg/graphite_wasm_wrapper";
// Extract the discriminant key names from the Widget tagged enum union (e.g. "TextButton" | "CheckboxInput" | ...)
@@ -138,7 +138,7 @@
component: ColorInput,
getProps: (props, index) => ({
...props,
value: parseFillChoiceUI(props.value),
value: parseFillChoice(props.value),
$$events: {
value: (e: CustomEvent) => widgetValueUpdate(index, e.detail, false),
startHistoryTransaction: () => widgetValueCommit(index, props.value),
@@ -150,7 +150,7 @@
getProps: (props, index) => ({
...props,
$$events: {
// The widget dispatches `"None"` or a bare `SRGBA8`, wrap the color in `{ Solid: ... }` so the payload matches Rust's `FillChoiceUI` shape (which the `Preset` variant expects).
// The widget dispatches `"None"` or a bare `SRGBA8`, wrap the color in `{ Solid: ... }` so the payload matches the Rust `FillChoice` shape the `Preset` variant expects
preset: (e: CustomEvent) => widgetValueCommitAndUpdate(index, { Preset: e.detail === "None" ? "None" : { Solid: e.detail } }, true),
eyedropperColorCode: (e: CustomEvent) => widgetValueCommitAndUpdate(index, { EyedropperColorCode: e.detail }, true),
},
@@ -2,13 +2,13 @@
import { createEventDispatcher } from "svelte";
import ColorPicker from "/src/components/floating-menus/ColorPicker.svelte";
import LayoutCol from "/src/components/layout/LayoutCol.svelte";
import { contrastingOutlineFactor, fillChoiceUIColor, fillChoiceUIGradient } from "/src/utility-functions/colors";
import type { FillChoiceUI, MenuDirection, ActionShortcut } from "/wrapper/pkg/graphite_wasm_wrapper";
import { contrastingOutlineFactor, fillChoiceColor, fillChoiceGradient } from "/src/utility-functions/colors";
import type { FillChoice, MenuDirection, ActionShortcut, SRGBA8 } from "/wrapper/pkg/graphite_wasm_wrapper";
const dispatch = createEventDispatcher<{ value: FillChoiceUI; startHistoryTransaction: undefined }>();
const dispatch = createEventDispatcher<{ value: FillChoice<SRGBA8>; startHistoryTransaction: undefined }>();
// Content
export let value: FillChoiceUI;
export let value: FillChoice<SRGBA8>;
export let chosenGradient: string | undefined = undefined;
export let allowNone = false;
// export let allowTransparency = false; // TODO: Implement
@@ -29,8 +29,8 @@
$: outlineFactor = contrastingOutlineFactor(value, "--color-3-darkgray", 0.01);
$: outlined = outlineFactor > 0.0001;
$: gradient = fillChoiceUIGradient(value);
$: solidColor = fillChoiceUIColor(value);
$: gradient = fillChoiceGradient(value);
$: solidColor = fillChoiceColor(value);
$: none = value === "None";
$: transparency = gradient ? gradient.color.some((color) => color.alpha < 255) : solidColor ? solidColor.alpha < 255 : false;
</script>
@@ -3,7 +3,7 @@
import ColorPicker from "/src/components/floating-menus/ColorPicker.svelte";
import LayoutCol from "/src/components/layout/LayoutCol.svelte";
import LayoutRow from "/src/components/layout/LayoutRow.svelte";
import { fillChoiceUIColor, sRgba8ToRgbaCSS } from "/src/utility-functions/colors";
import { fillChoiceColor, sRgba8ToRgbaCSS } from "/src/utility-functions/colors";
import type { SRGBA8, EditorWrapper } from "/wrapper/pkg/graphite_wasm_wrapper";
const editor = getContext<EditorWrapper>("editor");
@@ -42,7 +42,7 @@
on:open={({ detail }) => (primaryOpen = detail)}
colorOrGradient={{ Solid: primary }}
on:colorOrGradient={({ detail }) => {
const color = fillChoiceUIColor(detail);
const color = fillChoiceColor(detail);
if (color) primaryColorChanged(color);
}}
direction="Right"
@@ -55,7 +55,7 @@
on:open={({ detail }) => (secondaryOpen = detail)}
colorOrGradient={{ Solid: secondary }}
on:colorOrGradient={({ detail }) => {
const color = fillChoiceUIColor(detail);
const color = fillChoiceColor(detail);
if (color) secondaryColorChanged(color);
}}
direction="Right"