Merge pull request #3678 from penpot/alotor-codegen-fixes

Codegen & grid fixes
This commit is contained in:
Aitor Moreno 2023-10-02 12:46:09 +02:00 committed by GitHub
commit 828082ea47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 379 additions and 329 deletions

View file

@ -205,3 +205,6 @@
;; Modifiers
(dm/export gsm/set-objects-modifiers)
;; Rect
(dm/export grc/rect->points)

View file

@ -107,9 +107,7 @@
margin
(if ignore-margin?
0
(->> strokes
(map #(shape-stroke-margin % stroke-width))
(reduce d/max 0)))
(shape-stroke-margin shape stroke-width))
shadow-width
(->> (:shadow shape)
@ -125,8 +123,8 @@
0))
(reduce d/max 0))]
{:horizontal (+ stroke-width margin shadow-width)
:vertical (+ stroke-width margin shadow-height)})))
{:horizontal (mth/ceil (+ stroke-width margin shadow-width))
:vertical (mth/ceil (+ stroke-width margin shadow-height))})))
(defn- add-padding
[bounds padding]

View file

@ -16,6 +16,7 @@
[app.common.types.components-list :as ctkl]
[app.common.types.pages-list :as ctpl]
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -265,7 +266,7 @@
(gpt/add orig-pos delta)
{:skip-components? true
:bottom-frames? true}))
frame-ids-map (volatile! {})
ids-map (volatile! {})
update-new-shape
(fn [new-shape original-shape]
@ -275,8 +276,7 @@
(when (nil? (:parent-id original-shape))
(vswap! unames conj new-name))
(when (= (:type original-shape) :frame)
(vswap! frame-ids-map assoc (:id original-shape) (:id new-shape)))
(vswap! ids-map assoc (:id original-shape) (:id new-shape))
(cond-> new-shape
:always
@ -307,24 +307,29 @@
(dissoc :component-root))))
[new-shape new-shapes _]
(ctst/clone-object component-shape
nil
(if components-v2 (:objects component-page) (:objects component))
update-new-shape
(fn [object _] object)
force-id
keep-ids?)
(ctst/clone-object
component-shape
nil
(if components-v2 (:objects component-page) (:objects component))
update-new-shape
(fn [object _] object)
force-id
keep-ids?)
;; If frame-id points to a shape inside the component, remap it to the
;; corresponding new frame shape. If not, set it to the destination frame.
;; Also fix empty parent-id.
remap-frame-id (fn [shape]
(as-> shape $
(update $ :frame-id #(get @frame-ids-map % frame-id))
(update $ :parent-id #(or % (:frame-id $)))))]
;; If frame-id points to a shape inside the component, remap it to the
;; corresponding new frame shape. If not, set it to the destination frame.
;; Also fix empty parent-id.
remap-ids
(fn [shape]
(as-> shape $
(update $ :frame-id #(get @ids-map % frame-id))
(update $ :parent-id #(or % (:frame-id $)))
(cond-> $
(ctl/grid-layout? shape)
(ctl/remap-grid-cells @ids-map))))]
[(remap-frame-id new-shape)
(map remap-frame-id new-shapes)])))
[(remap-ids new-shape)
(map remap-ids new-shapes)])))
(defn get-top-instance
"The case of having an instance that contains another instances.

View file

@ -1177,3 +1177,15 @@
(for [r (range first-row (inc last-row))
c (range first-column (inc last-column))]
[r c]))))
(defn remap-grid-cells
"Remaps the shapes inside the cells"
[shape ids-map]
(let [do-remap-cells
(fn [cell]
(-> cell
(update :shapes #(mapv ids-map %))))
shape
(-> shape
(update :layout-grid-cells update-vals do-remap-cells))]
shape))

View file

@ -6,6 +6,7 @@
(ns common-tests.types-shape-interactions-test
(:require
[app.common.math :as mth]
[app.common.exceptions :as ex]
[app.common.geom.point :as gpt]
[app.common.geom.rect :as grc]
@ -332,56 +333,56 @@
(t/testing "Overlay top-center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 0))
(t/is (mth/close? (:x overlay-pos) 35))
(t/is (mth/close? (:y overlay-pos) 0))
(t/is (= snap-v :top))
(t/is (= snap-h :center))))
(t/testing "Overlay top-right relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-right base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 70))
(t/is (= (:y overlay-pos) 0))
(t/is (mth/close? (:x overlay-pos) 70))
(t/is (mth/close? (:y overlay-pos) 0))
(t/is (= snap-v :top))
(t/is (= snap-h :right))))
(t/testing "Overlay bottom-left relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-left base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 0))
(t/is (= (:y overlay-pos) 80))
(t/is (mth/close? (:x overlay-pos) 0))
(t/is (mth/close? (:y overlay-pos) 80))
(t/is (= snap-v :bottom))
(t/is (= snap-h :left))))
(t/testing "Overlay bottom-center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 80))
(t/is (mth/close? (:x overlay-pos) 35))
(t/is (mth/close? (:y overlay-pos) 80))
(t/is (= snap-v :bottom))
(t/is (= snap-h :center))))
(t/testing "Overlay bottom-right relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-right base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 70))
(t/is (= (:y overlay-pos) 80))
(t/is (mth/close? (:x overlay-pos) 70))
(t/is (mth/close? (:y overlay-pos) 80))
(t/is (= snap-v :bottom))
(t/is (= snap-h :right))))
(t/testing "Overlay center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 40))
(t/is (mth/close? (:x overlay-pos) 35))
(t/is (mth/close? (:y overlay-pos) 40))
(t/is (= snap-v :center))
(t/is (= snap-h :center))))
(t/testing "Overlay manual relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 40))
(t/is (mth/close? (:x overlay-pos) 35))
(t/is (mth/close? (:y overlay-pos) 40))
(t/is (= snap-v :center))
(t/is (= snap-h :center))))
@ -390,64 +391,64 @@
(ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62)))
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 17))
(t/is (= (:y overlay-pos) 67))
(t/is (mth/close? (:x overlay-pos) 17))
(t/is (mth/close? (:y overlay-pos) 67))
(t/is (= snap-v :top))
(t/is (= snap-h :left))))
(t/testing "Overlay top-left relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-left base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 5))
(t/is (= (:y overlay-pos) 5))
(t/is (mth/close? (:x overlay-pos) 5))
(t/is (mth/close? (:y overlay-pos) 5))
(t/is (= snap-v :top))
(t/is (= snap-h :left))))
(t/testing "Overlay top-center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 40))
(t/is (= (:y overlay-pos) 5))
(t/is (mth/close? (:x overlay-pos) 40))
(t/is (mth/close? (:y overlay-pos) 5))
(t/is (= snap-v :top))
(t/is (= snap-h :center))))
(t/testing "Overlay top-right relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-right base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 75))
(t/is (= (:y overlay-pos) 5))
(t/is (mth/close? (:x overlay-pos) 75))
(t/is (mth/close? (:y overlay-pos) 5))
(t/is (= snap-v :top))
(t/is (= snap-h :right))))
(t/testing "Overlay bottom-left relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-left base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 5))
(t/is (= (:y overlay-pos) 85))
(t/is (mth/close? (:x overlay-pos) 5))
(t/is (mth/close? (:y overlay-pos) 85))
(t/is (= snap-v :bottom))
(t/is (= snap-h :left))))
(t/testing "Overlay bottom-center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 40))
(t/is (= (:y overlay-pos) 85))
(t/is (mth/close? (:x overlay-pos) 40))
(t/is (mth/close? (:y overlay-pos) 85))
(t/is (= snap-v :bottom))
(t/is (= snap-h :center))))
(t/testing "Overlay bottom-right relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-right base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 75))
(t/is (= (:y overlay-pos) 85))
(t/is (mth/close? (:x overlay-pos) 75))
(t/is (mth/close? (:y overlay-pos) 85))
(t/is (= snap-v :bottom))
(t/is (= snap-h :right))))
(t/testing "Overlay center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 40))
(t/is (= (:y overlay-pos) 45))
(t/is (mth/close? (:x overlay-pos) 40))
(t/is (mth/close? (:y overlay-pos) 45))
(t/is (= snap-v :center))
(t/is (= snap-h :center))))
@ -456,64 +457,64 @@
(ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62)))
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 17))
(t/is (= (:y overlay-pos) 67))
(t/is (mth/close? (:x overlay-pos) 17))
(t/is (mth/close? (:y overlay-pos) 67))
(t/is (= snap-v :top))
(t/is (= snap-h :left))))
(t/testing "Overlay top-left relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-left base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 15))
(t/is (= (:y overlay-pos) 15))
(t/is (mth/close? (:x overlay-pos) 15))
(t/is (mth/close? (:y overlay-pos) 15))
(t/is (= snap-v :top))
(t/is (= snap-h :left))))
(t/testing "Overlay top-center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 15))
(t/is (mth/close? (:x overlay-pos) 25))
(t/is (mth/close? (:y overlay-pos) 15))
(t/is (= snap-v :top))
(t/is (= snap-h :center))))
(t/testing "Overlay top-right relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-right base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 15))
(t/is (mth/close? (:x overlay-pos) 35))
(t/is (mth/close? (:y overlay-pos) 15))
(t/is (= snap-v :top))
(t/is (= snap-h :right))))
(t/testing "Overlay bottom-left relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-left base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 15))
(t/is (= (:y overlay-pos) 45))
(t/is (mth/close? (:x overlay-pos) 15))
(t/is (mth/close? (:y overlay-pos) 45))
(t/is (= snap-v :bottom))
(t/is (= snap-h :left))))
(t/testing "Overlay bottom-center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 45))
(t/is (mth/close? (:x overlay-pos) 25))
(t/is (mth/close? (:y overlay-pos) 45))
(t/is (= snap-v :bottom))
(t/is (= snap-h :center))))
(t/testing "Overlay bottom-right relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-right base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 45))
(t/is (mth/close? (:x overlay-pos) 35))
(t/is (mth/close? (:y overlay-pos) 45))
(t/is (= snap-v :bottom))
(t/is (= snap-h :right))))
(t/testing "Overlay center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 30))
(t/is (mth/close? (:x overlay-pos) 25))
(t/is (mth/close? (:y overlay-pos) 30))
(t/is (= snap-v :center))
(t/is (= snap-h :center))))
@ -522,64 +523,64 @@
(ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62)))
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 27))
(t/is (= (:y overlay-pos) 77))
(t/is (mth/close? (:x overlay-pos) 27))
(t/is (mth/close? (:y overlay-pos) 77))
(t/is (= snap-v :top))
(t/is (= snap-h :left))))
(t/testing "Overlay top-left relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-left base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 15))
(t/is (= (:y overlay-pos) 15))
(t/is (mth/close? (:x overlay-pos) 15))
(t/is (mth/close? (:y overlay-pos) 15))
(t/is (= snap-v :top))
(t/is (= snap-h :left))))
(t/testing "Overlay top-center relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :top-center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 15))
(t/is (mth/close? (:x overlay-pos) 25))
(t/is (mth/close? (:y overlay-pos) 15))
(t/is (= snap-v :top))
(t/is (= snap-h :center))))
(t/testing "Overlay top-right relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :top-right base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 15))
(t/is (mth/close? (:x overlay-pos) 35))
(t/is (mth/close? (:y overlay-pos) 15))
(t/is (= snap-v :top))
(t/is (= snap-h :right))))
(t/testing "Overlay bottom-left relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-left base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 15))
(t/is (= (:y overlay-pos) 45))
(t/is (mth/close? (:x overlay-pos) 15))
(t/is (mth/close? (:y overlay-pos) 45))
(t/is (= snap-v :bottom))
(t/is (= snap-h :left))))
(t/testing "Overlay bottom-center relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 45))
(t/is (mth/close? (:x overlay-pos) 25))
(t/is (mth/close? (:y overlay-pos) 45))
(t/is (= snap-v :bottom))
(t/is (= snap-h :center))))
(t/testing "Overlay bottom-right relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :bottom-right base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 45))
(t/is (mth/close? (:x overlay-pos) 35))
(t/is (mth/close? (:y overlay-pos) 45))
(t/is (= snap-v :bottom))
(t/is (= snap-h :right))))
(t/testing "Overlay center relative to rect"
(let [i2 (ctsi/set-overlay-pos-type interaction-rect :center base-frame objects)
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 30))
(t/is (mth/close? (:x overlay-pos) 25))
(t/is (mth/close? (:y overlay-pos) 30))
(t/is (= snap-v :center))
(t/is (= snap-h :center))))
@ -588,8 +589,8 @@
(ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62)))
[overlay-pos [snap-v snap-h]] (ctsi/calc-overlay-position i2 rect objects rect base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 17))
(t/is (= (:y overlay-pos) 67))
(t/is (mth/close? (:x overlay-pos) 17))
(t/is (mth/close? (:y overlay-pos) 67))
(t/is (= snap-v :top))
(t/is (= snap-h :left))))))

