0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-23 23:18:48 -05:00

Add grid layout options to context

This commit is contained in:
alonso.torres 2024-05-03 13:44:31 +02:00
parent 9243ba937d
commit fde0bcfd3e
4 changed files with 245 additions and 40 deletions

View file

@ -72,7 +72,7 @@
:layout-grid-columns []})
(defn get-layout-initializer
[type from-frame?]
[type from-frame? calculate-params?]
(let [[initial-layout-data calculate-params]
(case type
:flex [initial-flex-layout flex/calculate-params]
@ -87,9 +87,11 @@
(cond-> (not from-frame?)
(assoc :show-content true :hide-in-viewer true)))
params (calculate-params objects (cfh/get-immediate-children objects (:id shape)) shape)]
params (when calculate-params?
(calculate-params objects (cfh/get-immediate-children objects (:id shape)) shape))]
(cond-> (merge shape params)
(= type :grid) (-> (ctl/assign-cells objects) ctl/reorder-grid-children))))))
(= type :grid)
(-> (ctl/assign-cells objects) ctl/reorder-grid-children))))))
;; Never call this directly but through the data-event `:layout/update`
;; Otherwise a lot of cycle dependencies could be generated
@ -124,7 +126,7 @@
(ptk/reify ::finalize))
(defn create-layout-from-id
[id type from-frame?]
[id type & {:keys [from-frame? calculate-params?] :or {from-frame? false calculate-params? true}}]
(dm/assert!
"expected uuid for `id`"
(uuid? id))
@ -135,7 +137,7 @@
(let [objects (wsh/lookup-page-objects state)
parent (get objects id)
undo-id (js/Symbol)
layout-initializer (get-layout-initializer type from-frame?)]
layout-initializer (get-layout-initializer type from-frame? calculate-params?)]
(rx/of (dwu/start-undo-transaction undo-id)
(dch/update-shapes [id] layout-initializer {:with-objects? true})
@ -177,7 +179,7 @@
(dwse/select-shapes ordered-ids)
(dwsh/create-artboard-from-selection new-shape-id parent-id group-index (:name (first selected-shapes)))
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
(create-layout-from-id new-shape-id type false)
(create-layout-from-id new-shape-id type)
(dch/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
(dch/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))
(dwsh/delete-shapes page-id selected)
@ -188,7 +190,7 @@
(rx/of
(dwsh/create-artboard-from-selection new-shape-id)
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
(create-layout-from-id new-shape-id type false)
(create-layout-from-id new-shape-id type)
(dch/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
(dch/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))))
@ -227,7 +229,7 @@
(rx/of
(dwu/start-undo-transaction undo-id)
(if (and single? is-frame?)
(create-layout-from-id (first selected) type true)
(create-layout-from-id (first selected) type :from-frame? true)
(create-layout-from-selection type))
(dwu/commit-undo-transaction undo-id))))))

View file

