Merge pull request #3900 from penpot/alotor-grid-improvements

Alotor grid improvements
This commit is contained in:
Eva Marco 2023-12-11 14:36:28 +01:00 committed by GitHub
commit 1e7ffb10b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 846 additions and 749 deletions

View file

@ -82,7 +82,6 @@
children children
(->> children (->> children
(keep (d/getf objects)) (keep (d/getf objects))
(remove :hidden)
(remove gco/invalid-geometry?) (remove gco/invalid-geometry?)
(map (partial apply-modifiers bounds))) (map (partial apply-modifiers bounds)))
@ -169,13 +168,13 @@
children-modifiers children-modifiers
(if (or flex-layout? grid-layout?) (if (or flex-layout? grid-layout?)
(->> (:shapes parent) (->> (:shapes parent)
(filter #(ctl/layout-absolute? objects %))) (filter #(ctl/position-absolute? objects %)))
(:shapes parent)) (:shapes parent))
children-layout children-layout
(when (or flex-layout? grid-layout?) (when (or flex-layout? grid-layout?)
(->> (:shapes parent) (->> (:shapes parent)
(remove #(ctl/layout-absolute? objects %))))] (remove #(ctl/position-absolute? objects %))))]
(cond-> modif-tree (cond-> modif-tree
(and has-modifiers? parent? (not root?)) (and has-modifiers? parent? (not root?))
@ -222,7 +221,7 @@
(ctm/resize (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent))))) (ctm/resize (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))
children (->> (cfh/get-immediate-children objects parent-id) children (->> (cfh/get-immediate-children objects parent-id)
(remove :hidden) (remove ctl/position-absolute?)
(remove gco/invalid-geometry?)) (remove gco/invalid-geometry?))
content-bounds content-bounds

View file

@ -299,7 +299,7 @@
ignore-constraints ignore-constraints
:scale :scale
(and (ctl/any-layout? parent) (not (ctl/layout-absolute? child))) (and (ctl/any-layout? parent) (not (ctl/position-absolute? child)))
:left :left
:else :else
@ -310,7 +310,7 @@
ignore-constraints ignore-constraints
:scale :scale
(and (ctl/any-layout? parent) (not (ctl/layout-absolute? child))) (and (ctl/any-layout? parent) (not (ctl/position-absolute? child)))
:top :top
:else :else
@ -335,13 +335,14 @@
child-bounds (gtr/transform-bounds child-bounds modifiers) child-bounds (gtr/transform-bounds child-bounds modifiers)
parent-bounds transformed-parent-bounds)) parent-bounds transformed-parent-bounds))
transformed-child-bounds (if reset-modifiers? transformed-child-bounds
child-bounds (if reset-modifiers?
(gtr/transform-bounds child-bounds modifiers))] child-bounds
(gtr/transform-bounds child-bounds modifiers))]
;; If the parent is a layout we don't need to calculate its constraints. Finish ;; If the parent is a layout we don't need to calculate its constraints. Finish
;; after normalize the children (to keep proper proportions) ;; after normalize the children (to keep proper proportions)
(if (ctl/any-layout? parent) (if (and (ctl/any-layout? parent) (not (ctl/position-absolute? child)))
modifiers modifiers
(let [child-points-before (gpo/parent-coords-bounds child-bounds parent-bounds) (let [child-points-before (gpo/parent-coords-bounds child-bounds parent-bounds)
child-points-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds) child-points-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds)

View file

@ -421,8 +421,12 @@
reverse? (ctl/reverse? shape) reverse? (ctl/reverse? shape)
children (cond->> children (not reverse?) reverse) children (cond->> children (not reverse?) reverse)
ignore-child?
(fn [[_ child]]
(ctl/position-absolute? child))
;; Don't take into account absolute children ;; Don't take into account absolute children
children (->> children (remove (comp ctl/layout-absolute? second))) children (->> children (remove ignore-child?))
;; Creates the layout lines information ;; Creates the layout lines information
layout-lines layout-lines

View file

@ -424,7 +424,7 @@
children children
(->> children (->> children
(remove #(ctl/layout-absolute? (second %)))) (remove #(ctl/position-absolute? (second %))))
children-map children-map
(into {} (into {}

View file

@ -178,7 +178,7 @@
position-delta (child-position-delta parent child child-bounds child-width child-height layout-data cell-data)] position-delta (child-position-delta parent child child-bounds child-width child-height layout-data cell-data)]
(cond-> (ctm/empty) (cond-> (ctm/empty)
(not (ctl/layout-absolute? child)) (not (ctl/position-absolute? child))
(-> (ctm/add-modifiers fill-modifiers) (-> (ctm/add-modifiers fill-modifiers)
(ctm/move position-delta))))) (ctm/move position-delta)))))

View file

@ -491,12 +491,19 @@
(defn align-self-stretch? [{:keys [layout-item-align-self]}] (defn align-self-stretch? [{:keys [layout-item-align-self]}]
(= :stretch layout-item-align-self)) (= :stretch layout-item-align-self))
(defn layout-absolute? (defn item-absolute?
([objects id] ([objects id]
(layout-absolute? (get objects id))) (item-absolute? (get objects id)))
([shape] ([shape]
(true? (:layout-item-absolute shape)))) (true? (:layout-item-absolute shape))))
(defn position-absolute?
([objects id]
(position-absolute? (get objects id)))
([shape]
(or (item-absolute? shape)
(:hidden shape))))
(defn layout-z-index (defn layout-z-index
([objects id] ([objects id]
(layout-z-index (get objects id))) (layout-z-index (get objects id)))
@ -509,11 +516,11 @@
(auto-width? objects frame-id) (auto-width? objects frame-id)
(or (and (col? objects frame-id) (or (and (col? objects frame-id)
(->> children-ids (->> children-ids
(remove (partial layout-absolute? objects)) (remove (partial position-absolute? objects))
(every? (partial fill-width? objects)))) (every? (partial fill-width? objects))))
(and (row? objects frame-id) (and (row? objects frame-id)
(->> children-ids (->> children-ids
(remove (partial layout-absolute? objects)) (remove (partial position-absolute? objects))
(some (partial fill-width? objects))))))) (some (partial fill-width? objects)))))))
(defn change-v-sizing? (defn change-v-sizing?
@ -705,8 +712,9 @@
(update :layout-grid-cells update-cells) (update :layout-grid-cells update-cells)
(assign-cells)))) (assign-cells))))
(defn- reorder-grid-track (defn- reorder-grid-tracks
[prop parent from-index to-index] "Swap the positions of the tracks info"
[parent prop from-index to-index]
(-> parent (-> parent
(update (update
prop prop
@ -720,13 +728,70 @@
(d/insert-at-index (inc to-index) [[nil tr]]) (d/insert-at-index (inc to-index) [[nil tr]])
(d/vec-without-nils)))))))) (d/vec-without-nils))))))))
(defn- swap-track-content
"Swap the shapes contained in the given tracks moves as necessary the others."
[parent prop from-track to-track]
(let [remap-tracks
(cond
(> from-track to-track)
(into {from-track to-track}
(map #(vector % (inc %)))
(range to-track from-track))
(< from-track to-track)
(into {from-track to-track}
(map #(vector % (dec %)))
(range (inc from-track) (inc to-track))))]
(-> parent
(update
:layout-grid-cells
update-vals
(fn [cell] (update cell prop #(get remap-tracks % %)))))))
(declare resize-cell-area)
(declare cells-by-column)
(declare cells-by-row)
(defn- reorder-grid-track
[parent from-index to-index move-content? cells-by tracks-props prop prop-span]
(let [from-track (inc from-index)
to-track (if (< to-index from-index)
(+ to-index 2)
(inc to-index))
move-content?
(and move-content? (not= from-track to-track))
parent
(if move-content?
(->> (concat (cells-by parent (dec from-track))
(cells-by parent (dec to-track)))
(reduce (fn [parent cell]
(cond-> parent
(and (> (get cell prop-span) 1)
(or (> to-track from-track) (not (= to-track (get cell prop))))
(or (< to-track from-track) (not (= to-track (+ (get cell prop) (dec (get cell prop-span)))))))
(resize-cell-area
(:row cell)
(:column cell)
(:row cell)
(:column cell)
(if (= prop :row) 1 (:row-span cell))
(if (= prop :column) 1 (:column-span cell)))))
parent))
parent)
parent
(reorder-grid-tracks parent tracks-props from-index to-index)]
(cond-> parent
move-content?
(swap-track-content prop from-track to-track))))
(defn reorder-grid-column (defn reorder-grid-column
[parent from-index to-index] [parent from-index to-index move-content?]
(reorder-grid-track :layout-grid-columns parent from-index to-index)) (reorder-grid-track parent from-index to-index move-content? cells-by-column :layout-grid-columns :column :column-span))
(defn reorder-grid-row (defn reorder-grid-row
[parent from-index to-index] [parent from-index to-index move-content?]
(reorder-grid-track :layout-grid-rows parent from-index to-index)) (reorder-grid-track parent from-index to-index move-content? cells-by-row :layout-grid-rows :row :row-span))
(defn cells-seq (defn cells-seq
[{:keys [layout-grid-cells layout-grid-dir]} & {:keys [sort?] :or {sort? false}}] [{:keys [layout-grid-cells layout-grid-dir]} & {:keys [sort?] :or {sort? false}}]
@ -992,9 +1057,8 @@
(defn resize-cell-area (defn resize-cell-area
"Increases/decreases the cell size" "Increases/decreases the cell size"
[parent row column new-row new-column new-row-span new-column-span] [parent row column new-row new-column new-row-span new-column-span]
(if (and (>= new-row 1)
(if (and (>= new-row 0) (>= new-column 1)
(>= new-column 0)
(>= new-row-span 1) (>= new-row-span 1)
(>= new-column-span 1)) (>= new-column-span 1))
(let [prev-cell (cell-by-row-column parent row column) (let [prev-cell (cell-by-row-column parent row column)
@ -1112,7 +1176,7 @@
(update :shapes #(d/removev children %)) (update :shapes #(d/removev children %))
(assign-cells)) (assign-cells))
children (->> children (remove #(layout-absolute? objects %)))] children (->> children (remove #(position-absolute? objects %)))]
(-> frame (-> frame
(update :shapes d/concat-vec children) (update :shapes d/concat-vec children)
@ -1146,22 +1210,30 @@
(assoc parent :shapes (into [] (reverse new-shapes))))) (assoc parent :shapes (into [] (reverse new-shapes)))))
(defn shapes-by-row (defn cells-by-row
[parent index] [parent index]
(->> (:layout-grid-cells parent) (->> (:layout-grid-cells parent)
(filter (fn [[_ {:keys [row row-span]}]] (filter (fn [[_ {:keys [row row-span]}]]
(and (>= (inc index) row) (and (>= (inc index) row)
(< (inc index) (+ row row-span))))) (< (inc index) (+ row row-span)))))
(map second) (map second)))
(mapcat :shapes)))
(defn shapes-by-column (defn cells-by-column
[parent index] [parent index]
(->> (:layout-grid-cells parent) (->> (:layout-grid-cells parent)
(filter (fn [[_ {:keys [column column-span]}]] (filter (fn [[_ {:keys [column column-span]}]]
(and (>= (inc index) column) (and (>= (inc index) column)
(< (inc index) (+ column column-span))))) (< (inc index) (+ column column-span)))))
(map second) (map second)))
(defn shapes-by-row
[parent index]
(->> (cells-by-row parent index)
(mapcat :shapes)))
(defn shapes-by-column
[parent index]
(->> (cells-by-column parent index)
(mapcat :shapes))) (mapcat :shapes)))
(defn cells-coordinates (defn cells-coordinates

View file

@ -1039,9 +1039,7 @@
(rx/of (dwe/start-edition-mode id)) (rx/of (dwe/start-edition-mode id))
(:group :bool :frame) (:group :bool :frame)
(let [shapes-ids (into (d/ordered-set) (let [shapes-ids (into (d/ordered-set) shapes)]
(remove #(dm/get-in objects [% :hidden]))
shapes)]
(rx/of (dws/select-shapes shapes-ids))) (rx/of (dws/select-shapes shapes-ids)))
:svg-raw :svg-raw

View file

@ -7,6 +7,7 @@
(ns app.main.data.workspace.grid-layout.editor (ns app.main.data.workspace.grid-layout.editor
(:require (:require
[app.common.geom.rect :as grc] [app.common.geom.rect :as grc]
[app.common.types.shape.layout :as ctl]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[potok.core :as ptk])) [potok.core :as ptk]))
@ -84,3 +85,18 @@
(-> local (-> local
(update :vbox merge (select-keys srect [:x :y :x1 :x2 :y1 :y2]))))))))))) (update :vbox merge (select-keys srect [:x :y :x1 :x2 :y1 :y2])))))))))))
(defn select-track-cells
[grid-id type index]
(ptk/reify ::select-track-cells
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
parent (get objects grid-id)
cells
(if (= type :column)
(ctl/cells-by-column parent index)
(ctl/cells-by-row parent index))
selected (into #{} (map :id) cells)]
(assoc-in state [:workspace-grid-edition grid-id :selected] selected)))))

View file

@ -193,7 +193,7 @@
(update :shapes #(d/removev ids %)) (update :shapes #(d/removev ids %))
(ctl/assign-cells)) (ctl/assign-cells))
ids (->> ids (remove #(ctl/layout-absolute? objects %))) ids (->> ids (remove #(ctl/position-absolute? objects %)))
frame (-> frame frame (-> frame
(update :shapes d/concat-vec ids) (update :shapes d/concat-vec ids)
(cond-> (some? cell) (cond-> (some? cell)

View file

@ -285,7 +285,7 @@
(dwu/commit-undo-transaction undo-id)))))) (dwu/commit-undo-transaction undo-id))))))
(defn reorder-layout-track (defn reorder-layout-track
[ids type from-index to-index] [ids type from-index to-index move-content?]
(assert (#{:row :column} type)) (assert (#{:row :column} type))
(ptk/reify ::reorder-layout-track (ptk/reify ::reorder-layout-track
@ -297,8 +297,8 @@
ids ids
(fn [shape] (fn [shape]
(case type (case type
:row (ctl/reorder-grid-row shape from-index to-index) :row (ctl/reorder-grid-row shape from-index to-index move-content?)
:column (ctl/reorder-grid-column shape from-index to-index)))) :column (ctl/reorder-grid-column shape from-index to-index move-content?))))
(ptk/data-event :layout/update ids) (ptk/data-event :layout/update ids)
(dwu/commit-undo-transaction undo-id)))))) (dwu/commit-undo-transaction undo-id))))))
@ -311,11 +311,13 @@
(update [_ state] (update [_ state]
(let [objects (wsh/lookup-page-objects state) (let [objects (wsh/lookup-page-objects state)
shape (get objects (first ids)) shape (get objects (first ids))
highlighted (when hover?
(->> (if (= type :row) highlighted
(ctl/shapes-by-row shape index) (when hover?
(ctl/shapes-by-column shape index)) (->> (if (= type :row)
(set)))] (ctl/shapes-by-row shape index)
(ctl/shapes-by-column shape index))
(set)))]
(cond-> state (cond-> state
hover? hover?
(update-in [:workspace-grid-edition (first ids) :hover-track] (fnil conj #{}) [type index]) (update-in [:workspace-grid-edition (first ids) :hover-track] (fnil conj #{}) [type index])
@ -359,7 +361,7 @@
all-children (->> parent all-children (->> parent
:shapes :shapes
(map (d/getf objects)) (map (d/getf objects))
(remove ctl/layout-absolute?))] (remove ctl/position-absolute?))]
(cond-> shape (cond-> shape
;; If the parent is hug width and the direction column ;; If the parent is hug width and the direction column

View file

@ -721,7 +721,7 @@
selected (wsh/lookup-selected state {:omit-blocked? true}) selected (wsh/lookup-selected state {:omit-blocked? true})
selected-shapes (->> selected (map (d/getf objects)))] selected-shapes (->> selected (map (d/getf objects)))]
(if (every? #(and (ctl/any-layout-immediate-child? objects %) (if (every? #(and (ctl/any-layout-immediate-child? objects %)
(not (ctl/layout-absolute? %))) (not (ctl/position-absolute? %)))
selected-shapes) selected-shapes)
(rx/of (reorder-selected-layout-child direction)) (rx/of (reorder-selected-layout-child direction))
(rx/of (nudge-selected-shapes direction shift?))))))) (rx/of (nudge-selected-shapes direction shift?)))))))
@ -829,7 +829,7 @@
moving-shapes moving-shapes
(->> moving-shapes (->> moving-shapes
(remove (fn [shape] (remove (fn [shape]
(and (ctl/layout-absolute? shape) (and (ctl/position-absolute? shape)
(= frame-id (:parent-id shape)))))) (= frame-id (:parent-id shape))))))
frame-component frame-component