View file

@ -330,17 +330,6 @@
(when selected
(rx/of (select-shape (:id selected))))))))
(defn remap-grid-cells
"Remaps the shapes inside the cells"
[shape ids-map]
(let [do-remap-cells
(fn [cell]
(-> cell
(update :shapes #(mapv ids-map %))))]
(update shape :layout-grid-cells update-vals do-remap-cells)))
;; --- Duplicate Shapes
(declare prepare-duplicate-shape-change)
(declare prepare-duplicate-flows)
@ -463,8 +452,7 @@
(d/update-when :interactions #(ctsi/remap-interactions % ids-map objects))
(cond-> (ctl/grid-layout? obj)
(-> (ctl/check-deassigned-cells)
(remap-grid-cells ids-map))))
(ctl/remap-grid-cells ids-map)))
new-obj (cond-> new-obj
(not duplicating-component?)
@ -474,7 +462,7 @@
changes (-> (pcb/add-object changes new-obj {:ignore-touched (and duplicating-component? child?)})
(pcb/amend-last-change #(assoc % :old-id (:id obj)))
(cond-> (ctl/grid-layout? objects (:parent-id obj))
(-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells)
(-> (pcb/update-shapes [(:parent-id obj)] (fn [shape] (-> shape ctl/assign-cells ctl/check-deassigned-cells)))
(pcb/reorder-grid-children [(:parent-id obj)]))))
changes (cond-> changes

View file

@ -25,12 +25,11 @@
handle-load
(mf/use-callback
(fn [data width height]
(prn "handle-load" data)
(reset! last-data* data)
(let [iframe-dom (mf/ref-val iframe-ref)]
(when iframe-dom
(-> iframe-dom (aset "width" width))
(-> iframe-dom (aset "height" height))
(-> iframe-dom (aset "width" (+ width 64)))
(-> iframe-dom (aset "height" (+ height 64)))
(-> iframe-dom .-contentWindow .-document .open)
(-> iframe-dom .-contentWindow .-document (.write data))
(-> iframe-dom .-contentWindow .-document .close)))))
@ -59,13 +58,13 @@
[:div {:style {:display "flex" :width "100%" :height "100%" :flex-direction "column" :overflow "auto" :align-items "center"}}
[:input {:id "zoom-input"
:ref zoom-ref
:type "range" :min 1 :max 200 :default-value 100
:type "range" :min 1 :max 400 :default-value 100
:on-change change-zoom
:style {:max-width "500px"}}]
[:div {:style {:width "100%" :height "100%" :overflow "auto"}}
[:iframe {:ref load-ref
:frameborder "0"
:frame-border "0"
:scrolling "no"
:style {:transform-origin "top center"
:style {:transform-origin "top left"
:transform (str "scale(" zoom ")")}}]]]))

View file

@ -34,6 +34,9 @@
[cuerdas.core :as str]
[rumext.v2 :as mf]))
(def small-size-limit 60)
(def medium-size-limit 110)
(defn apply-to-point [result next-fn]
(conj result (next-fn (last result))))
@ -630,6 +633,10 @@
[(:x text-p) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)]
[(- (:x text-p) (max 0 (:size track-data))) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)])
trackwidth (* text-width zoom)
medium? (and (>= trackwidth small-size-limit) (< trackwidth medium-size-limit))
small? (< trackwidth small-size-limit)
track-before (get-in layout-data [track-list-prop (dec index)])]
(mf/use-effect
@ -644,28 +651,29 @@
(dm/str (gmt/transform-in text-p (:transform shape)))
(dm/str (gmt/transform-in text-p (gmt/rotate (:transform shape) -90))))}
(when hovering?
[:rect {:x (+ text-x (/ 5 zoom))
(when (and hovering? (not small?))
[:rect {:x (+ text-x (/ 18 zoom))
:y text-y
:width (- text-width (/ 10 zoom))
:width (- text-width (/ 36 zoom))
:height (- text-height (/ 5 zoom))
:rx (/ 3 zoom)
:fill "var(--color-distance)"
:opacity 0.2}])
[:foreignObject {:x text-x :y text-y :width text-width :height text-height}
[:div {:class (css :grid-editor-wrapper)}
[:input
{:ref track-input-ref
:style {}
:class (css :grid-editor-label)
:type "text"
:default-value (format-size track-data)
:data-default-value (format-size track-data)
:on-key-down handle-keydown-track-input
:on-blur handle-blur-track-input}]
(when hovering?
[:button {:class (css :grid-editor-button)
:on-click handle-remove-track} i/trash])]]]
(when (not small?)
[:foreignObject {:x text-x :y text-y :width text-width :height text-height}
[:div {:class (css :grid-editor-wrapper)}
[:input
{:ref track-input-ref
:style {}
:class (css :grid-editor-label)
:type "text"
:default-value (format-size track-data)
:data-default-value (format-size track-data)
:on-key-down handle-keydown-track-input
:on-blur handle-blur-track-input}]
(when (and hovering? (not medium?) (not small?))
[:button {:class (css :grid-editor-button)
:on-click handle-remove-track} i/trash])]])]
[:g {:transform (when (= type :row) (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p)))}
[:& track-marker
@ -782,106 +790,107 @@
(fn []
#(st/emit! (dwge/stop-grid-layout-editing (:id shape)))))
[:g.grid-editor {:pointer-events (when view-only "none")
:on-pointer-down handle-pointer-down}
[:g.cells
(for [cell (ctl/get-cells shape {:sort? true})]
[:& grid-cell {:key (dm/str "cell-" (:id cell))
:shape base-shape
:layout-data layout-data
:cell cell
(when (and (not (:hidden shape)) (not (:blocked shape)))
[:g.grid-editor {:pointer-events (when view-only "none")
:on-pointer-down handle-pointer-down}
[:g.cells
(for [cell (ctl/get-cells shape {:sort? true})]
[:& grid-cell {:key (dm/str "cell-" (:id cell))
:shape base-shape
:layout-data layout-data
:cell cell
:zoom zoom
:hover? (contains? hover-cells (:id cell))
:selected? (contains? selected-cells (:id cell))}])]
(when-not view-only
[:*
[:& grid-editor-frame {:zoom zoom
:bounds bounds}]
(let [start-p (-> origin (gpt/add (hv width)))]
[:g {:transform (dm/str (gmt/transform-in start-p (:transform shape)))}
[:& plus-btn {:start-p start-p
:zoom zoom
:type :column
:on-click handle-add-column}]])
(let [start-p (-> origin (gpt/add (vv height)))]
[:g {:transform (dm/str (gmt/transform-in start-p (:transform shape)))}
[:& plus-btn {:start-p start-p
:zoom zoom
:type :row
:on-click handle-add-row}]])
(for [[idx column-data] (d/enumerate column-tracks)]
[:& track {:key (dm/str "column-track-" idx)
:shape shape
:zoom zoom
:hover? (contains? hover-cells (:id cell))
:selected? (contains? selected-cells (:id cell))}])]
(when-not view-only
[:*
[:& grid-editor-frame {:zoom zoom
:bounds bounds}]
(let [start-p (-> origin (gpt/add (hv width)))]
[:g {:transform (dm/str (gmt/transform-in start-p (:transform shape)))}
[:& plus-btn {:start-p start-p
:zoom zoom
:type :column
:on-click handle-add-column}]])
:type :column
:index idx
:layout-data layout-data
:snap-pixel? snap-pixel?
:track-data column-data
:hovering? (contains? hover-columns idx)}])
(let [start-p (-> origin (gpt/add (vv height)))]
[:g {:transform (dm/str (gmt/transform-in start-p (:transform shape)))}
[:& plus-btn {:start-p start-p
:zoom zoom
:type :row
:on-click handle-add-row}]])
;; Last track resize handler
(when-not (empty? column-tracks)
(let [last-track (last column-tracks)
start-p (:start-p last-track)
end-p (gpt/add start-p (hv (:size last-track)))
marker-p (-> (gpo/project-point bounds :h end-p)
(gpt/subtract (vv (/ 20 zoom))))]
[:g.track
[:& track-marker {:center marker-p
:index (count column-tracks)
:shape shape
:snap-pixel? snap-pixel?
:track-before (last column-tracks)
:type :column
:value (dm/str (inc (count column-tracks)))
:zoom zoom}]
[:& resize-track-handler
{:index (count column-tracks)
:last? true
:shape shape
:layout-data layout-data
:snap-pixel? snap-pixel?
:start-p end-p
:type :column
:track-before (last column-tracks)
:zoom zoom}]]))
(for [[idx column-data] (d/enumerate column-tracks)]
[:& track {:key (dm/str "column-track-" idx)
:shape shape
:zoom zoom
:type :column
:index idx
:layout-data layout-data
:snap-pixel? snap-pixel?
:track-data column-data
:hovering? (contains? hover-columns idx)}])
;; Last track resize handler
(when-not (empty? column-tracks)
(let [last-track (last column-tracks)
start-p (:start-p last-track)
end-p (gpt/add start-p (hv (:size last-track)))
marker-p (-> (gpo/project-point bounds :h end-p)
(gpt/subtract (vv (/ 20 zoom))))]
[:g.track
[:& track-marker {:center marker-p
:index (count column-tracks)
:shape shape
:snap-pixel? snap-pixel?
:track-before (last column-tracks)
:type :column
:value (dm/str (inc (count column-tracks)))
:zoom zoom}]
[:& resize-track-handler
{:index (count column-tracks)
:last? true
:shape shape
:layout-data layout-data
:snap-pixel? snap-pixel?
:start-p end-p
:type :column
:track-before (last column-tracks)
:zoom zoom}]]))
(for [[idx row-data] (d/enumerate row-tracks)]
[:& track {:index idx
:key (dm/str "row-track-" idx)
:layout-data layout-data
:shape shape
:snap-pixel? snap-pixel?
:track-data row-data
:type :row
:zoom zoom
:hovering? (contains? hover-rows idx)}])
(when-not (empty? row-tracks)
(let [last-track (last row-tracks)
start-p (:start-p last-track)
end-p (gpt/add start-p (vv (:size last-track)))
marker-p (-> (gpo/project-point bounds :v end-p)
(gpt/subtract (hv (/ 20 zoom))))]
[:g.track
[:g {:transform (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p))}
[:& track-marker {:center marker-p
:index (count row-tracks)
:shape shape
:snap-pixel? snap-pixel?
:track-before (last row-tracks)
:type :row
:value (dm/str (inc (count row-tracks)))
:zoom zoom}]]
[:& resize-track-handler
{:index (count row-tracks)
:last? true
:shape shape
:layout-data layout-data
:start-p end-p
:type :row
:track-before (last row-tracks)
:snap-pixel? snap-pixel?
:zoom zoom}]]))])]))
(for [[idx row-data] (d/enumerate row-tracks)]
[:& track {:index idx
:key (dm/str "row-track-" idx)
:layout-data layout-data
:shape shape
:snap-pixel? snap-pixel?
:track-data row-data
:type :row
:zoom zoom
:hovering? (contains? hover-rows idx)}])
(when-not (empty? row-tracks)
(let [last-track (last row-tracks)
start-p (:start-p last-track)
end-p (gpt/add start-p (vv (:size last-track)))
marker-p (-> (gpo/project-point bounds :v end-p)
(gpt/subtract (hv (/ 20 zoom))))]
[:g.track
[:g {:transform (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p))}
[:& track-marker {:center marker-p
:index (count row-tracks)
:shape shape
:snap-pixel? snap-pixel?
:track-before (last row-tracks)
:type :row
:value (dm/str (inc (count row-tracks)))
:zoom zoom}]]
[:& resize-track-handler
{:index (count row-tracks)
:last? true
:shape shape
:layout-data layout-data
:start-p end-p
:type :row
:track-before (last row-tracks)
:snap-pixel? snap-pixel?
:zoom zoom}]]))])])))

