mirror of
https://github.com/penpot/penpot.git
synced 2026-10-30 14:30:37 +00:00
✨ Generate layout item edits in component histories
Add grid item justification and child margin mode, alignment, fixed/fill sizing, size limits, absolute position and stacking order. Sample optional asymmetric margins before copying. Keep existing input indexes and fixture defaults, with explicit target eligibility and independent authored groups. Check companion values, propagation, preserved overrides, reset, update main, detach and exact undo/redo. Replay the histories through the real frontend layout events and retain corrupt-result controls. Correct F239's full-sync comparison to wait for layout on both routes. The reduced add-child/absolute-child history stays settled, while the negative control still rejects a real 0.25 px absolute-child displacement. No geometry tolerance or golden data changes. Validate the final continuation on common JVM (2004 tests / 32919 assertions), common JS (1940 / 31522), frontend (1745 / 13569), backend (1793 / 9007) and exporter (16 / 40). All four modules pass lint and format. All six generated properties pass 40 programs at seed 712 in both runtimes. Golden data is unchanged. The final continuation benchmark passes with no regression flags. Lower quantile ratios against Phase 1e: main 10/100/1000 0.51/0.58/0.57, three levels 0.57, chain 0.53, library 0.57, many shapes 0.45, variant switch 0.66. Machine/JVM differences make these rough comparisons; baseline unchanged. AI-assisted-by: gpt-6
This commit is contained in:
parent
96a4c76ab6
commit
a086fd9657
@ -96,7 +96,10 @@
|
||||
:fixed-scroll :constraints-h :constraints-v :layout-item-margin
|
||||
:layout-gap :layout-padding :layout-align-items :layout-flex-dir
|
||||
:layout-wrap-type :layout-justify-content :layout-align-content
|
||||
:layout-gap-type :layout-padding-type})
|
||||
:layout-gap-type :layout-padding-type :layout-justify-items
|
||||
:layout-item-margin-type :layout-item-align-self :layout-item-h-sizing
|
||||
:layout-item-v-sizing :layout-item-min-w :layout-item-max-w
|
||||
:layout-item-min-h :layout-item-max-h :layout-item-absolute :layout-item-z-index})
|
||||
|
||||
(defn set-property
|
||||
"`shape` with `property` set to `value`. Public so the frontend interpreter
|
||||
@ -140,7 +143,7 @@
|
||||
(def ^:private layout-container-properties
|
||||
#{:layout-gap :layout-padding :layout-align-items :layout-flex-dir
|
||||
:layout-wrap-type :layout-justify-content :layout-align-content
|
||||
:layout-gap-type :layout-padding-type})
|
||||
:layout-gap-type :layout-padding-type :layout-justify-items})
|
||||
|
||||
(defn- with-layout-reflow
|
||||
[changes id]
|
||||
@ -186,7 +189,7 @@
|
||||
value' (applied-value* property value)
|
||||
layout-id (cond
|
||||
(and (:layout shape) (contains? layout-container-properties property)) shape-id
|
||||
(and (= :layout-item-margin property)
|
||||
(and (contains? ctl/layout-child-attrs property)
|
||||
(:layout (get-in page [:objects (:parent-id shape)]))) (:parent-id shape))
|
||||
changes (cond-> (cls/generate-update-shapes
|
||||
(pcb/empty-changes nil (:id page))
|
||||
@ -194,6 +197,11 @@
|
||||
(fn [shape] (set-property shape property value'))
|
||||
(:objects page)
|
||||
{})
|
||||
(and (= :layout-item-absolute property)
|
||||
(ctl/grid-layout? (get-in page [:objects layout-id])))
|
||||
(pcb/update-shapes [layout-id] ctl/assign-cells
|
||||
{:with-objects? true :ignore-touched true})
|
||||
|
||||
layout-id
|
||||
(-> (with-layout-reflow layout-id)
|
||||
(assoc ::layout-reflow? true))
|
||||
|
||||
@ -87,6 +87,17 @@
|
||||
(tm/apply-to (n/change-property parent :layout-padding {:p1 3 :p2 6 :p3 9 :p4 12}))
|
||||
(#(with-settled-layout % name)))))
|
||||
|
||||
(defn- with-layout-item-margins
|
||||
[situation name]
|
||||
(let [ids (:shapes (tm/shape-by-id situation ((n/main-head-of name) situation)))]
|
||||
(-> (reduce (fn [s id]
|
||||
(->> s
|
||||
(tm/apply-to (n/change-property (constantly id) :layout-item-margin
|
||||
{:m1 2 :m2 4 :m3 6 :m4 8}))
|
||||
(tm/apply-to (n/change-property (constantly id) :layout-item-margin-type :multiple))))
|
||||
situation ids)
|
||||
(with-settled-layout name))))
|
||||
|
||||
(defn- with-outer-layout
|
||||
[situation name layout]
|
||||
(if-not layout
|
||||
@ -201,6 +212,8 @@
|
||||
(with-layout name (when (zero? index) (:layout opts)))
|
||||
(cond-> (and (zero? index) (:layout opts) (:layout-children opts))
|
||||
(with-layout-children name))
|
||||
(cond-> (and (zero? index) (:layout opts) (:layout-item-margins opts))
|
||||
(with-layout-item-margins name))
|
||||
(as-> s (reduce #(tm/apply-to %2 %1) s
|
||||
[(n/make-nested-component name depth)]))
|
||||
(with-outer-layout name (when (and (zero? index) (pos? depth) (:layout-copies opts)) (:layout opts)))
|
||||
@ -432,7 +445,18 @@
|
||||
[:layout-justify-content [:start :space-between :center :end :space-around :space-evenly]]
|
||||
[:layout-align-content [:stretch :center :end :start :space-between :space-around :space-evenly]]
|
||||
[:layout-gap-type [:multiple :simple]]
|
||||
[:layout-padding-type [:simple :multiple]]])
|
||||
[:layout-padding-type [:simple :multiple]]
|
||||
[:layout-justify-items [:start :center :end :stretch]]
|
||||
[:layout-item-margin-type [:simple :multiple]]
|
||||
[:layout-item-align-self [:start :center :end :stretch]]
|
||||
[:layout-item-h-sizing [:fix :fill]]
|
||||
[:layout-item-v-sizing [:fix :fill]]
|
||||
[:layout-item-min-w [0 24 64]]
|
||||
[:layout-item-max-w [256 96 64]]
|
||||
[:layout-item-min-h [0 24 64]]
|
||||
[:layout-item-max-h [256 96 64]]
|
||||
[:layout-item-absolute [false true]]
|
||||
[:layout-item-z-index [0 2 -1]]])
|
||||
|
||||
(def text-style-edits
|
||||
"All twelve style units, independent of the production text group table."
|
||||
@ -480,7 +504,14 @@
|
||||
:layout-gap-type :layout-padding-type
|
||||
:layout-justify-content :layout-align-content) (some? (:layout shape))
|
||||
(:layout-flex-dir :layout-wrap-type) (= :flex (:layout shape))
|
||||
:layout-item-margin (some? (:layout (tm/shape-by-id situation (:parent-id shape))))
|
||||
:layout-justify-items (= :grid (:layout shape))
|
||||
:layout-item-align-self (= :flex (:layout (tm/shape-by-id situation (:parent-id shape))))
|
||||
(:layout-item-margin :layout-item-margin-type
|
||||
:layout-item-h-sizing :layout-item-v-sizing
|
||||
:layout-item-min-w :layout-item-max-w
|
||||
:layout-item-min-h :layout-item-max-h
|
||||
:layout-item-absolute :layout-item-z-index)
|
||||
(some? (:layout (tm/shape-by-id situation (:parent-id shape))))
|
||||
true))))
|
||||
(and (= kind :edit) (= 2 (mod (or property 0) 3)))
|
||||
(remove (fn [{:keys [shape]}]
|
||||
@ -637,7 +668,7 @@
|
||||
(shadow/parent-orientation (all-objects situation) (all-objects settled))
|
||||
(shadow/settle (all-objects settled)))
|
||||
all (into (set (synchronizable-components situation)) (r/pending-components situation))
|
||||
full-before (:situation (cf/sync-world situation all))
|
||||
full-before (r/settle situation all)
|
||||
full (:situation (cf/sync-world settled all))
|
||||
opts {:free-head-placement false}
|
||||
settled-design (oracle/canonical settled opts)
|
||||
@ -1023,8 +1054,9 @@
|
||||
depth (gen/choose 0 2)
|
||||
layout (gen/elements [nil :flex :grid])
|
||||
layout-children gen/boolean
|
||||
layout-item-margins gen/boolean
|
||||
ops (operation-gen structure-kinds)]
|
||||
{:world [components depth {:text true :text-styles true :layout layout :layout-children layout-children}]
|
||||
{:world [components depth {:text true :text-styles true :layout layout :layout-children layout-children :layout-item-margins layout-item-margins}]
|
||||
:ops ops}))
|
||||
|
||||
(def swap-kinds (into structure-kinds [:swap :switch]))
|
||||
@ -1034,10 +1066,11 @@
|
||||
differ? gen/boolean
|
||||
layout (gen/elements [nil :flex :grid])
|
||||
layout-children gen/boolean
|
||||
layout-item-margins gen/boolean
|
||||
ops (operation-gen swap-kinds)]
|
||||
{:world [components 2 {:variants true :variant-diff differ? :rich-variants true
|
||||
:text true :text-styles true :layout layout :layout-copies true
|
||||
:layout-children layout-children}]
|
||||
:layout-children layout-children :layout-item-margins layout-item-margins}]
|
||||
:ops ops}))
|
||||
|
||||
(def library-kinds
|
||||
@ -1047,9 +1080,10 @@
|
||||
(gen/let [depth (gen/choose 0 2)
|
||||
layout (gen/elements [nil :flex :grid])
|
||||
layout-children gen/boolean
|
||||
layout-item-margins gen/boolean
|
||||
ops (operation-gen library-kinds)]
|
||||
{:world [2 depth {:library true :variants true :rich-variants true :text true :text-styles true
|
||||
:layout layout :layout-copies true :layout-children layout-children}]
|
||||
:layout layout :layout-copies true :layout-children layout-children :layout-item-margins layout-item-margins}]
|
||||
:ops ops}))
|
||||
|
||||
(def stale-library-kinds
|
||||
@ -1060,10 +1094,11 @@
|
||||
library-depth (gen/choose 1 2)
|
||||
layout (gen/elements [nil :flex :grid])
|
||||
layout-children gen/boolean
|
||||
layout-item-margins gen/boolean
|
||||
ops (operation-gen stale-library-kinds)]
|
||||
{:world [2 depth {:library true :stale-libraries true :library-variants true :library-text true
|
||||
:library-depth library-depth :variants true :rich-variants true :text true :text-styles true
|
||||
:layout layout :layout-copies true :layout-children layout-children}]
|
||||
:layout layout :layout-copies true :layout-children layout-children :layout-item-margins layout-item-margins}]
|
||||
:ops ops}))
|
||||
|
||||
(def dependency-kinds
|
||||
|
||||
@ -28,7 +28,14 @@
|
||||
:layout-padding :layout-padding :layout-align-items :layout-align-items
|
||||
:layout-flex-dir :layout-flex-dir :layout-wrap-type :layout-wrap-type
|
||||
:layout-justify-content :layout-justify-content :layout-align-content :layout-align-content
|
||||
:layout-gap-type :layout-gap :layout-padding-type :layout-padding})
|
||||
:layout-gap-type :layout-gap :layout-padding-type :layout-padding
|
||||
:layout-justify-items :layout-justify-items
|
||||
:layout-item-margin-type :layout-item-margin
|
||||
:layout-item-align-self :layout-item-align-self
|
||||
:layout-item-h-sizing :layout-item-h-sizing :layout-item-v-sizing :layout-item-v-sizing
|
||||
:layout-item-min-w :layout-item-min-w :layout-item-max-w :layout-item-max-w
|
||||
:layout-item-min-h :layout-item-min-h :layout-item-max-h :layout-item-max-h
|
||||
:layout-item-absolute :layout-item-absolute :layout-item-z-index :layout-item-z-index})
|
||||
|
||||
(defn attribute-applicable?
|
||||
"The clipping and background-export controls belong to frames."
|
||||
|
||||
@ -184,7 +184,51 @@
|
||||
[22 :layout-justify-content :layout-justify-content #{:flex :grid}]
|
||||
[23 :layout-align-content :layout-align-content #{:flex :grid}]
|
||||
[24 :layout-gap-type :layout-gap #{:flex :grid}]
|
||||
[25 :layout-padding-type :layout-padding #{:flex :grid}]])
|
||||
[25 :layout-padding-type :layout-padding #{:flex :grid}]
|
||||
[26 :layout-justify-items :layout-justify-items #{:grid}]])
|
||||
|
||||
(def layout-item-cases
|
||||
[[27 :layout-item-margin-type :layout-item-margin #{:flex :grid}]
|
||||
[28 :layout-item-align-self :layout-item-align-self #{:flex}]
|
||||
[29 :layout-item-h-sizing :layout-item-h-sizing #{:flex :grid}]
|
||||
[30 :layout-item-v-sizing :layout-item-v-sizing #{:flex :grid}]
|
||||
[31 :layout-item-min-w :layout-item-min-w #{:flex :grid}]
|
||||
[32 :layout-item-max-w :layout-item-max-w #{:flex :grid}]
|
||||
[33 :layout-item-min-h :layout-item-min-h #{:flex :grid}]
|
||||
[34 :layout-item-max-h :layout-item-max-h #{:flex :grid}]
|
||||
[35 :layout-item-absolute :layout-item-absolute #{:flex :grid}]
|
||||
[36 :layout-item-z-index :layout-item-z-index #{:flex :grid}]])
|
||||
|
||||
(t/deftest remaining-layout-inputs-resolve-only-in-their-own-context
|
||||
(doseq [layout [nil :flex :grid]
|
||||
[property attr _ layouts] (into [[26 :layout-justify-items :layout-justify-items #{:grid}]]
|
||||
layout-item-cases)]
|
||||
(let [situation (cg/world [1 0 {:layout layout :layout-children true}])
|
||||
resolved (cg/resolve-op situation {} [:style 0 property 1 1])
|
||||
parent (tm/shape-by-id situation (get-in resolved [:shape :parent-id]))]
|
||||
(t/is (= attr (:property resolved)))
|
||||
(if (contains? layouts layout)
|
||||
(do
|
||||
(t/is (some? (:op resolved)))
|
||||
(t/is (not= (get (:shape resolved) attr) (:value resolved)))
|
||||
(t/is (= layout (if (= property 26) (get-in resolved [:shape :layout]) (:layout parent)))))
|
||||
(do
|
||||
(t/is (nil? (:op resolved)))
|
||||
(t/is (= :skip (get-in resolved [:trace :status]))))))))
|
||||
|
||||
(t/deftest asymmetric-item-margins-are-settled-before-copying
|
||||
(doseq [layout [:flex :grid]]
|
||||
(let [situation (cg/world [1 0 {:layout layout :layout-children true :layout-item-margins true}])
|
||||
main-id ((n/main-rect-of "random-0") situation)
|
||||
images (filter #(or (= main-id (get-in % [:shape :id]))
|
||||
(= main-id (get-in % [:shape :shape-ref]))) (cg/tree situation))]
|
||||
(t/is (= 3 (count images)))
|
||||
(doseq [{:keys [shape]} images]
|
||||
(t/is (= {:m1 2 :m2 4 :m3 6 :m4 8} (:layout-item-margin shape)))
|
||||
(t/is (= :multiple (:layout-item-margin-type shape))))
|
||||
(t/is (= :valid (try (oracle/check situation {}) :valid
|
||||
(catch #?(:clj Exception :cljs js/Error) error
|
||||
(select-keys (ex-data error) [:invariant :group]))))))))
|
||||
|
||||
(t/deftest multi-child-layout-fixtures-start-settled-before-user-actions
|
||||
(doseq [layout [:flex :grid] depth [0 1]]
|
||||
@ -309,6 +353,94 @@
|
||||
(t/is (pos? (get-in result [:coverage :random kind :changed] 0))
|
||||
(str kind " changes " property " in " layout))))))
|
||||
|
||||
(t/deftest adding-a-flex-child-before-making-a-copy-child-absolute-stays-settled
|
||||
(t/is (map? (cg/run {:world [1 0 {:layout :flex :layout-children true}]
|
||||
:ops [[:add-child 0] [:style 2 35 1 1]]}))))
|
||||
|
||||
(t/deftest full-settlement-comparison-still-rejects-absolute-child-drift
|
||||
(let [initial (-> (cg/initial-state [1 0 {:layout :flex :layout-children true}])
|
||||
(cg/step [:add-child 0]) cg/settle-state)
|
||||
id (get-in (cg/resolve-op (:situation initial) {} [:style 2 35 1 1]) [:shape :id])
|
||||
edited (cg/step initial [:style 2 35 1 1])
|
||||
settled (assoc edited :situation (r/settle (:situation edited)) :checkpoint nil)
|
||||
settle r/settle
|
||||
corrupt-full (fn [situation component-ids]
|
||||
(let [result (settle situation component-ids)
|
||||
file (tm/file result)
|
||||
path [:data :pages-index (:id (thf/current-page file)) :objects id]]
|
||||
(tm/with-file result (update-in file path gsh/move (gpt/point 0.25 0)))))
|
||||
invariant (with-redefs [r/settle (fn
|
||||
([situation] (settle situation (r/pending-components situation)))
|
||||
([situation ids] (corrupt-full situation ids)))]
|
||||
(try (cg/settle-state settled) nil
|
||||
(catch #?(:clj Exception :cljs js/Error) error
|
||||
(:invariant (ex-data error)))))]
|
||||
(t/is (= :I6 invariant))))
|
||||
|
||||
(t/deftest layout-item-overrides-retain-values-and-companions
|
||||
(doseq [[property attr group layouts] layout-item-cases
|
||||
layout (sort layouts)]
|
||||
(t/testing (str attr " in " layout)
|
||||
(let [initial (cg/initial-state [1 0 {:layout layout :layout-children true :layout-item-margins true}])
|
||||
situation (:situation initial)
|
||||
authored (if (= property 27) 0 1)
|
||||
other (if (= property 27) 1 0)
|
||||
resolved (cg/resolve-op situation {} [:style 0 property authored 1])
|
||||
shape (:shape resolved)
|
||||
id (:id shape)
|
||||
expected (if (= property 27)
|
||||
{:layout-item-margin-type :simple :layout-item-margin {:m1 2 :m2 4 :m3 6 :m4 8}}
|
||||
{attr (:value resolved)})
|
||||
edited (-> initial (cg/step [:style 0 property authored 1]) cg/settle-state)
|
||||
after (:situation edited)
|
||||
file (tm/file after)
|
||||
path [:data :pages-index (:id (thf/current-page file)) :objects id]
|
||||
invariant (fn [file]
|
||||
(try (oracle/check (tm/with-file after file) (:model edited)) nil
|
||||
(catch #?(:clj Exception :cljs js/Error) error
|
||||
(:invariant (ex-data error)))))
|
||||
reverted (cond-> (if (contains? shape attr)
|
||||
(assoc-in file (conj path attr) (get shape attr))
|
||||
(update-in file path dissoc attr))
|
||||
(and (= property 35) (= layout :grid))
|
||||
(assoc-in (conj (pop path) (:parent-id shape) :layout-grid-cells)
|
||||
(:layout-grid-cells (tm/shape-by-id situation (:parent-id shape)))))
|
||||
main-index (first (keep (fn [index]
|
||||
(when (= (:shape-ref shape)
|
||||
(get-in (cg/resolve-op situation {} [:style index property other 0])
|
||||
[:shape :id])) index))
|
||||
(range (count (cg/tree situation)))))
|
||||
updated (-> edited (cg/step [:style main-index property authored 0]) cg/settle-state
|
||||
(cg/step [:style main-index property other 0]) cg/settle-state)
|
||||
value (:value (cg/resolve-op situation {} [:style main-index property other 0]))
|
||||
copies (filter #(= (:shape-ref shape) (get-in % [:shape :shape-ref])) (cg/tree situation))]
|
||||
(t/is (= expected (get-in edited [:model id group])))
|
||||
(t/is (= #{group} (:touched (tm/shape-by-id after id))))
|
||||
(t/is (= (:layout-item-margin shape) (:layout-item-margin (tm/shape-by-id after id))))
|
||||
(t/is (= :I9 (invariant reverted)))
|
||||
(t/is (= :I3 (invariant (update-in file (conj path :touched) disj group))))
|
||||
(t/is (some? main-index))
|
||||
(t/is (= 2 (count copies)))
|
||||
(doseq [{copy :shape} copies]
|
||||
(let [actual (tm/shape-by-id (:situation updated) (:id copy))]
|
||||
(t/is (= (if (= id (:id copy)) (:value resolved) value) (get actual attr)))
|
||||
(t/is (= (if (= id (:id copy)) #{group} #{}) (set (:touched actual))))))
|
||||
(t/is (= expected (get-in updated [:model id group])))))))
|
||||
|
||||
(t/deftest layout-item-histories-survive-component-operations
|
||||
(doseq [[property _ _ layouts] layout-item-cases
|
||||
layout (sort layouts)]
|
||||
(let [authored (if (= property 27) 0 1)
|
||||
other (if (= property 27) 1 0)
|
||||
result (cg/run {:world [1 0 {:layout layout :layout-children true :layout-item-margins true}]
|
||||
:ops [[:style 0 property authored 1] [:style 0 property authored 0]
|
||||
[:style 0 property other 0] [:undo] [:redo] [:update-main 0]
|
||||
[:style 0 property other 1] [:reset 0]
|
||||
[:style 0 property other 1] [:detach 0] [:undo] [:redo]]})]
|
||||
(doseq [kind [:style :update-main :reset :detach]]
|
||||
(t/is (pos? (get-in result [:coverage :random kind :changed] 0))
|
||||
(str kind " changes " property " in " layout))))))
|
||||
|
||||
(t/deftest text-style-edits-cover-every-style-unit
|
||||
(doseq [[unit group] (map-indexed vector
|
||||
[:text-content-family :text-content-weight :text-content-size
|
||||
|
||||
@ -90,7 +90,7 @@
|
||||
|
||||
(t/deftest ^:async layout-container-histories-survive-component-operations
|
||||
(doseq [[property layouts] [[20 [:flex]] [21 [:flex]] [22 [:flex :grid]] [23 [:flex :grid]]
|
||||
[24 [:flex :grid]] [25 [:flex :grid]]]
|
||||
[24 [:flex :grid]] [25 [:flex :grid]] [26 [:grid]]]
|
||||
layout layouts]
|
||||
(await (replay {:world [1 0 {:layout layout :layout-children true}]
|
||||
:ops [[:style 0 property 1 1] [:style 0 property 1 0]
|
||||
@ -98,6 +98,21 @@
|
||||
[:style 0 property 0 1] [:reset 0]
|
||||
[:style 0 property 0 1] [:detach 0] [:undo] [:redo]]}))))
|
||||
|
||||
(t/deftest ^:async layout-item-histories-survive-component-operations
|
||||
(doseq [property (range 27 37)
|
||||
layout (if (= property 28) [:flex] [:flex :grid])]
|
||||
(let [authored (if (= property 27) 0 1)
|
||||
other (if (= property 27) 1 0)]
|
||||
(await (replay {:world [1 0 {:layout layout :layout-children true :layout-item-margins true}]
|
||||
:ops [[:style 0 property authored 1] [:style 0 property authored 0]
|
||||
[:style 0 property other 0] [:undo] [:redo] [:update-main 0]
|
||||
[:style 0 property other 1] [:reset 0]
|
||||
[:style 0 property other 1] [:detach 0] [:undo] [:redo]]})))))
|
||||
|
||||
(t/deftest ^:async adding-a-flex-child-before-making-a-copy-child-absolute-stays-settled
|
||||
(await (replay {:world [1 0 {:layout :flex :layout-children true}]
|
||||
:ops [[:add-child 0] [:style 2 35 1 1] [:undo] [:redo]]})))
|
||||
|
||||
(t/deftest ^:async nesting-a-copy-alongside-a-hidden-layout-child-stays-settled
|
||||
(await (replay {:world [3 0 {:text true :text-styles true :layout :flex}]
|
||||
:ops [[:delete 9 9 1 2] [:text 5 9 1 3] [:style 3 1 1]
|
||||
|
||||
@ -150,13 +150,20 @@
|
||||
[(dwsl/update-layout-child [id] (select-keys shape [:layout-item-margin
|
||||
:layout-item-margin-type]))])
|
||||
|
||||
(:layout-item-margin-type :layout-item-align-self
|
||||
:layout-item-h-sizing :layout-item-v-sizing
|
||||
:layout-item-min-w :layout-item-max-w
|
||||
:layout-item-min-h :layout-item-max-h
|
||||
:layout-item-absolute :layout-item-z-index)
|
||||
[(dwsl/update-layout-child [id] {property value})]
|
||||
|
||||
;; the layers panel's rename, which renames a main's component too
|
||||
:name
|
||||
[(dw/end-rename-shape id value)]
|
||||
|
||||
;; Container controls use the sidebar transaction and reflow event.
|
||||
(:layout-flex-dir :layout-wrap-type :layout-justify-content
|
||||
:layout-align-content :layout-gap-type :layout-padding-type)
|
||||
:layout-align-content :layout-gap-type :layout-padding-type :layout-justify-items)
|
||||
[(dwsl/update-layout [id] {property value})]
|
||||
|
||||
[(dwsh/update-shapes #{id} (fn [shape] (n/set-property shape property value)))]))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user