View file

@ -26,6 +26,7 @@
[app.common.types.file :as ctf] [app.common.types.file :as ctf]
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.types.shape-tree :as ctst] [app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl]
[app.config :as cfg] [app.config :as cfg]
[app.main.fonts :as fonts] [app.main.fonts :as fonts]
[app.main.ui.context :as muc] [app.main.ui.context :as muc]
@ -34,6 +35,7 @@
[app.main.ui.shapes.embed :as embed] [app.main.ui.shapes.embed :as embed]
[app.main.ui.shapes.export :as export] [app.main.ui.shapes.export :as export]
[app.main.ui.shapes.frame :as frame] [app.main.ui.shapes.frame :as frame]
[app.main.ui.shapes.grid-layout-viewer :refer [grid-layout-viewer]]
[app.main.ui.shapes.group :as group] [app.main.ui.shapes.group :as group]
[app.main.ui.shapes.image :as image] [app.main.ui.shapes.image :as image]
[app.main.ui.shapes.path :as path] [app.main.ui.shapes.path :as path]
@ -304,11 +306,22 @@
:fill "none"} :fill "none"}
[:& shape-wrapper {:shape frame}]]])) [:& shape-wrapper {:shape frame}]]]))
(mf/defc empty-grids
{::mf/wrap-props false}
[{:keys [root-shape-id objects]}]
(let [empty-grids
(->> (cons root-shape-id (cfh/get-children-ids objects root-shape-id))
(filter #(ctl/grid-layout? objects %))
(map #(get objects %))
(filter #(empty? (:shapes %))))]
(for [grid empty-grids]
[:& grid-layout-viewer {:shape grid :objects objects}])))
;; Component for rendering a thumbnail of a single componenent. Mainly ;; Component for rendering a thumbnail of a single componenent. Mainly
;; used to render thumbnails on assets panel. ;; used to render thumbnails on assets panel.
(mf/defc component-svg (mf/defc component-svg
{::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]} {::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
[{:keys [objects root-shape zoom] :or {zoom 1} :as props}] [{:keys [objects root-shape show-grids? zoom] :or {zoom 1} :as props}]
(when root-shape (when root-shape
(let [root-shape-id (:id root-shape) (let [root-shape-id (:id root-shape)
include-metadata (mf/use-ctx export/include-metadata-ctx) include-metadata (mf/use-ctx export/include-metadata-ctx)
@ -350,9 +363,59 @@
:xmlns:penpot (when include-metadata "https://penpot.app/xmlns") :xmlns:penpot (when include-metadata "https://penpot.app/xmlns")
:fill "none"} :fill "none"}
[:> shape-container {:shape root-shape'} [:*
[:& (mf/provider muc/is-component?) {:value true} [:> shape-container {:shape root-shape'}
[:& root-shape-wrapper {:shape root-shape' :view-box vbox}]]]]))) [:& (mf/provider muc/is-component?) {:value true}
[:& root-shape-wrapper {:shape root-shape' :view-box vbox}]]]
(when show-grids?
[:& empty-grids {:root-shape-id root-shape-id :objects objects}])]])))
(mf/defc component-svg-thumbnail
{::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
[{:keys [thumbnail-uri on-error show-grids?
objects root-shape zoom] :or {zoom 1} :as props}]
(when root-shape
(let [root-shape-id (:id root-shape)
vector
(mf/use-memo
(mf/deps (:x root-shape) (:y root-shape))
(fn []
(-> (gpt/point (:x root-shape) (:y root-shape))
(gpt/negate))))
objects
(mf/use-memo
(mf/deps vector objects root-shape-id)
(fn []
(let [children-ids (cons root-shape-id (cfh/get-children-ids objects root-shape-id))
update-fn #(update %1 %2 gsh/transform-shape (ctm/move-modifiers vector))]
(reduce update-fn objects children-ids))))
root-shape' (get objects root-shape-id)
width (:width root-shape' 0)
height (:height root-shape' 0)
width-zoom (* (:width root-shape') zoom)
height-zoom (* (:height root-shape') zoom)
vbox (format-viewbox {:width width :height height})]
[:svg {:view-box vbox
:width (ust/format-precision width-zoom viewbox-decimal-precision)
:height (ust/format-precision height-zoom viewbox-decimal-precision)
:version "1.1"
:xmlns "http://www.w3.org/2000/svg"
:xmlnsXlink "http://www.w3.org/1999/xlink"
:fill "none"}
[:foreignObject {:x 0 :y 0 :width width :height height }
[:img {:src thumbnail-uri
:on-error on-error
:loading "lazy"
:decoding "async"}]]
(when show-grids?
[:& empty-grids {:root-shape-id root-shape-id :objects objects}])])))
(mf/defc object-svg (mf/defc object-svg
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}

View file

@ -10,6 +10,7 @@
["highlight.js" :as hljs] ["highlight.js" :as hljs]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.main.ui.context :as ctx] [app.main.ui.context :as ctx]
[app.util.dom :as dom]
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -19,8 +20,10 @@
(let [new-css-system (mf/use-ctx ctx/new-css-system) (let [new-css-system (mf/use-ctx ctx/new-css-system)
block-ref (mf/use-ref) block-ref (mf/use-ref)
code (str/trim code)] code (str/trim code)]
(mf/with-effect [code type] (mf/with-effect
[code type]
(when-let [node (mf/ref-val block-ref)] (when-let [node (mf/ref-val block-ref)]
(dom/set-data! node "highlighted" nil)
(hljs/highlightElement node))) (hljs/highlightElement node)))
(if new-css-system (if new-css-system

View file

@ -21,6 +21,15 @@
(let [percent-val (mth/precision (* value 100) precision)] (let [percent-val (mth/precision (* value 100) precision)]
(dm/str percent-val "%")))))) (dm/str percent-val "%"))))))
(defn format-frs
([value]
(format-frs value nil))
([value {:keys [precision] :or {precision 2}}]
(let [value (if (string? value) (d/parse-double value) value)]
(when (d/num? value)
(let [value (mth/precision value precision)]
(dm/str value "fr"))))))
(defn format-number (defn format-number
([value] ([value]
(format-number value nil)) (format-number value nil))

View file

@ -171,7 +171,7 @@
(cleanup) (cleanup)
(rx/push! global-drag-end nil) (rx/push! global-drag-end nil)
(when (fn? on-drop) (when (fn? on-drop)
(on-drop side drop-data)))) (on-drop side drop-data event))))
on-drag-end on-drag-end
(fn [event] (fn [event]

View file

@ -16,6 +16,7 @@
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.types.shape.layout :as ctl]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.modifiers :as dwm]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
@ -693,8 +694,7 @@
objects (wsh/lookup-page-objects @st/state) objects (wsh/lookup-page-objects @st/state)
children (->> (cfh/get-immediate-children objects frame-id) children (->> (cfh/get-immediate-children objects frame-id)
(remove :layout-item-absolute) (remove ctl/position-absolute?))
(remove :hidden))
children-to-display (if (or (= :row-reverse saved-dir) children-to-display (if (or (= :row-reverse saved-dir)
(= :column-reverse saved-dir)) (= :column-reverse saved-dir))

View file

@ -15,7 +15,6 @@
[app.main.ui.context :as muc] [app.main.ui.context :as muc]
[app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.attrs :as attrs]
[app.main.ui.shapes.custom-stroke :refer [shape-fills shape-strokes]] [app.main.ui.shapes.custom-stroke :refer [shape-fills shape-strokes]]
[app.main.ui.shapes.grid-layout-viewer :refer [grid-layout-viewer]]
[app.util.debug :as dbg] [app.util.debug :as dbg]
[app.util.object :as obj] [app.util.object :as obj]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -165,7 +164,6 @@
[props] [props]
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")
childs (unchecked-get props "childs") childs (unchecked-get props "childs")
is-component? (mf/use-ctx muc/is-component?)
childs (cond-> childs childs (cond-> childs
(ctl/any-layout? shape) (ctl/any-layout? shape)
(cfh/sort-layout-children-z-index))] (cfh/sort-layout-children-z-index))]
@ -175,9 +173,5 @@
(for [item childs] (for [item childs]
(let [id (dm/get-prop item :id)] (let [id (dm/get-prop item :id)]
(when (some? id) (when (some? id)
[:& shape-wrapper {:key (dm/str id) :shape item}])))] [:& shape-wrapper {:key (dm/str id) :shape item}])))]])))
(when (and ^boolean is-component?
^boolean (empty? childs))
[:& grid-layout-viewer {:shape shape :childs childs}])])))

View file

@ -15,7 +15,6 @@
[app.common.geom.shapes.grid-layout :as gsg] [app.common.geom.shapes.grid-layout :as gsg]
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc grid-cell-area-label (mf/defc grid-cell-area-label
@ -85,9 +84,8 @@
{::mf/wrap-props false} {::mf/wrap-props false}
[props] [props]
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")
objects (mf/deref refs/workspace-page-objects) objects (unchecked-get props "objects")
bounds (d/lazy-map (keys objects) #(gsh/shape->points (get objects %))) bounds (d/lazy-map (keys objects) #(gsh/shape->points (get objects %)))
children children
(->> (cfh/get-immediate-children objects (:id shape)) (->> (cfh/get-immediate-children objects (:id shape))
(remove :hidden) (remove :hidden)

View file

@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC ;; Copyright (c) KALEIDOS INC
(ns app.main.ui.viewer.inspect.left-sidebar (ns app.main.ui.viewer.inspect.left-sidebar
(:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
@ -15,7 +16,9 @@
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.shape-icon :as si] [app.main.ui.components.shape-icon :as si]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.layer-item :refer [layer-item-inner]]
[app.main.ui.workspace.sidebar.layer-name :refer [layer-name]] [app.main.ui.workspace.sidebar.layer-name :refer [layer-name]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.keyboard :as kbd] [app.util.keyboard :as kbd]
@ -28,43 +31,55 @@
(l/derived st/state))) (l/derived st/state)))
(mf/defc layer-item (mf/defc layer-item
[{:keys [item selected objects disable-collapse?] :as props}] [{:keys [item selected objects disable-collapse? depth component-child? hide-toggle?] :as props}]
(let [id (:id item) (let [new-css-system (mf/use-ctx ctx/new-css-system)
name (:name item) id (:id item)
hidden? (:hidden item) name (:name item)
touched? (-> item :touched seq boolean) hidden? (:hidden item)
touched? (-> item :touched seq boolean)
selected? (contains? selected id) selected? (contains? selected id)
item-ref (mf/use-ref nil) item-ref (mf/use-ref nil)
depth (+ depth 1)
file (mf/deref refs/viewer-file) file (mf/deref refs/viewer-file)
components-v2 (dm/get-in file [:data :options :components-v2]) components-v2 (dm/get-in file [:data :options :components-v2])
main-instance? (if components-v2
(ctk/main-instance? item) main-instance?
true) (if components-v2
collapsed-iref (mf/use-memo (ctk/main-instance? item)
(mf/deps id) true)
(make-collapsed-iref id))
component-tree? (or component-child? (:component-root item))
collapsed-iref
(mf/use-memo
(mf/deps id)
(make-collapsed-iref id))
expanded? (not (mf/deref collapsed-iref)) expanded? (not (mf/deref collapsed-iref))
absolute? (ctl/layout-absolute? item) absolute? (ctl/item-absolute? item)
toggle-collapse toggle-collapse
(fn [event] (mf/use-callback
(dom/stop-propagation event) (mf/deps id)
(st/emit! (dv/toggle-collapse id))) (fn [event]
(dom/stop-propagation event)
(st/emit! (dv/toggle-collapse id))))
select-shape select-shape
(fn [event] (mf/use-callback
(dom/prevent-default event) (mf/deps id)
(let [id (:id item)] (fn [event]
(cond (dom/prevent-default event)
(kbd/mod? event) (cond
(st/emit! (dv/toggle-selection id)) (kbd/mod? event)
(st/emit! (dv/toggle-selection id))
(kbd/shift? event) (kbd/shift? event)
(st/emit! (dv/shift-select-to id)) (st/emit! (dv/shift-select-to id))
:else :else
(st/emit! (dv/select-shape id)))))] (st/emit! (dv/select-shape id)))))]
(mf/use-effect (mf/use-effect
(mf/deps selected) (mf/deps selected)
@ -72,55 +87,102 @@
(when (and (= (count selected) 1) selected?) (when (and (= (count selected) 1) selected?)
(dom/scroll-into-view-if-needed! (mf/ref-val item-ref) true)))) (dom/scroll-into-view-if-needed! (mf/ref-val item-ref) true))))
[:li {:ref item-ref (if new-css-system
:class (dom/classnames [:& layer-item-inner
:component (not (nil? (:component-id item))) {:ref item-ref
:masked (:masked-group item) :item item
:selected selected?)} :depth depth
:read-only? true
:highlighted? false
:selected? selected?
:component-tree? component-tree?
:hidden? hidden?
:filtered? false
:expanded? expanded?
:hide-toggle? hide-toggle?
:on-select-shape select-shape
:on-toggle-collapse toggle-collapse}
[:div.element-list-body {:class (dom/classnames :selected selected? (when (and (:shapes item) expanded?)
:icon-layer (= (:type item) :icon)) [:div {:class (stl/css-case
:on-click select-shape} :element-children true
[:div.icon :parent-selected selected?)}
(when absolute? (for [[index id] (reverse (d/enumerate (:shapes item)))]
[:div.absolute i/position-absolute]) (when-let [item (get objects id)]
[:& si/element-icon {:shape item :main-instance? main-instance?}]] [:& layer-item
[:& layer-name {:shape-id id {:item item
:shape-name name :selected selected
:shape-touched? touched? :index index
:hidden? hidden? :objects objects
:selected? selected? :key (dm/str id)
:type-frame (cfh/frame-shape? item) :depth depth
:disabled-double-click true}] :component-child? component-tree?}]))])]
(when (and (not disable-collapse?) (:shapes item)) ;; OLD
[:span.toggle-content [:li {:ref item-ref
{:on-click toggle-collapse :class (dom/classnames
:class (when expanded? "inverse")} :component (not (nil? (:component-id item)))
i/arrow-slide])] :masked (:masked-group item)
:selected selected?)}
(when (and (:shapes item) expanded?) [:div.element-list-body {:class (dom/classnames :selected selected?
[:ul.element-children :icon-layer (= (:type item) :icon))
(for [[index id] (reverse (d/enumerate (:shapes item)))] :on-click select-shape}
(when-let [item (get objects id)] [:div.icon
[:& layer-item (when absolute?
{:item item [:div.absolute i/position-absolute])
:selected selected [:& si/element-icon {:shape item :main-instance? main-instance?}]]
:index index [:& layer-name {:shape-id id
:objects objects :shape-name name
:key (:id item)}]))])])) :shape-touched? touched?
:hidden? hidden?
:selected? selected?
:type-frame (cfh/frame-shape? item)
:disabled-double-click true}]
(when (and (not disable-collapse?) (:shapes item))
[:span.toggle-content
{:on-click toggle-collapse
:class (when expanded? "inverse")}
i/arrow-slide])]
(when (and (:shapes item) expanded?)
[:ul.element-children
(for [[index id] (reverse (d/enumerate (:shapes item)))]
(when-let [item (get objects id)]
[:& layer-item
{:item item
:selected selected
:index index
:objects objects
:key (:id item)}]))])])))
(mf/defc left-sidebar (mf/defc left-sidebar
[{:keys [frame page local]}] [{:keys [frame page local]}]
(let [selected (:selected local) (let [new-css-system (mf/use-ctx ctx/new-css-system)
selected (:selected local)
objects (:objects page)] objects (:objects page)]
[:aside.settings-bar.settings-bar-left (if new-css-system
[:div.settings-bar-inside [:aside {:class (stl/css :settings-bar-left)}
[:ul.element-list [:div {:class (stl/css :settings-bar-inside)}
[:& layer-item [:div {:class (stl/css :element-list)}
{:item frame [:& layer-item
:selected selected {:item frame
:index 0 :selected selected
:objects objects :index 0
:disable-collapse? true}]]]])) :objects objects
:sortable? false
:filtered? false
:depth -2
:hide-toggle? true}]]]]
[:aside.settings-bar.settings-bar-left
[:div.settings-bar-inside
[:ul.element-list
[:& layer-item
{:item frame
:selected selected
:index 0
:objects objects
:disable-collapse? true}]]]])))

View file

@ -0,0 +1,22 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) KALEIDOS INC
@use "common/refactor/common-refactor.scss" as *;
.settings-bar-left {
background-color: $db-primary;
height: 100%;
width: $s-256;
}
.settings-bar-inside {
display: grid;
grid-template-columns: 100%;
grid-template-rows: 100%;
height: calc(100% - $s-2);
overflow-y: auto;
padding-top: $s-8;
}

View file

@ -19,7 +19,7 @@
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.undo :as dwu] [app.main.data.workspace.undo :as dwu]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.render :refer [component-svg]] [app.main.render :refer [component-svg component-svg-thumbnail]]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.context-menu :refer [context-menu]] [app.main.ui.components.context-menu :refer [context-menu]]
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]] [app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
@ -283,18 +283,26 @@
{::mf/wrap-props false} {::mf/wrap-props false}
[{:keys [file-id root-shape component container]}] [{:keys [file-id root-shape component container]}]
(let [retry (mf/use-state 0) (let [retry (mf/use-state 0)
thumbnail-uri (get-component-thumbnail-uri file-id component)] thumbnail-uri (get-component-thumbnail-uri file-id component)
(if (some? thumbnail-uri) handle-error
[:img {:src thumbnail-uri (mf/use-fn
:on-error (fn [] (mf/deps @retry)
(when (@retry < 3) (fn []
(inc retry))) (when (@retry < 3)
:loading "lazy" (inc retry))))]
:decoding "async"
:class (dom/classnames (css :thumbnail) true)}]
[:& component-svg {:root-shape root-shape
:objects (:objects container)}])))
(if (some? thumbnail-uri)
[:& component-svg-thumbnail
{:thumbnail-uri thumbnail-uri
:on-error handle-error
:root-shape root-shape
:objects (:objects container)
:show-grids? true}]
[:& component-svg
{:root-shape root-shape
:objects (:objects container)
:show-grids? true}])))
(defn generate-components-menu-entries (defn generate-components-menu-entries
[shapes components-v2] [shapes components-v2]

View file

@ -32,6 +32,129 @@
[okulary.core :as l] [okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc layer-item-inner
{::mf/wrap-props false
::mf/forward-ref true}
[{:keys [item depth parent-size name-ref children
;; Flags
read-only? highlighted? selected? component-tree?
filtered? expanded? dnd-over? dnd-over-top? dnd-over-bot? hide-toggle?
;; Callbacks
on-select-shape on-context-menu on-pointer-enter on-pointer-leave on-zoom-to-selected
on-toggle-collapse on-enable-drag on-disable-drag on-toggle-visibility on-toggle-blocking]}
dref]
(let [id (:id item)
name (:name item)
blocked? (:blocked item)
hidden? (:hidden item)
has-shapes? (-> item :shapes seq boolean)
touched? (-> item :touched seq boolean)
parent-board? (and (cfh/frame-shape? item)
(= uuid/zero (:parent-id item)))
absolute? (ctl/item-absolute? item)
components-v2 (mf/use-ctx ctx/components-v2)
main-instance? (or (not components-v2) (:main-instance item))]
[:*
[:div {:id id
:ref dref
:on-click on-select-shape
:on-context-menu on-context-menu
:class (stl/css-case
:layer-row true
:highlight highlighted?
:component (some? (:component-id item))
:masked (:masked-group item)
:selected selected?
:type-frame (cfh/frame-shape? item)
:type-bool (cfh/bool-shape? item)
:type-comp component-tree?
:hidden hidden?
:dnd-over dnd-over?
:dnd-over-top dnd-over-top?
:dnd-over-bot dnd-over-bot?
:root-board parent-board?)}
[:span {:class (stl/css-case
:tab-indentation true
:filtered filtered?)
:style {"--depth" depth}}]
[:div {:class (stl/css-case
:element-list-body true
:filtered filtered?
:selected selected?
:icon-layer (= (:type item) :icon))
:style {"--depth" depth}
:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave
:on-double-click dom/stop-propagation}
(if (< 0 (count (:shapes item)))
[:div {:class (stl/css :button-content)}
(when (and (not hide-toggle?) (not filtered?))
[:button {:class (stl/css-case
:toggle-content true
:inverse expanded?)
:on-click on-toggle-collapse}
i/arrow-refactor])
[:div {:class (stl/css :icon-shape)
:on-double-click on-zoom-to-selected}
(when absolute?
[:div {:class (stl/css :absolute)}])
[:& sic/element-icon-refactor
{:shape item
:main-instance? main-instance?}]]]
[:div {:class (stl/css :button-content)}
(when (not ^boolean filtered?)
[:span {:class (stl/css :toggle-content)}])
[:div {:class (stl/css :icon-shape)
:on-double-click on-zoom-to-selected}
(when ^boolean absolute?
[:div {:class (stl/css :absolute)}])
[:& sic/element-icon-refactor
{:shape item
:main-instance? main-instance?}]]])
[:& layer-name {:ref name-ref
:shape-id id
:shape-name name
:shape-touched? touched?
:disabled-double-click read-only?
:on-start-edit on-disable-drag
:on-stop-edit on-enable-drag
:depth depth
:parent-size parent-size
:selected? selected?
:type-comp component-tree?
:type-frame (cfh/frame-shape? item)
:hidden? hidden?}]
(when (not read-only?)
[:div {:class (stl/css-case
:element-actions true
:is-parent has-shapes?
:selected hidden?
:selected blocked?)}
[:button {:class (stl/css-case
:toggle-element true
:selected hidden?)
:title (if hidden?
(tr "workspace.shape.menu.show")
(tr "workspace.shape.menu.hide"))
:on-click on-toggle-visibility}
(if ^boolean hidden? i/hide-refactor i/shown-refactor)]
[:button {:class (stl/css-case
:block-element true
:selected blocked?)
:title (if (:blocked item)
(tr "workspace.shape.menu.unlock")
(tr "workspace.shape.menu.lock"))
:on-click on-toggle-blocking}
(if ^boolean blocked? i/lock-refactor i/unlock-refactor)]])]]
children]))
(mf/defc layer-item (mf/defc layer-item
{::mf/wrap-props false} {::mf/wrap-props false}
[{:keys [index item selected objects sortable? filtered? depth parent-size component-child? highlighted]}] [{:keys [index item selected objects sortable? filtered? depth parent-size component-child? highlighted]}]
@ -53,9 +176,10 @@
selected? (contains? selected id) selected? (contains? selected id)
highlighted? (contains? highlighted id) highlighted? (contains? highlighted id)
container? (or (cfh/frame-shape? item) container? (or (cfh/frame-shape? item)
(cfh/group-shape? item)) (cfh/group-shape? item))
absolute? (ctl/layout-absolute? item) absolute? (ctl/item-absolute? item)
components-v2 (mf/use-ctx ctx/components-v2) components-v2 (mf/use-ctx ctx/components-v2)
read-only? (mf/use-ctx ctx/workspace-read-only?) read-only? (mf/use-ctx ctx/workspace-read-only?)
@ -210,113 +334,44 @@
(let [scroll-to @scroll-to-middle?] (let [scroll-to @scroll-to-middle?]
(ts/schedule (ts/schedule
100 100
#(let [scroll-distance-ratio (dom/get-scroll-distance-ratio node scroll-node) #(when (and node scroll-node)
scroll-behavior (if (> scroll-distance-ratio 1) "instant" "smooth")] (let [scroll-distance-ratio (dom/get-scroll-distance-ratio node scroll-node)
(if scroll-to scroll-behavior (if (> scroll-distance-ratio 1) "instant" "smooth")]
(dom/scroll-into-view! first-child-node #js {:block "center" :behavior scroll-behavior :inline "start"}) (if scroll-to
(do (dom/scroll-into-view! first-child-node #js {:block "center" :behavior scroll-behavior :inline "start"})
(dom/scroll-into-view-if-needed! first-child-node #js {:block "center" :behavior scroll-behavior :inline "start"}) (do
(reset! scroll-to-middle? true)))))))] (dom/scroll-into-view-if-needed! first-child-node #js {:block "center" :behavior scroll-behavior :inline "start"})
(reset! scroll-to-middle? true))))))))]
#(when (some? subid) #(when (some? subid)
(rx/dispose! subid)))) (rx/dispose! subid))))
(if new-css-system (if new-css-system
[:* [:& layer-item-inner
[:div {:on-context-menu on-context-menu {:ref dref
:ref dref :item item
:on-click select-shape :depth depth
:id id :parent-size parent-size
:class (stl/css-case :name-ref ref
:layer-row true :read-only? read-only?
:component (some? (:component-id item)) :highlighted? highlighted?
:masked (:masked-group item) :selected? selected?
:selected selected? :component-tree? component-tree?
:type-frame (cfh/frame-shape? item) :filtered? filtered?
:type-bool (cfh/bool-shape? item) :expanded? expanded?
:type-comp component-tree? :dnd-over? (= (:over dprops) :center)
:hidden hidden? :dnd-over-top? (= (:over dprops) :top)
:dnd-over (= (:over dprops) :center) :dnd-over-bot? (= (:over dprops) :bot)
:dnd-over-top (= (:over dprops) :top) :on-select-shape select-shape
:dnd-over-bot (= (:over dprops) :bot) :on-context-menu on-context-menu
:root-board parent-board?)} :on-pointer-enter on-pointer-enter
[:span {:class (stl/css-case :on-pointer-leave on-pointer-leave
:tab-indentation true :on-zoom-to-selected zoom-to-selected
:filtered filtered?) :on-toggle-collapse toggle-collapse
:style {"--depth" depth}}] :on-enable-drag enable-drag
[:div {:class (stl/css-case :on-disable-drag disable-drag
:element-list-body true :on-toggle-visibility toggle-visibility
:filtered filtered? :on-toggle-blocking toggle-blocking}
:selected selected?
:icon-layer (= (:type item) :icon))
:style {"--depth" depth}
:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave
:on-double-click dom/stop-propagation}
(if (< 0 (count (:shapes item)))
[:div {:class (stl/css :button-content)}
(when (not filtered?)
[:button {:class (stl/css-case
:toggle-content true
:inverse expanded?)
:on-click toggle-collapse}
i/arrow-refactor])
[:div {:class (stl/css :icon-shape)
:on-double-click zoom-to-selected}
(when absolute?
[:div {:class (stl/css :absolute)}])
[:& sic/element-icon-refactor
{:shape item
:main-instance? main-instance?}]]]
[:div {:class (stl/css :button-content)}
(when (not ^boolean filtered?)
[:span {:class (stl/css :toggle-content)}])
[:div {:class (stl/css :icon-shape)
:on-double-click zoom-to-selected}
(when ^boolean absolute?
[:div {:class (stl/css :absolute)}])
[:& sic/element-icon-refactor
{:shape item
:main-instance? main-instance?}]]])
[:& layer-name {:ref ref
:shape-id id
:shape-name name
:shape-touched? touched?
:disabled-double-click read-only?
:on-start-edit disable-drag
:on-stop-edit enable-drag
:depth depth
:parent-size parent-size
:selected? selected?
:type-comp component-tree?
:type-frame (cfh/frame-shape? item)
:hidden? hidden?}]
[:div {:class (stl/css-case
:element-actions true
:is-parent has-shapes?
:selected hidden?
:selected blocked?)}
[:button {:class (stl/css-case
:toggle-element true
:selected hidden?)
:title (if hidden?
(tr "workspace.shape.menu.show")
(tr "workspace.shape.menu.hide"))
:on-click toggle-visibility}
(if ^boolean hidden? i/hide-refactor i/shown-refactor)]
[:button {:class (stl/css-case
:block-element true
:selected blocked?)
:title (if (:blocked item)
(tr "workspace.shape.menu.unlock")
(tr "workspace.shape.menu.lock"))
:on-click toggle-blocking}
(if ^boolean blocked? i/lock-refactor i/unlock-refactor)]]]]
(when (and (:shapes item) expanded?) (when (and (:shapes item) expanded?)
[:div {:class (stl/css-case [:div {:class (stl/css-case
@ -324,11 +379,11 @@
:parent-selected selected? :parent-selected selected?
:sticky-children parent-board?) :sticky-children parent-board?)
:data-id (when ^boolean parent-board? id)} :data-id (when ^boolean parent-board? id)}
(for [[index id] (reverse (d/enumerate (:shapes item)))] (for [[index id] (reverse (d/enumerate (:shapes item)))]
(when-let [item (get objects id)] (when-let [item (get objects id)]
[:& layer-item [:& layer-item
{:item item {:item item
:highlighted highlighted
:selected selected :selected selected
:index index :index index
:objects objects :objects objects

View file

@ -12,478 +12,242 @@
align-items: center; align-items: center;
width: 100%; width: 100%;
background-color: var(--layer-row-background-color); background-color: var(--layer-row-background-color);
border: 2px solid transparent;
.element-list-body { &.highlight,
display: flex;
align-items: center;
height: $s-32;
width: calc(100% - (var(--depth) * var(--layer-indentation-size)));
padding-right: $s-12;
cursor: pointer;
&.filtered {
width: calc(100% - $s-12);
}
.button-content {
display: flex;
height: 100%;
.toggle-content {
@include buttonStyle;
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
height: 100%;
width: $s-24;
padding: 0 4px 0 8px;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
&.inverse {
svg {
transform: rotate(90deg);
}
.icon-shape {
transform: rotate(-90deg);
}
}
}
.icon-shape {
@include flexCenter;
@include buttonStyle;
position: relative;
justify-self: flex-end;
width: $s-16;
height: 100%;
width: $s-24;
padding: 0 $s-8 0 $s-4;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
.absolute {
position: absolute;
background-color: var(--layer-row-foreground-color);
opacity: $op-4;
width: $s-12;
height: $s-12;
border-radius: $br-2;
}
}
}
.element-actions {
display: none;
height: 100%;
.toggle-element,
.block-element {
@include buttonStyle;
@include flexCenter;
height: 100%;
width: $s-24;
margin: 0;
display: none;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
&.selected {
display: flex;
.toggle-element,
.block-element {
display: flex;
opacity: $op-0;
&.selected {
opacity: $op-10;
}
}
}
}
}
.element-children {
width: 100%;
ul {
margin-bottom: 0;
}
&.parent-selected {
.layer-row {
background-color: var(--layer-child-row-background-color);
}
}
}
&.hidden {
.element-list-body {
.button-content {
.toggle-content {
svg {
opacity: $op-7;
}
}
.icon-shape {
svg {
opacity: $op-7;
}
.absolute {
opacity: $op-1;
}
}
}
.element-actions {
.toggle-element,
.block-element {
svg {
opacity: $op-7;
}
}
}
}
}
&:hover { &:hover {
--context-hover-color: var(--layer-row-foreground-color-hover); --context-hover-color: var(--layer-row-foreground-color-hover);
--context-hover-opacity: $op-10; --context-hover-opacity: $op-10;
background-color: var(--layer-row-background-color-hover); background-color: var(--layer-row-background-color-hover);
color: var(--layer-row-foreground-color-hover);
box-shadow: $s-16 0px 0px 0px var(--layer-row-background-color-hover); box-shadow: $s-16 0px 0px 0px var(--layer-row-background-color-hover);
&.hidden { &.hidden {
opacity: $op-10; opacity: $op-10;
} }
.element-list-body {
.button-content {
.toggle-content {
background-color: var(--layer-row-background-color-hover);
svg {
opacity: $op-10;
stroke: var(--layer-row-foreground-color-hover);
}
}
.icon-shape {
opacity: $op-10;
svg {
stroke: var(--layer-row-foreground-color-hover);
}
& .absolute {
opacity: $op-4;
background-color: var(--layer-row-foreground-color-hover);
}
}
}
.element-actions {
display: flex;
.toggle-element,
.block-element {
display: flex;
svg {
opacity: $op-10;
stroke: var(--layer-row-foreground-color-hover);
}
}
&.selected {
.toggle-element,
.block-element {
opacity: $op-10;
}
}
}
}
.element-children {
.layer-row {
background-color: transparent;
color: var(--layer-row-foreground-color-hover);
&:hover {
background-color: var(--layer-row-background-color-hover);
}
}
}
} }
&.selected { &.selected {
background-color: var(--layer-row-background-color-selected); background-color: var(--layer-row-background-color-selected);
box-shadow: $s-16 0px 0px 0px var(--layer-row-background-color-selected); box-shadow: $s-16 0px 0px 0px var(--layer-row-background-color-selected);
.element-list-body {
.button-content {
.toggle-content {
background-color: var(--layer-row-background-color-selected);
svg {
stroke: var(--layer-row-foreground-color-selected);
}
}
.icon-shape {
svg {
stroke: var(--layer-row-foreground-color-selected);
}
.absolute {
background-color: var(--layer-row-foreground-color-selected);
}
}
}
.element-actions {
.toggle-element,
.block-element {
display: flex;
svg {
stroke: var(--layer-row-foreground-color-selected);
}
}
&.selected {
.toggle-element,
.block-element {
display: flex;
opacity: $op-10;
&.selected {
opacity: $op-10;
}
}
}
}
}
.element-children {
background-color: transparent;
color: var(--layer-row-foreground-color-selected);
&:hover {
background-color: var(--layer-row-background-color-selected);
}
}
&:hover {
background-color: var(--layer-row-background-color-selected);
}
} }
&.type-comp {
.button-content { &.selected.highlight,
.toggle-content { &.selected:hover {
svg { background-color: var(--layer-row-background-color-selected);
stroke: var(--layer-row-component-foreground-color);
}
}
.icon-shape {
svg {
stroke: var(--layer-row-component-foreground-color);
}
.absolute {
background-color: var(--layer-row-component-foreground-color);
}
}
}
.element-actions {
.toggle-element,
.block-element {
svg {
stroke: var(--layer-row-component-foreground-color);
}
}
}
.element-children {
color: var(--layer-row-component-foreground-color);
}
&.hidden {
.element-list-body {
.button-content {
.toggle-content {
opacity: $op-7;
}
.icon-shape {
opacity: $op-7;
.absolute {
opacity: $op-1;
}
}
}
.element-actions {
.toggle-element,
.block-element {
svg {
opacity: $op-7;
}
}
}
}
&:hover {
.element-list-body {
.button-content {
.toggle-content {
opacity: $op-10;
svg {
stroke: var(--layer-row-foreground-color-hover);
}
}
.icon-shape {
opacity: $op-10;
svg {
stroke: var(--layer-row-foreground-color-hover);
}
& .absolute {
opacity: $op-4;
}
}
}
.element-actions {
.toggle-element,
.block-element {
svg {
opacity: $op-10;
stroke: var(--layer-row-foreground-color-hover);
}
}
}
}
}
}
} }
&.type-comp.selected {
.button-content { .parent-selected & {
.toggle-content { background-color: var(--layer-child-row-background-color);
svg {
stroke: var(--layer-row-component-foreground-color);
}
}
.icon-shape {
svg {
stroke: var(--layer-row-component-foreground-color);
}
.absolute {
background-color: var(--layer-row-component-foreground-color);
}
}
}
.element-actions {
.toggle-element,
.block-element {
svg {
stroke: var(--layer-row-component-foreground-color);
}
}
}
.element-children {
color: var(--layer-row-component-foreground-color);
}
&.hidden {
.element-list-body {
.button-content {
.toggle-content {
opacity: $op-7;
}
.icon-shape {
opacity: $op-7;
.absolute {
opacity: $op-1;
}
}
}
.element-actions {
.toggle-element,
.block-element {
svg {
opacity: $op-7;
}
}
}
}
&:hover {
.element-list-body {
.button-content {
.toggle-content {
opacity: $op-10;
svg {
stroke: var(--layer-row-foreground-color-hover);
}
}
.icon-shape {
opacity: $op-10;
& .absolute {
opacity: $op-4;
}
}
}
.element-actions {
.toggle-element,
.block-element {
svg {
opacity: $op-10;
stroke: var(--layer-row-foreground-color-hover);
}
}
}
}
}
}
&:hover {
.element-list-body {
.button-content {
.toggle-content {
svg {
stroke: var(--layer-row-foreground-color-hover);
}
}
.icon-shape {
svg {
stroke: var(--layer-row-foreground-color-hover);
}
}
}
.element-actions {
.toggle-element,
.block-element {
svg {
stroke: var(--layer-row-foreground-color-hover);
}
}
}
}
}
} }
&:global(.sticky) {
position: sticky; .parent-selected &.highlight,
top: 0px; .parent-selected &:hover {
z-index: 3; background-color: var(--layer-row-background-color-hover);
}
&.dnd-over-bot {
border-bottom: $s-2 solid var(--layer-row-foreground-color-hover);
}
&.dnd-over-top {
border-bottom: $s-2 solid var(--layer-row-foreground-color-hover);
}
&.dnd-over {
border: $s-2 solid var(--layer-row-foreground-color-hover);
} }
} }
.parent-selected .layer-row {
background-color: var(--layer-child-row-background-color); .element-children {
&:hover { .layer-row.highlight &,
background-color: var(--layer-row-background-color-hover); .layer-row:hover & {
&.hidden { background-color: var(--layer-row-background-color-selected);
}
.layer-row.type-comp & {
color: var(--layer-row-component-foreground-color);
}
.layer-row.selected & {
background-color: transparent;
color: var(--layer-row-foreground-color-selected);
}
}
.element-list-body {
display: flex;
align-items: center;
height: $s-32;
width: calc(100% - (var(--depth) * var(--layer-indentation-size)));
padding-right: $s-12;
cursor: pointer;
&.filtered {
width: calc(100% - $s-12);
}
}
.element-actions {
display: none;
height: 100%;
&.selected {
display: flex;
}
.layer-row.highlight &,
.layer-row:hover & {
display: flex;
}
}
.button-content {
display: flex;
height: 100%;
}
.icon-shape {
@include flexCenter;
@include buttonStyle;
position: relative;
justify-self: flex-end;
width: $s-16;
height: 100%;
width: $s-24;
padding: 0 $s-8 0 $s-4;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
.layer-row.selected & {
stroke: var(--layer-row-foreground-color-selected);
}
.layer-row.type-comp & {
stroke: var(--layer-row-component-foreground-color);
}
}
.inverse & {
transform: rotate(-90deg);
}
.layer-row.hidden & {
opacity: $op-7;
}
.layer-row.highlight &,
.layer-row:hover & {
opacity: $op-10;
svg {
stroke: var(--layer-row-foreground-color-hover);
}
}
}
.absolute {
position: absolute;
background-color: var(--layer-row-foreground-color);
opacity: $op-4;
width: $s-12;
height: $s-12;
border-radius: $br-2;
.layer-row.hidden & {
opacity: $op-1;
}
.layer-row.type-comp & {
background-color: var(--layer-row-component-foreground-color);
}
.layer-row.highlight &,
.layer-row:hover & {
opacity: $op-4;
background-color: var(--layer-row-foreground-color-hover);
}
.layer-row.selected & {
background-color: var(--layer-row-foreground-color-selected);
}
}
.toggle-content {
@include buttonStyle;
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
height: 100%;
width: $s-24;
padding: 0 4px 0 8px;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
.layer-row.hidden & {
opacity: $op-7;
}
.layer-row.selected & {
stroke: var(--layer-row-foreground-color-selected);
}
.layer-row.type-comp & {
stroke: var(--layer-row-component-foreground-color);
}
.layer-row.highlight &,
.layer-row:hover & {
opacity: $op-10;
stroke: var(--layer-row-foreground-color-hover);
}
}
.layer-row.selected & {
background-color: var(--layer-row-background-color-selected);
}
&.inverse svg {
transform: rotate(90deg);
}
}
.toggle-element,
.block-element {
@include buttonStyle;
@include flexCenter;
height: 100%;
width: $s-24;
margin: 0;
display: none;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
.layer-row.hidden & {
opacity: $op-7;
}
.type-comp & {
stroke: var(--layer-row-component-foreground-color);
}
}
.element-actions.selected & {
display: flex;
opacity: $op-0;
&.selected {
opacity: $op-10; opacity: $op-10;
} }
.element-list-body { }
.button-content {
.toggle-content { .layer-row.highlight &,
background-color: var(--layer-row-background-color-hover); .layer-row:hover & {
svg { display: flex;
stroke: var(--layer-row-foreground-color-hover); svg {
} opacity: $op-10;
} stroke: var(--layer-row-foreground-color-hover);
.icon-shape {
svg {
stroke: var(--layer-row-foreground-color-hover);
}
.absolute {
background-color: var(--layer-row-foreground-color-hover);
}
}
}
.element-actions {
.toggle-element,
.block-element {
display: flex;
svg {
stroke: var(--layer-row-foreground-color-hover);
}
}
&.selected {
.toggle-element,
.block-element {
opacity: $op-10;
}
}
}
} }
.element-children :global(.layer-row) { }
background-color: transparent; .layer-row.selected & {
color: var(--layer-row-foreground-color-hover); display: flex;
&:hover { svg {
background-color: var(--layer-row-background-color-hover); stroke: var(--layer-row-foreground-color-selected);
}
} }
} }
} }
:global(.sticky) {
position: sticky;
top: 0px;
z-index: 3;
}
.tab-indentation { .tab-indentation {
display: block; display: block;
height: $s-16; height: $s-16;

View file

@ -47,7 +47,7 @@
highlighted (hooks/use-equal-memo highlighted) highlighted (hooks/use-equal-memo highlighted)
root (get objects uuid/zero) root (get objects uuid/zero)
new-css-system (mf/use-ctx ctx/new-css-system)] new-css-system (mf/use-ctx ctx/new-css-system)]
[:ul [:div
{:class (stl/css new-css-system :element-list)} {:class (stl/css new-css-system :element-list)}
[:& hooks/sortable-container {} [:& hooks/sortable-container {}
(for [[index id] (reverse (d/enumerate (:shapes root)))] (for [[index id] (reverse (d/enumerate (:shapes root)))]

View file

@ -24,10 +24,12 @@
[app.main.ui.components.select :refer [select]] [app.main.ui.components.select :refer [select]]
[app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.components.title-bar :refer [title-bar]]
[app.main.ui.context :as ctx] [app.main.ui.context :as ctx]
[app.main.ui.formats :as fmt]
[app.main.ui.hooks :as h] [app.main.ui.hooks :as h]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd]
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -951,20 +953,20 @@
(defn manage-values [{:keys [value type]}] (defn manage-values [{:keys [value type]}]
(case type (case type
:auto "auto" :auto "auto"
:percent (dm/str value "%") :percent (fmt/format-percent value)
:flex (dm/str value "fr") :flex (fmt/format-frs value)
:fixed (dm/str value "px") :fixed (fmt/format-pixels value)
value)) value))
(mf/defc grid-track-info (mf/defc grid-track-info
[{:keys [is-col? type index column set-column-value set-column-type remove-element reorder-track hover-track]}] [{:keys [is-col? type index column set-column-value set-column-type remove-element reorder-track hover-track on-select-track]}]
(let [new-css-system (mf/use-ctx ctx/new-css-system) (let [new-css-system (mf/use-ctx ctx/new-css-system)
drop-track drop-track
(mf/use-fn (mf/use-fn
(mf/deps type reorder-track index) (mf/deps type reorder-track index)
(fn [drop-position data] (fn [drop-position data event]
(reorder-track type (:index data) (if (= :top drop-position) (dec index) index)))) (reorder-track type (:index data) (if (= :top drop-position) (dec index) index) (kbd/mod? event))))
pointer-enter pointer-enter
(mf/use-fn (mf/use-fn
@ -978,6 +980,13 @@
(fn [] (fn []
(hover-track type index false))) (hover-track type index false)))
handle-select-track
(mf/use-fn
(mf/deps on-select-track type index)
(fn []
(when on-select-track
(on-select-track type index))))
[dprops dref] [dprops dref]
(h/use-sortable (h/use-sortable
:data-type "penpot/grid-track" :data-type "penpot/grid-track"
@ -998,7 +1007,8 @@
:on-pointer-leave pointer-leave} :on-pointer-leave pointer-leave}
[:div {:class (stl/css :track-info-container)} [:div {:class (stl/css :track-info-container)}
[:div {:class (stl/css :track-info-dir-icon)} [:div {:class (stl/css :track-info-dir-icon)
:on-click handle-select-track}
(if is-col? i/flex-vertical-refactor i/flex-horizontal-refactor)] (if is-col? i/flex-vertical-refactor i/flex-horizontal-refactor)]
[:div {:class (stl/css :track-info-value)} [:div {:class (stl/css :track-info-value)}
@ -1057,7 +1067,8 @@
i/minus]]))) i/minus]])))
(mf/defc grid-columns-row (mf/defc grid-columns-row
[{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type remove-element reorder-track hover-track] :as props}] [{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type
remove-element reorder-track hover-track on-select-track] :as props}]
(let [new-css-system (mf/use-ctx ctx/new-css-system) (let [new-css-system (mf/use-ctx ctx/new-css-system)
column-num (count column-values) column-num (count column-values)
@ -1098,7 +1109,8 @@
:set-column-type set-column-type :set-column-type set-column-type
:remove-element remove-element :remove-element remove-element
:reorder-track reorder-track :reorder-track reorder-track
:hover-track hover-track}])]])] :hover-track hover-track
:on-select-track on-select-track}])]])]
[:div.grid-columns [:div.grid-columns
[:div.grid-columns-header [:div.grid-columns-header
@ -1119,7 +1131,8 @@
:set-column-type set-column-type :set-column-type set-column-type
:remove-element remove-element :remove-element remove-element
:reorder-track reorder-track :reorder-track reorder-track
:hover-track hover-track}])]])]))) :hover-track hover-track
:on-select-track on-select-track}])]])])))
;; LAYOUT COMPONENT ;; LAYOUT COMPONENT
@ -1364,12 +1377,7 @@
handle-open-grid-help handle-open-grid-help
(mf/use-callback (mf/use-callback
(fn [] (fn []
(st/emit! (dom/open-new-window cf/grid-help-uri)))) (st/emit! (dom/open-new-window cf/grid-help-uri))))]
handle-locate-grid
(mf/use-callback
(fn []
(st/emit! (dwge/locate-board (first ids)))))]
(if new-css-system (if new-css-system
[:div {:class (stl/css :element-set)} [:div {:class (stl/css :element-set)}
@ -1383,7 +1391,18 @@
[:div {:class (stl/css :title-actions)} [:div {:class (stl/css :title-actions)}
[:button {:class (stl/css :remove-layout) [:button {:class (stl/css :remove-layout)
:on-click on-remove-layout} :on-click on-remove-layout}
i/remove-refactor]] i/remove-refactor]
(when ^boolean grid-enabled?
[:*
[:button {:class (stl/css :add-layout)
:on-click handle-show-layout-dropdown}
i/menu-refactor]
[:& dropdown {:show show-layout-dropdown? :on-close handle-close-layout-options}
[:div {:class (stl/css :layout-options)}
[:button {:class (stl/css :layout-option) :on-click set-flex} "Flex layout"]
[:button {:class (stl/css :layout-option) :on-click set-grid} "Grid layout"]]]])]
[:div {:class (stl/css :title-actions)} [:div {:class (stl/css :title-actions)}
(if ^boolean grid-enabled? (if ^boolean grid-enabled?
@ -1469,11 +1488,7 @@
:set-justify set-justify-grid}] :set-justify set-justify-grid}]
[:& justify-grid-row {:is-col? false [:& justify-grid-row {:is-col? false
:justify-items grid-justify-content-row :justify-items grid-justify-content-row
:set-justify set-justify-grid}] :set-justify set-justify-grid}]]]
[:button {:on-click handle-locate-grid
:class (stl/css :locate-button)}
i/locate-refactor]]]
nil)))] nil)))]
[:div.element-set [:div.element-set
@ -1686,8 +1701,8 @@
reorder-track reorder-track
(mf/use-fn (mf/use-fn
(mf/deps ids) (mf/deps ids)
(fn [type from-index to-index] (fn [type from-index to-index move-content?]
(st/emit! (dwsl/reorder-layout-track ids type from-index to-index)))) (st/emit! (dwsl/reorder-layout-track ids type from-index to-index move-content?))))
hover-track hover-track
(mf/use-fn (mf/use-fn
@ -1695,6 +1710,12 @@
(fn [type index hover?] (fn [type index hover?]
(st/emit! (dwsl/hover-layout-track ids type index hover?)))) (st/emit! (dwsl/hover-layout-track ids type index hover?))))
handle-select-track
(mf/use-fn
(mf/deps ids)
(fn [type index]
(st/emit! (dwge/select-track-cells (first ids) type index))))
set-column-value set-column-value
(mf/use-fn (mf/use-fn
(mf/deps ids) (mf/deps ids)
@ -1720,7 +1741,7 @@
handle-locate-grid handle-locate-grid
(mf/use-callback (mf/use-callback
(fn [] (fn []
(st/emit! (dwge/locate-board (first ids))))) ] (st/emit! (dwge/locate-board (first ids)))))]
(if new-css-system (if new-css-system
[:div {:class (stl/css :grid-layout-menu)} [:div {:class (stl/css :grid-layout-menu)}
@ -1767,7 +1788,8 @@
:set-column-type set-column-type :set-column-type set-column-type
:remove-element remove-element :remove-element remove-element
:reorder-track reorder-track :reorder-track reorder-track
:hover-track hover-track}] :hover-track hover-track
:on-select-track handle-select-track}]
[:& grid-columns-row {:is-col? false [:& grid-columns-row {:is-col? false
:expanded? @grid-rows-open? :expanded? @grid-rows-open?
@ -1778,7 +1800,8 @@
:set-column-type set-column-type :set-column-type set-column-type
:remove-element remove-element :remove-element remove-element
:reorder-track reorder-track :reorder-track reorder-track
:hover-track hover-track}]] :hover-track hover-track
:on-select-track handle-select-track}]]
[:div {:class (stl/css :row)} [:div {:class (stl/css :row)}
[:& gap-section {:gap-selected? gap-selected? [:& gap-section {:gap-selected? gap-selected?
:on-change set-gap :on-change set-gap

View file

@ -222,15 +222,18 @@
} }
.track-info-dir-icon { .track-info-dir-icon {
cursor: pointer;
border-radius: $br-8 0 0 $br-8; border-radius: $br-8 0 0 $br-8;
background-color: var(--input-background-color); background-color: var(--input-background-color);
padding-left: $s-12; padding: 0 $s-8;
svg { svg {
@extend .button-icon; @extend .button-icon;
stroke: var(--icon-foreground); stroke: var(--icon-foreground);
height: 100%; height: 100%;
} }
&:hover svg {
stroke: var(--icon-foreground-hover);
}
} }
.track-info-value { .track-info-value {

View file

@ -378,7 +378,7 @@
selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
selection-parents (mf/deref selection-parents-ref) selection-parents (mf/deref selection-parents-ref)
is-absolute? (:layout-item-absolute values) is-absolute? (:layout-item-absolute values)
is-col? (every? ctl/col? selection-parents) is-col? (every? ctl/col? selection-parents)
@ -510,7 +510,7 @@
(when open? (when open?
[:div {:class (stl/css :flex-element-menu)} [:div {:class (stl/css :flex-element-menu)}
[:div {:class (stl/css :row)} [:div {:class (stl/css :row)}
(when is-flex-parent? (when (or is-layout-child? is-absolute?)
[:div {:class (stl/css :position-options)} [:div {:class (stl/css :position-options)}
[:& radio-buttons {:selected (if is-absolute? "absolute" "static") [:& radio-buttons {:selected (if is-absolute? "absolute" "static")
:on-change on-change-position :on-change on-change-position

View file

@ -93,7 +93,7 @@
selection-parents (mf/deref selection-parents-ref) selection-parents (mf/deref selection-parents-ref)
flex-child? (->> selection-parents (some ctl/flex-layout?)) flex-child? (->> selection-parents (some ctl/flex-layout?))
absolute? (ctl/layout-absolute? shape) absolute? (ctl/item-absolute? shape)
flex-container? (ctl/flex-layout? shape) flex-container? (ctl/flex-layout? shape)
flex-auto-width? (ctl/auto-width? shape) flex-auto-width? (ctl/auto-width? shape)
flex-fill-width? (ctl/fill-width? shape) flex-fill-width? (ctl/fill-width? shape)

View file

@ -41,7 +41,7 @@
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref) is-grid-parent? (mf/deref is-grid-parent-ref)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids) ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))

View file

@ -43,7 +43,7 @@
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref) is-grid-parent? (mf/deref is-grid-parent-ref)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids) ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))

View file

@ -49,7 +49,7 @@
is-grid-parent? (mf/deref is-grid-parent-ref) is-grid-parent? (mf/deref is-grid-parent-ref)
is-layout-container? (ctl/any-layout? shape) is-layout-container? (ctl/any-layout? shape)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids) ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))

View file

@ -50,7 +50,7 @@
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref) is-grid-parent? (mf/deref is-grid-parent-ref)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids) ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))

View file

@ -43,7 +43,7 @@
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref) is-grid-parent? (mf/deref is-grid-parent-ref)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids) ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))

View file

@ -43,7 +43,7 @@
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref) is-grid-parent? (mf/deref is-grid-parent-ref)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids) ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))