View file

@ -46,7 +46,7 @@
margin: 0;
padding: 0;
position: absolute;
right: calc(10px / var(--zoom));
right: calc(20px / var(--zoom));
width: calc(20px / var(--zoom));
height: calc(20px / var(--zoom));
@ -80,12 +80,12 @@
.grid-cell-outline {
fill: transparent;
stroke: var(--color-distance);
stroke-linecap: round;
stroke-width: calc(2 / var(--zoom));
stroke-dasharray: 0 calc(8 / var(--zoom));
stroke-opacity: 0.5;
stroke-width: calc(1 / var(--zoom));
&.hover,
&.selected {
stroke-dasharray: initial;
stroke-opacity: 1;
stroke-width: calc(2 / var(--zoom));
}
}

View file

@ -58,5 +58,6 @@
[objects shape]
;; Layout children with a transform should be wrapped
(and (ctl/any-layout-immediate-child? objects shape)
(not (ctl/layout-absolute? shape))
(not (gmt/unit? (:transform shape)))))

View file

@ -23,68 +23,69 @@
(generate-html objects shape 0))
([objects shape level]
(let [indent (str/repeat " " level)
maybe-reverse (if (ctl/any-layout? shape) reverse identity)
(when (and (some? shape) (some? (:selrect shape)))
(let [indent (str/repeat " " level)
maybe-reverse (if (ctl/any-layout? shape) reverse identity)
shape-html
(cond
(cgc/svg-markup? shape)
(let [svg-markup (generate-svg objects shape)]
shape-html
(cond
(cgc/svg-markup? shape)
(let [svg-markup (generate-svg objects shape)]
(dm/fmt "%<div class=\"%\">\n%\n%</div>"
indent
(dm/str "shape " (d/name (:type shape)) " "
(cgc/shape->selector shape))
svg-markup
indent))
(cph/text-shape? shape)
(let [text-shape-html (rds/renderToStaticMarkup (mf/element text/text-shape #js {:shape shape :code? true}))]
(dm/fmt "%<div class=\"%\">\n%\n%</div>"
indent
(dm/str "shape " (d/name (:type shape)) " "
(cgc/shape->selector shape))
text-shape-html
indent))
(cph/image-shape? shape)
(let [data (or (:metadata shape) (:fill-image shape))
image-url (cfg/resolve-file-media data)]
(dm/fmt "%<img src=\"%\" class=\"%\">\n%</img>"
indent
image-url
(dm/str "shape " (d/name (:type shape)) " "
(cgc/shape->selector shape))
indent))
(empty? (:shapes shape))
(dm/fmt "%<div class=\"%\">\n%</div>"
indent
(dm/str "shape " (d/name (:type shape)) " "
(cgc/shape->selector shape))
indent)
:else
(dm/fmt "%<div class=\"%\">\n%\n%</div>"
indent
(dm/str "shape " (d/name (:type shape)) " "
(dm/str (d/name (:type shape)) " "
(cgc/shape->selector shape))
svg-markup
(->> (:shapes shape)
(maybe-reverse)
(map #(generate-html objects (get objects %) (inc level)))
(str/join "\n"))
indent))
(cph/text-shape? shape)
(let [text-shape-html (rds/renderToStaticMarkup (mf/element text/text-shape #js {:shape shape :code? true}))]
(dm/fmt "%<div class=\"%\">\n%\n%</div>"
indent
(dm/str "shape " (d/name (:type shape)) " "
(cgc/shape->selector shape))
text-shape-html
indent))
shape-html
(if (cgc/has-wrapper? objects shape)
(dm/fmt "<div class=\"%\">%</div>"
(dm/str (cgc/shape->selector shape) "-wrapper")
shape-html)
(cph/image-shape? shape)
(let [data (or (:metadata shape) (:fill-image shape))
image-url (cfg/resolve-file-media data)]
(dm/fmt "%<img src=\"%\" class=\"%\">\n%</img>"
indent
image-url
(dm/str "shape " (d/name (:type shape)) " "
(cgc/shape->selector shape))
indent))
(empty? (:shapes shape))
(dm/fmt "%<div class=\"%\">\n%</div>"
indent
(dm/str "shape " (d/name (:type shape)) " "
(cgc/shape->selector shape))
indent)
:else
(dm/fmt "%<div class=\"%\">\n%\n%</div>"
indent
(dm/str (d/name (:type shape)) " "
(cgc/shape->selector shape))
(->> (:shapes shape)
(maybe-reverse)
(map #(generate-html objects (get objects %) (inc level)))
(str/join "\n"))
indent))
shape-html
(if (cgc/has-wrapper? objects shape)
(dm/fmt "<div class=\"%\">%</div>"
(dm/str (cgc/shape->selector shape) "-wrapper")
shape-html)
shape-html)]
(dm/fmt "%<!-- % -->\n%" indent (dm/str (d/name (:type shape)) ": " (:name shape)) shape-html))))
shape-html)]
(dm/fmt "%<!-- % -->\n%" indent (dm/str (d/name (:type shape)) ": " (:name shape)) shape-html)))))
(defn generate-markup
[objects shapes]
(->> shapes
(map #(generate-html objects %))
(keep #(generate-html objects %))
(str/join "\n")))

View file

@ -9,7 +9,8 @@
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.matrix :as gmt]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.bounds :as gsb]
[app.common.geom.shapes.points :as gpo]
[app.common.pages.helpers :as cph]
[app.common.text :as txt]
[app.common.types.shape.layout :as ctl]
@ -38,13 +39,6 @@ body {
gap: 2rem;
}
svg {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
* {
box-sizing: border-box;
}
@ -64,7 +58,10 @@ svg {
:justify-self
:grid-column
:grid-row
:z-index})
:z-index
:top
:left
:position})
(def shape-css-properties
[:position
@ -139,12 +136,16 @@ svg {
[shape objects]
(when (and (ctl/any-layout-immediate-child? objects shape)
(not (gmt/unit? (:transform shape))))
(let [{:keys [width height]} (gsh/shapes->rect [shape])]
(cond-> [[:position "relative"]
[:width width]
(let [parent (get objects (:parent-id shape))
bounds (gpo/parent-coords-bounds (:points shape) (:points parent))
width (gpo/width-points bounds)
height (gpo/height-points bounds)]
(cond-> [[:width width]
[:height height]]
(ctl/flex-layout-immediate-child? objects shape)
(conj [:flex-shrink 0])))))
(or (not (ctl/any-layout-immediate-child? objects shape))
(not (ctl/layout-absolute? shape)))
(conj [:position "relative"])))))
(defn shape->wrapper-child-css-properties
[shape objects]
@ -153,6 +154,16 @@ svg {
[:left "50%"]
[:top "50%"]]))
(defn shape->svg-props
[shape objects]
(let [bounds (gsb/get-object-bounds objects shape)]
[[:position "absolute"]
[:top 0]
[:left 0]
[:transform (dm/fmt "translate(%,%)"
(dm/str (- (:x bounds) (-> shape :selrect :x)) "px")
(dm/str (- (:y bounds) (-> shape :selrect :y)) "px"))]]))
(defn shape->css-properties
"Given a shape extract the CSS properties in the format of list [property value]"
[shape objects properties]
@ -235,40 +246,49 @@ svg {
(get-shape-css-selector shape objects nil))
([shape objects options]
(let [selector (cgc/shape->selector shape)
(when (and (some? shape) (some? (:selrect shape)))
(let [selector (cgc/shape->selector shape)
wrapper? (cgc/has-wrapper? objects shape)
wrapper? (cgc/has-wrapper? objects shape)
svg? (cgc/svg-markup? shape)
css-properties
(if wrapper?
(filter (complement shape-wrapper-css-properties) shape-css-properties)
shape-css-properties)
css-properties
(if wrapper?
(filter (complement shape-wrapper-css-properties) shape-css-properties)
shape-css-properties)
properties
(-> shape
(shape->css-properties objects css-properties)
(format-css-properties options))
wrapper-properties
(when wrapper?
(-> (d/concat-vec
(shape->css-properties shape objects shape-wrapper-css-properties)
(shape->wrapper-css-properties shape objects))
(format-css-properties options)))
wrapper-child-properties
(when wrapper?
properties
(-> shape
(shape->wrapper-child-css-properties objects)
(format-css-properties options)))]
(shape->css-properties objects css-properties)
(format-css-properties options))
(str/join
"\n"
(filter some? [(str/fmt "/* %s */" (:name shape))
(when wrapper? (str/fmt ".%s-wrapper {\n%s\n}" selector wrapper-properties))
(when wrapper? (str/fmt ".%s-wrapper > * {\n%s\n}" selector wrapper-child-properties))
(str/fmt ".%s {\n%s\n}" selector properties)
(when (cph/text-shape? shape) (generate-text-css shape))])))))
wrapper-properties
(when wrapper?
(-> (d/concat-vec
(shape->css-properties shape objects shape-wrapper-css-properties)
(shape->wrapper-css-properties shape objects))
(format-css-properties options)))
wrapper-child-properties
(when wrapper?
(-> shape
(shape->wrapper-child-css-properties objects)
(format-css-properties options)))
svg-child-props
(when svg?
(-> shape
(shape->svg-props objects)
(format-css-properties options)))]
(str/join
"\n"
(filter some? [(str/fmt "/* %s */" (:name shape))
(when wrapper? (str/fmt ".%s-wrapper {\n%s\n}" selector wrapper-properties))
(when wrapper? (str/fmt ".%s-wrapper > * {\n%s\n}" selector wrapper-child-properties))
(when svg? (str/fmt ".%s > svg {\n%s\n}" selector svg-child-props))
(str/fmt ".%s {\n%s\n}" selector properties)
(when (cph/text-shape? shape) (generate-text-css shape))]))))))
(defn get-css-property
([objects shape property]
@ -294,5 +314,5 @@ svg {
(dm/str
prelude
(->> shapes
(map #(get-shape-css-selector % objects options))
(keep #(get-shape-css-selector % objects options))
(str/join "\n\n")))))

View file

@ -49,12 +49,14 @@
(when (and (not (cph/root-frame? shape))
(or (not (ctl/any-layout-immediate-child? objects shape))
(ctl/layout-absolute? shape)))
(let [parent (get objects (:parent-id shape))
parent-value (dm/get-in parent [:selrect coord])
[selrect _ _]
(-> (:points shape)
(gsh/transform-points (gsh/shape->center parent) (:transform-inverse parent))
(gsh/transform-points (gsh/shape->center parent) (:transform-inverse parent (gmt/matrix)))
(gsh/calculate-geometry))
shape-value (get selrect coord)]
@ -117,7 +119,17 @@
(defmethod get-value :transform
[_ shape objects]
(when-not (cgc/svg-markup? shape)
(if (cgc/svg-markup? shape)
(let [parent (get objects (:parent-id shape))
transform
(:transform-inverse parent (gmt/matrix))
transform-str (when-not (gmt/unit? transform) (fmt/format-matrix transform))]
(if (cgc/has-wrapper? objects shape)
(dm/str "translate(-50%, -50%) " (d/nilv transform-str ""))
transform-str))
(let [parent (get objects (:parent-id shape))
transform
@ -207,6 +219,7 @@
(defmethod get-value :overflow
[_ shape _]
(when (and (cph/frame-shape? shape)
(not (cgc/svg-markup? shape))
(not (:show-content shape)))
"hidden"))