@ -0,0 +1,162 @@
;; 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
(ns app.plugins.grid
(:require
[app.common.data :as d]
[app.common.record :as crc]
[app.common.spec :as us]
[app.common.types.shape.layout :as ctl]
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.store :as st]
[app.plugins.utils :as utils :refer [get-data get-state]]))
(defn- make-tracks
[tracks]
(.freeze
js/Object
(apply array (->> tracks (map utils/to-js)))))
(deftype GridLayout [_data]
Object
(addRow
[self type value]
(let [id (get-data self :id)
type (keyword type)]
(st/emit! (dwsl/add-layout-track #{id} :row {:type type :value value}))))
(addRowAtIndex
[self type value index]
(let [id (get-data self :id)
type (keyword type)]
(st/emit! (dwsl/add-layout-track #{id} :row {:type type :value value} index))))
(addColumn
[self type value]
(let [id (get-data self :id)
type (keyword type)]
(st/emit! (dwsl/add-layout-track #{id} :column {:type type :value value}))))
(addColumnAtIndex
[self type value index]
(let [id (get-data self :id)
type (keyword type)]
(st/emit! (dwsl/add-layout-track #{id} :column {:type type :value value} index))))
(removeRow
[self index]
(let [id (get-data self :id)]
(st/emit! (dwsl/remove-layout-track #{id} :row index))))
(removeColumn
[self index]
(let [id (get-data self :id)]
(st/emit! (dwsl/remove-layout-track #{id} :column index))))
(setColumn
[self index type value]
(let [id (get-data self :id)
type (keyword type)]
(st/emit! (dwsl/change-layout-track #{id} :column index (d/without-nils {:type type :value value})))))
(setRow
[self index type value]
(let [id (get-data self :id)
type (keyword type)]
(st/emit! (dwsl/change-layout-track #{id} :row index (d/without-nils {:type type :value value})))))
(remove
[self]
(let [id (get-data self :id)]
(st/emit! (dwsl/remove-layout #{id})))))
(defn grid-layout-proxy
[data]
(-> (GridLayout. data)
(crc/add-properties!
{:name "dir"
:get #(get-state % :layout-grid-dir d/name)
:set
(fn [self value]
(let [id (get-data self :id)
value (keyword value)]
(when (contains? ctl/grid-direction-types value)
(st/emit! (dwsl/update-layout #{id} {:layout-grid-dir value})))))}
{:name "rows"
:get #(get-state % :layout-grid-rows make-tracks)}
{:name "columns"
:get #(get-state % :layout-grid-columns make-tracks)}
{:name "alignItems"
:get #(get-state % :layout-align-items d/name)
:set
(fn [self value]
(let [id (get-data self :id)
value (keyword value)]
(when (contains? ctl/align-items-types value)
(st/emit! (dwsl/update-layout #{id} {:layout-align-items value})))))}
{:name "alignContent"
:get #(get-state % :layout-align-content d/name)
:set
(fn [self value]
(let [id (get-data self :id)
value (keyword value)]
(when (contains? ctl/align-content-types value)
(st/emit! (dwsl/update-layout #{id} {:layout-align-content value})))))}
{:name "justifyItems"
:get #(get-state % :layout-justify-items d/name)
:set
(fn [self value]
(let [id (get-data self :id)
value (keyword value)]
(when (contains? ctl/justify-items-types value)
(st/emit! (dwsl/update-layout #{id} {:layout-justify-items value})))))}
{:name "justifyContent"
:get #(get-state % :layout-justify-content d/name)
:set
(fn [self value]
(let [id (get-data self :id)
value (keyword value)]
(when (contains? ctl/justify-content-types value)
(st/emit! (dwsl/update-layout #{id} {:layout-justify-content value})))))}
{:name "rowGap"
:get #(:row-gap (get-state % :layout-gap))
:set
(fn [self value]
(let [id (get-data self :id)]
(when (us/safe-int? value)
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))}
{:name "columnGap"
:get #(:column-gap (get-state % :layout-gap))
:set
(fn [self value]
(let [id (get-data self :id)]
(when (us/safe-int? value)
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))}
{:name "verticalPadding"
:get #(:p1 (get-state % :layout-padding))
:set
(fn [self value]
(let [id (get-data self :id)]
(when (us/safe-int? value)
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))}
{:name "horizontalPadding"
:get #(:p2 (get-state % :layout-padding))
:set
(fn [self value]
(let [id (get-data self :id)]
(when (us/safe-int? value)
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))})))

View file

@ -7,7 +7,6 @@
(ns app.plugins.shape
"RPC for plugins runtime."
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.record :as crc]
@ -16,9 +15,11 @@
[app.main.data.workspace :as udw]
[app.main.data.workspace.changes :as dwc]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.store :as st]
[app.plugins.utils :as utils :refer [get-data get-data-fn]]
[app.plugins.grid :as grid]
[app.plugins.utils :as utils :refer [get-data get-data-fn get-state]]
[app.util.object :as obj]))
(declare data->shape-proxy)
@ -40,23 +41,8 @@
(let [page-id (:current-page-id @st/state)]
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects shape-id])))
(defn- get-state
([self attr]
(let [id (get-data self :id)
page-id (d/nilv (get-data self :page-id) (:current-page-id @st/state))]
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id attr])))
([self attr mapfn]
(-> (get-state self attr)
(mapfn))))
(deftype ShapeProxy [^:mutable #_:clj-kondo/ignore _data]
(deftype ShapeProxy [#_:clj-kondo/ignore _data]
Object
(getChildren
[self]
(apply array (->> (get-state self :shapes)
(map locate-shape)
(map data->shape-proxy))))
(resize
[self width height]
(let [id (get-data self :id)]
@ -76,6 +62,13 @@
(let [id (get-data self :id)]
(st/emit! (dwsh/delete-shapes #{id}))))
;; Only for frames + groups + booleans
(getChildren
[self]
(apply array (->> (get-state self :shapes)
(map locate-shape)
(map data->shape-proxy))))
(appendChild [self child]
(let [parent-id (get-data self :id)
child-id (uuid/uuid (obj/get child "id"))]
@ -84,7 +77,16 @@
(insertChild [self index child]
(let [parent-id (get-data self :id)
child-id (uuid/uuid (obj/get child "id"))]
(st/emit! (udw/relocate-shapes #{child-id} parent-id index)))))
(st/emit! (udw/relocate-shapes #{child-id} parent-id index))))
;; Only for frames
(addFlexLayout [self]
(let [id (get-data self :id)]
(st/emit! (dwsl/create-layout-from-id id :flex :from-frame? true :calculate-params? false))))
(addGridLayout [self]
(let [id (get-data self :id)]
(st/emit! (dwsl/create-layout-from-id id :grid :from-frame? true :calculate-params? false)))))
(crc/define-properties!
ShapeProxy
@ -206,6 +208,32 @@
{:name "children"
:get #(.getChildren ^js %)}))
(cond-> (not (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data)))
(-> (obj/unset! "appendChild")
(obj/unset! "insertChild")
(obj/unset! "getChildren")))
(cond-> (cfh/frame-shape? data)
(-> (crc/add-properties!
{:name "grid"
:get
(fn [self]
(let [layout (get-state self :layout)]
(when (= :grid layout)
(grid/grid-layout-proxy data))))})
#_(crc/add-properties!
{:name "flex"
:get
(fn [self]
(let [layout (get-state self :layout)]
(when (= :flex layout)
(flex-layout-proxy data))))})))
(cond-> (not (cfh/frame-shape? data))
(-> (obj/unset! "addGridLayout")
(obj/unset! "addFlexLayout")))
(cond-> (cfh/text-shape? data)
(crc/add-properties!
{:name "characters"
@ -213,4 +241,3 @@
:set (fn [self value]
(let [id (get-data self :id)]
(st/emit! (dwc/update-shapes [id] #(txt/change-text % value)))))}))))

View file

@ -7,9 +7,11 @@
(ns app.plugins.utils
"RPC for plugins runtime."
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.spec :as us]
[app.common.uuid :as uuid]
[app.main.store :as st]
[app.util.object :as obj]
[cuerdas.core :as str]
[promesa.core :as p]))
@ -32,22 +34,34 @@
(fn [self]
(get-data self attr transform-fn))))
(defn get-state
([self attr]
(let [id (get-data self :id)
page-id (d/nilv (get-data self :page-id) (:current-page-id @st/state))]
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id attr])))
([self attr mapfn]
(-> (get-state self attr)
(mapfn))))
(defn from-js
"Converts the object back to js"
[obj]
(let [ret (js->clj obj {:keyword-fn (fn [k] (str/camel (name k)))})]
(reduce-kv
(fn [m k v]
(let [v (cond (map? v)
(from-js v)
([obj]
(from-js obj identity))
([obj vfn]
(let [ret (js->clj obj {:keyword-fn (fn [k] (str/camel (name k)))})]
(reduce-kv
(fn [m k v]
(let [k (keyword (str/kebab k))
v (cond (map? v)
(from-js v)
(and (string? v) (re-matches us/uuid-rx v))
(uuid/uuid v)
(and (string? v) (re-matches us/uuid-rx v))
(uuid/uuid v)
:else v)]
(assoc m (keyword (str/kebab k)) v)))
{}
ret)))
:else (vfn k v))]
(assoc m k v)))
{}
ret))))
(defn to-js
"Converts to javascript an camelize the keys"