mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
🐛 Keep derived layout paddings non-negative (#12129)
Adding a flex or grid layout to a board with children derives the paddings from the distance between the board and its children. A child that overflows the board, or floating point noise after "Resize board to fit content", gave negative paddings. The shape schema rejects them since paddings must be non-negative, so update-file failed and autosave stopped. Clamp the derived paddings to 0, as the derived gaps already are. Closes #12107 AI-assisted-by: claude-opus-5-5
This commit is contained in:
parent
51ae83202e
commit
fcbb8f1fc0
@ -88,8 +88,8 @@
|
||||
parent-selrect (:selrect parent)
|
||||
|
||||
padding (when (and (not (nil? parent)) (> (count shapes) 0))
|
||||
{:p1 (- min-y (:y1 parent-selrect))
|
||||
:p2 (- min-x (:x1 parent-selrect))})]
|
||||
{:p1 (max 0 (- min-y (:y1 parent-selrect)))
|
||||
:p2 (max 0 (- min-x (:x1 parent-selrect)))})]
|
||||
|
||||
(cond-> {:layout-flex-dir direction :layout-gap layout-gap}
|
||||
(not (nil? padding))
|
||||
|
||||
@ -154,8 +154,8 @@
|
||||
layout-grid-columns (mapv (constantly ctl/default-track-value) cols)
|
||||
|
||||
parent-childs-vector (gpt/to-vec (gpo/origin (:points parent)) (gpt/point all-shapes-rect))
|
||||
p-left (:x parent-childs-vector)
|
||||
p-top (:y parent-childs-vector)]
|
||||
p-left (max 0 (:x parent-childs-vector))
|
||||
p-top (max 0 (:y parent-childs-vector))]
|
||||
|
||||
(-> {:layout-grid-columns layout-grid-columns
|
||||
:layout-grid-rows layout-grid-rows
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
(ns common-tests.geom-flex-layout-test
|
||||
(:require
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes.flex-layout.params :as flparams]
|
||||
[app.common.geom.shapes.flex-layout.positions :as flp]
|
||||
[app.common.math :as mth]
|
||||
[app.common.types.shape :as cts]
|
||||
@ -104,3 +105,33 @@
|
||||
:layout-justify-content :end
|
||||
:x 0 :y 0 :width 100 :height 100})]
|
||||
(t/is (not (ctl/v-end? frame))))))
|
||||
|
||||
;; ---- calculate-params paddings ----
|
||||
;;
|
||||
;; Adding a flex layout derives the paddings from the distance between the
|
||||
;; board and its children. A child that overflows the board, or floating
|
||||
;; point noise after "Resize board to fit content", gave negative paddings
|
||||
;; that the shape schema rejects, which broke autosave (#12107).
|
||||
|
||||
(defn- params-for-child
|
||||
[child-attrs]
|
||||
(let [parent (cts/setup-shape {:type :frame :x 0 :y 0 :width 100 :height 100})
|
||||
child (cts/setup-shape (merge {:type :rect :parent-id (:id parent)} child-attrs))
|
||||
parent (assoc parent :shapes [(:id child)])
|
||||
objects {(:id parent) parent (:id child) child}]
|
||||
(flparams/calculate-params objects [child] parent)))
|
||||
|
||||
(t/deftest calculate-params-keeps-positive-padding
|
||||
(t/is (= {:p1 20 :p2 10 :p3 20 :p4 10}
|
||||
(:layout-padding (params-for-child {:x 10 :y 20 :width 50 :height 50})))))
|
||||
|
||||
(t/deftest calculate-params-clamps-overflowing-child-padding
|
||||
(t/is (= {:p1 0 :p2 0 :p3 0 :p4 0}
|
||||
(:layout-padding (params-for-child {:x -10 :y -5 :width 150 :height 150})))))
|
||||
|
||||
(t/deftest calculate-params-clamps-float-noise-padding
|
||||
(let [padding (:layout-padding
|
||||
(params-for-child {:x -1.1728368917829357E-5
|
||||
:y -2.1457672119140625E-6
|
||||
:width 100 :height 100}))]
|
||||
(t/is (every? #(not (neg? %)) (vals padding)))))
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
[app.common.geom.modifiers]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes.grid-layout.layout-data :as gld]
|
||||
[app.common.geom.shapes.grid-layout.params :as glparams]
|
||||
[app.common.math :as mth]
|
||||
[app.common.types.shape :as cts]
|
||||
[clojure.test :as t]))
|
||||
@ -408,3 +409,27 @@
|
||||
result (gld/set-auto-multi-span (auto-col-parent) tracks cmap cells frame-bounds {} :column)]
|
||||
(t/is (mth/close? 100.0 (:size (nth result 0)) 0.001))
|
||||
(t/is (mth/close? 100.0 (:size (nth result 1)) 0.001)))))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; calculate-params: derived paddings are never negative
|
||||
;; ---------------------------------------------------------------------------
|
||||
;;
|
||||
;; Adding a grid layout derives the paddings from the children. A child that
|
||||
;; overflows the board gave negative paddings that the shape schema rejects,
|
||||
;; which broke autosave (#12107).
|
||||
|
||||
(defn- grid-params-for-children
|
||||
[& children-attrs]
|
||||
(let [parent (cts/setup-shape {:type :frame :x 0 :y 0 :width 100 :height 100})
|
||||
children (mapv #(cts/setup-shape (merge {:type :rect :parent-id (:id parent)} %))
|
||||
children-attrs)]
|
||||
(glparams/calculate-params nil children parent)))
|
||||
|
||||
(t/deftest grid-calculate-params-keeps-positive-padding
|
||||
(let [params (grid-params-for-children {:x 10 :y 20 :width 30 :height 30})]
|
||||
(t/is (mth/close? 20 (get-in params [:layout-padding :p1])))
|
||||
(t/is (mth/close? 10 (get-in params [:layout-padding :p2])))))
|
||||
|
||||
(t/deftest grid-calculate-params-clamps-overflowing-child-padding
|
||||
(let [params (grid-params-for-children {:x -10 :y -5 :width 150 :height 150})]
|
||||
(t/is (= {:p1 0 :p2 0 :p3 0 :p4 0} (:layout-padding params)))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user