From fadb3124a0051b76a47a5025f2a3f7d1dea2fc7b Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 30 Jul 2026 12:49:00 +0200 Subject: [PATCH] :bug: Clamp gradient stop offsets to valid range (#10881) * :bug: Clamp gradient stop offsets to valid [0, 1] range Fixed a bug where gradient stop offsets outside the valid [0, 1] range were being sent to the server, causing schema validation errors ('invalid shape found'). Changes: - Viewport gradient handler: clamp offset in points-on-pointer-down before creating new stops - Colorpicker gradient preview: clamp offset in handle-preview-down before adding stops - Data layer: clamp offset parameter in update-colorpicker-add-stop and all stop offsets in update-colorpicker-stops; added app.common.math require All clamping follows the existing pattern used in handle-marker-pointer-move. AI-assisted-by: deepseek-v4-flash * :lipstick: Fix formatting in gradient handlers Fix cljfmt formatting issues in gradient handler functions. AI-assisted-by: qwen3.7-plus --- frontend/src/app/main/data/workspace/colors.cljs | 7 +++++-- frontend/src/app/main/store.cljs | 2 +- .../src/app/main/ui/workspace/colorpicker/gradients.cljs | 1 + frontend/src/app/main/ui/workspace/viewport/gradients.cljs | 1 + 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index c145a203b7..c137936650 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] + [app.common.math :as mth] [app.common.schema :as sm] [app.common.types.color :as clr] [app.common.types.fills :as types.fills] @@ -950,7 +951,8 @@ (or (not cap-stops?) (< (count stops) types.fills/MAX-GRADIENT-STOPS))] (if can-add-stop? - (let [new-stop (-> (clr/interpolate-gradient stops offset) + (let [offset (mth/clamp offset 0 1) + new-stop (-> (clr/interpolate-gradient stops offset) (split-color-components)) stops (conj stops new-stop) stops (into [] (sort-by :offset stops)) @@ -973,7 +975,8 @@ stops (mapv split-color-components (if cap-stops? (take types.fills/MAX-GRADIENT-STOPS stops) - stops))] + stops)) + stops (mapv #(update % :offset (fn [o] (mth/clamp o 0 1))) stops)] (-> state (assoc :current-color (get stops stop)) (assoc :stops stops)))))))) diff --git a/frontend/src/app/main/store.cljs b/frontend/src/app/main/store.cljs index dc389033ae..8bdff34a65 100644 --- a/frontend/src/app/main/store.cljs +++ b/frontend/src/app/main/store.cljs @@ -121,7 +121,7 @@ delta (if prev-t (str "(+" (ct/diff-ms prev-t t) "ms)") "(+0ms)") - delta-pad (str/pad delta {:length 10 :type :right})] + delta-pad (str/pad delta {:length 10 :type :right})] (recur t (next xs) (conj! out (str iso " " delta-pad " " name)))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs index 7010e84371..93648bc80d 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs @@ -233,6 +233,7 @@ (mf/deps on-add-stop-preview) (fn [^js e] (let [offset (-> (event->offset e) + (mth/clamp 0 1) (mth/precision 2))] (when on-add-stop-preview (on-add-stop-preview offset))))) diff --git a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs index bc16b89045..c135d11e7e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs @@ -189,6 +189,7 @@ lv (-> (gpt/to-vec from-p to-p) (gpt/unit)) nv (gpt/normal-left lv) offset (-> (gsp/project-t position [from-p to-p] nv) + (mth/clamp 0 1) (mth/precision 2)) new-stop (cc/interpolate-gradient stops offset) stops (conj stops new-stop)