View file

@ -46,7 +46,7 @@
is-grid-parent* (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent* (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent*) is-grid-parent? (mf/deref is-grid-parent*)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
parents-by-ids* (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids* (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
parents (mf/deref parents-by-ids*)] parents (mf/deref parents-by-ids*)]

View file

@ -116,7 +116,7 @@
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref) is-grid-parent? (mf/deref is-grid-parent-ref)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids) ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))

View file

@ -40,7 +40,7 @@
is-grid-parent? (mf/deref is-grid-parent-ref) is-grid-parent? (mf/deref is-grid-parent-ref)
layout-container-values (select-keys shape layout-container-flex-attrs) layout-container-values (select-keys shape layout-container-flex-attrs)
is-layout-child-absolute? (ctl/layout-absolute? shape) is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids) ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))

View file

@ -664,6 +664,7 @@
(let [target (-> event dom/get-target) (let [target (-> event dom/get-target)
value (-> target dom/get-input-value str/upper) value (-> target dom/get-input-value str/upper)
value-int (d/parse-integer value) value-int (d/parse-integer value)
value-int (when value-int (max 0 value-int))
[track-type value] [track-type value]
(cond (cond

View file

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

View file

@ -133,7 +133,7 @@ body {
[:height height]] [:height height]]
(or (not (ctl/any-layout-immediate-child? objects shape)) (or (not (ctl/any-layout-immediate-child? objects shape))
(not (ctl/layout-absolute? shape))) (not (ctl/position-absolute? shape)))
(conj [:position "relative"]))))) (conj [:position "relative"])))))
(defn shape->wrapper-child-css-properties (defn shape->wrapper-child-css-properties

View file

@ -31,7 +31,7 @@
[_ shape objects] [_ shape objects]
(cond (cond
(or (and (ctl/any-layout-immediate-child? objects shape) (or (and (ctl/any-layout-immediate-child? objects shape)
(not (ctl/layout-absolute? shape)) (not (ctl/position-absolute? shape))
(or (cfh/group-like-shape? shape) (or (cfh/group-like-shape? shape)
(cfh/frame-shape? shape) (cfh/frame-shape? shape)
(cgc/svg-markup? shape))) (cgc/svg-markup? shape)))
@ -39,7 +39,7 @@
:relative :relative
(and (ctl/any-layout-immediate-child? objects shape) (and (ctl/any-layout-immediate-child? objects shape)
(not (ctl/layout-absolute? shape))) (not (ctl/position-absolute? shape)))
nil nil
:else :else
@ -50,7 +50,7 @@
(when (and (not (cfh/root-frame? shape)) (when (and (not (cfh/root-frame? shape))
(or (not (ctl/any-layout-immediate-child? objects shape)) (or (not (ctl/any-layout-immediate-child? objects shape))
(ctl/layout-absolute? shape))) (ctl/position-absolute? shape)))
(let [parent (get objects (:parent-id shape)) (let [parent (get objects (:parent-id shape))
@ -291,7 +291,7 @@
(defn get-grid-coord (defn get-grid-coord
[shape objects prop span-prop] [shape objects prop span-prop]
(when (and (ctl/grid-layout-immediate-child? objects shape) (when (and (ctl/grid-layout-immediate-child? objects shape)
(not (ctl/layout-absolute? shape))) (not (ctl/position-absolute? shape)))
(let [parent (get objects (:parent-id shape)) (let [parent (get objects (:parent-id shape))
cell (ctl/get-cell-by-shape-id parent (:id shape))] cell (ctl/get-cell-by-shape-id parent (:id shape))]
(when (and (when (and
@ -314,7 +314,7 @@
(defmethod get-value :grid-area (defmethod get-value :grid-area
[_ shape objects] [_ shape objects]
(when (and (ctl/grid-layout-immediate-child? objects shape) (when (and (ctl/grid-layout-immediate-child? objects shape)
(not (ctl/layout-absolute? shape))) (not (ctl/position-absolute? shape)))
(let [parent (get objects (:parent-id shape)) (let [parent (get objects (:parent-id shape))
cell (ctl/get-cell-by-shape-id parent (:id shape))] cell (ctl/get-cell-by-shape-id parent (:id shape))]
(when (and (= (:position cell) :area) (d/not-empty? (:area-name cell))) (when (and (= (:position cell) :area) (d/not-empty? (:area-name cell)))