mirror of
https://github.com/penpot/penpot.git
synced 2025-02-05 05:49:07 -05:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
da517f2d35
13 changed files with 161 additions and 100 deletions
|
@ -44,7 +44,12 @@
|
|||
(let [component-id (:current-component-id file)
|
||||
change (cond-> change
|
||||
(and add-container? (some? component-id))
|
||||
(assoc :component-id component-id)
|
||||
(cond->
|
||||
:always
|
||||
(assoc :component-id component-id)
|
||||
|
||||
(some? (:current-frame-id file))
|
||||
(assoc :frame-id (:current-frame-id file)))
|
||||
|
||||
(and add-container? (nil? component-id))
|
||||
(assoc :page-id (:current-page-id file)
|
||||
|
@ -223,7 +228,6 @@
|
|||
(clear-names)))
|
||||
|
||||
(defn add-artboard [file data]
|
||||
(assert (nil? (:current-component-id file)))
|
||||
(let [obj (-> (cts/make-minimal-shape :frame)
|
||||
(merge data)
|
||||
(check-name file :frame)
|
||||
|
@ -237,11 +241,11 @@
|
|||
(update :parent-stack conjv (:id obj)))))
|
||||
|
||||
(defn close-artboard [file]
|
||||
(assert (nil? (:current-component-id file)))
|
||||
|
||||
(let [parent-id (-> file :parent-id peek)
|
||||
parent (lookup-shape file parent-id)
|
||||
current-frame-id (or (:frame-id parent) root-frame)]
|
||||
current-frame-id (or (:frame-id parent)
|
||||
(when (nil? (:current-component-id file))
|
||||
root-frame))]
|
||||
(-> file
|
||||
(assoc :current-frame-id current-frame-id)
|
||||
(update :parent-stack pop))))
|
||||
|
@ -561,35 +565,37 @@
|
|||
:id id}))))
|
||||
|
||||
(defn start-component
|
||||
[file data]
|
||||
([file data] (start-component file data :group))
|
||||
([file data root-type]
|
||||
(let [selrect (or (gsh/make-selrect (:x data) (:y data) (:width data) (:height data))
|
||||
cts/empty-selrect)
|
||||
name (:name data)
|
||||
path (:path data)
|
||||
main-instance-id (:main-instance-id data)
|
||||
main-instance-page (:main-instance-page data)
|
||||
obj (-> (cts/make-shape root-type selrect data)
|
||||
(dissoc :path
|
||||
:main-instance-id
|
||||
:main-instance-page
|
||||
:main-instance-x
|
||||
:main-instance-y)
|
||||
(check-name file root-type)
|
||||
(d/without-nils))]
|
||||
(-> file
|
||||
(commit-change
|
||||
{:type :add-component
|
||||
:id (:id obj)
|
||||
:name name
|
||||
:path path
|
||||
:main-instance-id main-instance-id
|
||||
:main-instance-page main-instance-page
|
||||
:shapes [obj]})
|
||||
|
||||
(let [selrect cts/empty-selrect
|
||||
name (:name data)
|
||||
path (:path data)
|
||||
main-instance-id (:main-instance-id data)
|
||||
main-instance-page (:main-instance-page data)
|
||||
obj (-> (cts/make-minimal-group nil selrect name)
|
||||
(merge data)
|
||||
(dissoc :path
|
||||
:main-instance-id
|
||||
:main-instance-page
|
||||
:main-instance-x
|
||||
:main-instance-y)
|
||||
(check-name file :group)
|
||||
(d/without-nils))]
|
||||
(-> file
|
||||
(commit-change
|
||||
{:type :add-component
|
||||
:id (:id obj)
|
||||
:name name
|
||||
:path path
|
||||
:main-instance-id main-instance-id
|
||||
:main-instance-page main-instance-page
|
||||
:shapes [obj]})
|
||||
|
||||
(assoc :last-id (:id obj))
|
||||
(update :parent-stack conjv (:id obj))
|
||||
(assoc :current-component-id (:id obj)))))
|
||||
(assoc :last-id (:id obj))
|
||||
(update :parent-stack conjv (:id obj))
|
||||
(assoc :current-component-id (:id obj))
|
||||
(assoc :current-frame-id (when (= (:type obj) :frame)
|
||||
(:id obj)))))))
|
||||
|
||||
(defn finish-component
|
||||
[file]
|
||||
|
@ -624,7 +630,7 @@
|
|||
|
||||
{:add-container? true}))
|
||||
|
||||
:else
|
||||
(= (:type component) :group)
|
||||
(let [component' (gsh/update-group-selrect component children)]
|
||||
(commit-change
|
||||
file
|
||||
|
@ -637,11 +643,13 @@
|
|||
{:type :set :attr :y :val (-> component' :selrect :y) :ignore-touched true}
|
||||
{:type :set :attr :width :val (-> component' :selrect :width) :ignore-touched true}
|
||||
{:type :set :attr :height :val (-> component' :selrect :height) :ignore-touched true}]}
|
||||
{:add-container? true}))
|
||||
|
||||
{:add-container? true})))]
|
||||
:else file)]
|
||||
|
||||
(-> file
|
||||
(dissoc :current-component-id)
|
||||
(dissoc :current-frame-id)
|
||||
(update :parent-stack pop))))
|
||||
|
||||
(defn finish-deleted-component
|
||||
|
@ -700,7 +708,7 @@
|
|||
(gpt/point x
|
||||
y)
|
||||
#_{:main-instance? true
|
||||
:force-id main-instance-id})]
|
||||
:force-id main-instance-id})]
|
||||
|
||||
(as-> file $
|
||||
(reduce #(commit-change %1
|
||||
|
|
|
@ -183,7 +183,6 @@
|
|||
(dm/export gsi/rect-contains-shape?)
|
||||
|
||||
;; Bool
|
||||
|
||||
(dm/export gsb/calc-bool-content)
|
||||
|
||||
;; Constraints
|
||||
|
@ -196,4 +195,3 @@
|
|||
|
||||
;; Modifiers
|
||||
(dm/export gsm/set-objects-modifiers)
|
||||
|
||||
|
|
|
@ -270,7 +270,6 @@
|
|||
(update :undo-changes #(reduce mk-undo-change % shapes))
|
||||
(apply-changes-local)))))
|
||||
|
||||
|
||||
(defn changed-attrs
|
||||
"Returns the list of attributes that will change when `update-fn` is applied"
|
||||
[object update-fn {:keys [attrs]}]
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[app.common.types.page :as ctp]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.typography :as ctt]
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
(s/def ::index integer?)
|
||||
|
@ -61,7 +62,7 @@
|
|||
(some? (:frame-id o)))
|
||||
(and (contains? o :component-id)
|
||||
(not (contains? o :page-id))
|
||||
(nil? (:frame-id o)))))
|
||||
(not= (:frame-id o) uuid/zero))))
|
||||
|
||||
(defn- valid-container-id?
|
||||
[o]
|
||||
|
|
|
@ -69,13 +69,16 @@
|
|||
(assert (nil? (:component-id shape)))
|
||||
(assert (nil? (:component-file shape)))
|
||||
(assert (nil? (:shape-ref shape)))
|
||||
(let [;; Ensure that the component root is not an instance and
|
||||
;; it's no longer tied to a frame.
|
||||
update-new-shape (fn [new-shape _original-shape]
|
||||
(let [frame-ids-map (volatile! {})
|
||||
|
||||
;; Ensure that the component root is not an instance
|
||||
update-new-shape (fn [new-shape original-shape]
|
||||
(when (= (:type original-shape) :frame)
|
||||
(vswap! frame-ids-map assoc (:id original-shape) (:id new-shape)))
|
||||
|
||||
(cond-> new-shape
|
||||
true
|
||||
(-> (assoc :frame-id nil)
|
||||
(dissoc :component-root?))
|
||||
(dissoc :component-root?)
|
||||
|
||||
(nil? (:parent-id new-shape))
|
||||
(dissoc :component-id
|
||||
|
@ -100,9 +103,17 @@
|
|||
(assoc :main-instance? true)
|
||||
|
||||
(some? (:parent-id new-shape))
|
||||
(dissoc :component-root?)))]
|
||||
(dissoc :component-root?)))
|
||||
|
||||
(ctst/clone-object shape nil objects update-new-shape update-original-shape)))
|
||||
[new-root-shape new-shapes updated-shapes]
|
||||
(ctst/clone-object shape nil objects update-new-shape update-original-shape)
|
||||
|
||||
;; If frame-id points to a shape inside the component, remap it to the
|
||||
;; corresponding new frame shape. If not, set it to nil.
|
||||
remap-frame-id (fn [shape]
|
||||
(update shape :frame-id #(get @frame-ids-map % nil)))]
|
||||
|
||||
[new-root-shape (map remap-frame-id new-shapes) updated-shapes]))
|
||||
|
||||
(defn make-component-instance
|
||||
"Clone the shapes of the component, generating new names and ids, and linking
|
||||
|
@ -115,13 +126,14 @@
|
|||
{:keys [main-instance? force-id] :or {main-instance? false force-id nil}}]
|
||||
(let [component-shape (get-shape component (:id component))
|
||||
|
||||
orig-pos (gpt/point (:x component-shape) (:y component-shape))
|
||||
delta (gpt/subtract position orig-pos)
|
||||
orig-pos (gpt/point (:x component-shape) (:y component-shape))
|
||||
delta (gpt/subtract position orig-pos)
|
||||
|
||||
objects (:objects container)
|
||||
unames (volatile! (ctst/retrieve-used-names objects))
|
||||
objects (:objects container)
|
||||
unames (volatile! (ctst/retrieve-used-names objects))
|
||||
|
||||
frame-id (ctst/frame-id-by-position objects (gpt/add orig-pos delta))
|
||||
frame-id (ctst/frame-id-by-position objects (gpt/add orig-pos delta))
|
||||
frame-ids-map (volatile! {})
|
||||
|
||||
update-new-shape
|
||||
(fn [new-shape original-shape]
|
||||
|
@ -130,14 +142,13 @@
|
|||
(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)))
|
||||
|
||||
(cond-> new-shape
|
||||
true
|
||||
(as-> $
|
||||
(gsh/move $ delta)
|
||||
(assoc $ :frame-id frame-id)
|
||||
(assoc $ :parent-id
|
||||
(or (:parent-id $) (:frame-id $)))
|
||||
(dissoc $ :touched))
|
||||
(-> (gsh/move delta)
|
||||
(dissoc :touched))
|
||||
|
||||
(nil? (:shape-ref original-shape))
|
||||
(assoc :shape-ref (:id original-shape))
|
||||
|
@ -160,7 +171,15 @@
|
|||
(get component :objects)
|
||||
update-new-shape
|
||||
(fn [object _] object)
|
||||
force-id)]
|
||||
force-id)
|
||||
|
||||
[new-shape new-shapes])))
|
||||
;; 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 $)))))]
|
||||
|
||||
[new-shape (map remap-frame-id new-shapes)])))
|
||||
|
||||
|
|
|
@ -397,11 +397,13 @@
|
|||
|
||||
group-wrapper
|
||||
(mf/use-memo
|
||||
(mf/deps objects root-shape)
|
||||
(fn []
|
||||
(case (:type root-shape)
|
||||
:group (group-wrapper-factory objects)
|
||||
:frame (frame-wrapper-factory objects))))]
|
||||
(mf/deps objects)
|
||||
(fn [] (group-wrapper-factory objects)))
|
||||
|
||||
frame-wrapper
|
||||
(mf/use-memo
|
||||
(mf/deps objects)
|
||||
(fn [] (frame-wrapper-factory objects)))]
|
||||
|
||||
[:> "symbol" #js {:id (str id)
|
||||
:viewBox vbox
|
||||
|
@ -412,7 +414,9 @@
|
|||
"penpot:main-instance-y" main-instance-y}
|
||||
[:title name]
|
||||
[:> shape-container {:shape root-shape}
|
||||
[:& group-wrapper {:shape root-shape :view-box vbox}]]]))
|
||||
(case (:type root-shape)
|
||||
:group [:& group-wrapper {:shape root-shape :view-box vbox}]
|
||||
:frame [:& frame-wrapper {:shape root-shape :view-box vbox}])]]))
|
||||
|
||||
(mf/defc components-sprite-svg
|
||||
{::mf/wrap-props false}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
[app.main.ui.workspace.viewport.utils :as vwu]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as globals]
|
||||
[debug :refer [debug?]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn get-shape-node
|
||||
|
@ -52,19 +53,27 @@
|
|||
masking-child?
|
||||
[shape-node
|
||||
(dom/query parent-node ".mask-clip-path")
|
||||
(dom/query parent-node ".mask-shape")]
|
||||
(dom/query parent-node ".mask-shape")
|
||||
(when (debug? :shape-titles)
|
||||
(dom/query (dm/str "#frame-title-" id)))]
|
||||
|
||||
group?
|
||||
(let [shape-defs (dom/query shape-node "defs")]
|
||||
(d/concat-vec
|
||||
[(when (debug? :shape-titles)
|
||||
(dom/query (dm/str "#frame-title-" id)))]
|
||||
(dom/query-all shape-defs ".svg-def")
|
||||
(dom/query-all shape-defs ".svg-mask-wrapper")))
|
||||
|
||||
text?
|
||||
[shape-node]
|
||||
[shape-node
|
||||
(when (debug? :shape-titles)
|
||||
(dom/query (dm/str "#frame-title-" id)))]
|
||||
|
||||
:else
|
||||
[shape-node]))))
|
||||
[shape-node
|
||||
(when (debug? :shape-titles)
|
||||
(dom/query (dm/str "#frame-title-" id)))]))))
|
||||
|
||||
(defn transform-region!
|
||||
[node modifiers]
|
||||
|
|
|
@ -311,7 +311,15 @@
|
|||
|
||||
;; Debug only: Disable the thumbnails
|
||||
new-active-frames
|
||||
(if (debug? :disable-frame-thumbnails) (into #{} all-frames) new-active-frames)]
|
||||
(cond
|
||||
(debug? :disable-frame-thumbnails)
|
||||
(into #{} all-frames)
|
||||
|
||||
(debug? :force-frame-thumbnails)
|
||||
#{}
|
||||
|
||||
:else
|
||||
new-active-frames)]
|
||||
|
||||
(when (not= @active-frames new-active-frames)
|
||||
(reset! active-frames new-active-frames)))))))
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
(let [inv-zoom (/ 1 zoom)]
|
||||
(dm/fmt "scale(%, %) translate(%, %)" inv-zoom inv-zoom (* zoom x) (* zoom y))))
|
||||
|
||||
(defn title-transform [frame zoom]
|
||||
(let [frame-transform (gsh/transform-str frame {:no-flip true})
|
||||
label-pos (gpt/point (:x frame) (- (:y frame) (/ 10 zoom)))]
|
||||
(dm/str frame-transform " " (text-transform label-pos zoom))))
|
||||
(defn title-transform [{:keys [selrect] :as shape} zoom]
|
||||
(let [transform (gsh/transform-str shape {:no-flip true})
|
||||
label-pos (gpt/point (:x selrect) (- (:y selrect) (/ 10 zoom)))]
|
||||
(dm/str transform " " (text-transform label-pos zoom))))
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
(mf/defc frame-title
|
||||
{::mf/wrap [mf/memo
|
||||
#(mf/deferred % ts/raf)]}
|
||||
[{:keys [frame selected? zoom show-artboard-names? on-frame-enter on-frame-leave on-frame-select]}]
|
||||
[{:keys [frame selected? zoom show-artboard-names? show-id? on-frame-enter on-frame-leave on-frame-select]}]
|
||||
(let [workspace-read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
on-mouse-down
|
||||
(mf/use-callback
|
||||
|
@ -148,7 +148,6 @@
|
|||
:width (:width frame)
|
||||
:height 20
|
||||
:class "workspace-frame-label"
|
||||
;:transform (dm/str frame-transform " " (text-transform label-pos zoom))
|
||||
:style {:fill (when selected? "var(--color-primary-dark)")}
|
||||
:visibility (if show-artboard-names? "visible" "hidden")
|
||||
:on-mouse-down on-mouse-down
|
||||
|
@ -156,7 +155,9 @@
|
|||
:on-context-menu on-context-menu
|
||||
:on-pointer-enter on-pointer-enter
|
||||
:on-pointer-leave on-pointer-leave}
|
||||
(:name frame)]])))
|
||||
(if show-id?
|
||||
(dm/str (dm/str (:id frame)) " - " (:name frame))
|
||||
(:name frame))]])))
|
||||
|
||||
(mf/defc frame-titles
|
||||
{::mf/wrap-props false
|
||||
|
@ -169,20 +170,26 @@
|
|||
on-frame-enter (unchecked-get props "on-frame-enter")
|
||||
on-frame-leave (unchecked-get props "on-frame-leave")
|
||||
on-frame-select (unchecked-get props "on-frame-select")
|
||||
frames (ctt/get-frames objects)
|
||||
shapes (ctt/get-frames objects)
|
||||
shapes (if (debug? :shape-titles)
|
||||
(into (set shapes)
|
||||
(map (d/getf objects))
|
||||
selected)
|
||||
shapes)
|
||||
focus (unchecked-get props "focus")]
|
||||
|
||||
[:g.frame-titles
|
||||
(for [frame frames]
|
||||
(for [{:keys [id parent-id] :as shape} shapes]
|
||||
(when (and
|
||||
(= (:parent-id frame) uuid/zero)
|
||||
(or (empty? focus)
|
||||
(contains? focus (:id frame))))
|
||||
[:& frame-title {:key (dm/str "frame-title-" (:id frame))
|
||||
:frame frame
|
||||
:selected? (contains? selected (:id frame))
|
||||
(not= id uuid/zero)
|
||||
(or (debug? :shape-titles) (= parent-id uuid/zero))
|
||||
(or (empty? focus) (contains? focus id)))
|
||||
[:& frame-title {:key (dm/str "frame-title-" id)
|
||||
:frame shape
|
||||
:selected? (contains? selected id)
|
||||
:zoom zoom
|
||||
:show-artboard-names? show-artboard-names?
|
||||
:show-id? (debug? :shape-titles)
|
||||
:on-frame-enter on-frame-enter
|
||||
:on-frame-leave on-frame-leave
|
||||
:on-frame-select on-frame-select}]))]))
|
||||
|
|
|
@ -64,9 +64,9 @@
|
|||
(or (find-node node :penpot:shape)
|
||||
(find-node node :penpot:page)))
|
||||
|
||||
([node tag]
|
||||
(-> (get-data node)
|
||||
(find-node tag))))
|
||||
([node tag]
|
||||
(-> (get-data node)
|
||||
(find-node tag))))
|
||||
|
||||
(defn get-type
|
||||
[node]
|
||||
|
@ -217,10 +217,10 @@
|
|||
(let [;; Old .penpot files doesn't have "g" nodes. They have a clipPath reference as a node attribute
|
||||
to-url #(dm/str "url(#" % ")")
|
||||
frame-clip-rect-node (->> (find-all-nodes node :defs)
|
||||
(mapcat #(find-all-nodes % :clipPath))
|
||||
(filter #(= (to-url (:id (:attrs %))) (:clip-path node-attrs)))
|
||||
(mapcat #(find-all-nodes % #{:rect :path}))
|
||||
(first))
|
||||
(mapcat #(find-all-nodes % :clipPath))
|
||||
(filter #(= (to-url (:id (:attrs %))) (:clip-path node-attrs)))
|
||||
(mapcat #(find-all-nodes % #{:rect :path}))
|
||||
(first))
|
||||
|
||||
;; The nodes with the "frame-background" class can have some anidation depending on the strokes they have
|
||||
g-nodes (find-all-nodes node :g)
|
||||
|
@ -1007,8 +1007,8 @@
|
|||
(ctsi/has-overlay-opts interaction)
|
||||
(assoc :overlay-pos-type (get-meta node :overlay-pos-type keyword)
|
||||
:overlay-position (gpt/point
|
||||
(get-meta node :overlay-position-x d/parse-double)
|
||||
(get-meta node :overlay-position-y d/parse-double))
|
||||
(get-meta node :overlay-position-x d/parse-double)
|
||||
(get-meta node :overlay-position-y d/parse-double))
|
||||
:close-click-outside (get-meta node :close-click-outside str->bool)
|
||||
:background-overlay (get-meta node :background-overlay str->bool)))))))))
|
||||
|
||||
|
|
|
@ -389,21 +389,22 @@
|
|||
old-id (cip/get-id node)
|
||||
id (resolve old-id)
|
||||
path (get-in node [:attrs :penpot:path] "")
|
||||
type (cip/get-type content)
|
||||
main-instance-id (resolve (uuid (get-in node [:attrs :penpot:main-instance-id] "")))
|
||||
main-instance-page (resolve (uuid (get-in node [:attrs :penpot:main-instance-page] "")))
|
||||
data (-> (cip/parse-data :group content)
|
||||
data (-> (cip/parse-data type content)
|
||||
(assoc :path path)
|
||||
(assoc :id id)
|
||||
(assoc :main-instance-id main-instance-id)
|
||||
(assoc :main-instance-page main-instance-page))
|
||||
|
||||
file (-> file (fb/start-component data))
|
||||
children (cip/node-seq node)]
|
||||
file (-> file (fb/start-component data type))
|
||||
children (cip/node-seq node)]
|
||||
|
||||
(->> (rx/from children)
|
||||
(rx/filter cip/shape?)
|
||||
(rx/skip 1)
|
||||
(rx/skip-last 1)
|
||||
(rx/skip 1) ;; Skip the outer component and the respective closint tag
|
||||
(rx/skip-last 1) ;; because they are handled in start-component an finish-component
|
||||
(rx/mapcat (partial resolve-media context file-id))
|
||||
(rx/reduce (partial process-import-node context) file)
|
||||
(rx/map fb/finish-component))))
|
||||
|
@ -419,8 +420,9 @@
|
|||
main-instance-page (resolve (uuid (get-in node [:attrs :penpot:main-instance-page] "")))
|
||||
main-instance-x (get-in node [:attrs :penpot:main-instance-x] "")
|
||||
main-instance-y (get-in node [:attrs :penpot:main-instance-y] "")
|
||||
type (cip/get-type content)
|
||||
|
||||
data (-> (cip/parse-data :group content)
|
||||
data (-> (cip/parse-data type content)
|
||||
(assoc :path path)
|
||||
(assoc :id id)
|
||||
(assoc :main-instance-id main-instance-id)
|
||||
|
|
|
@ -69,6 +69,9 @@
|
|||
;; Disable frame thumbnails
|
||||
:disable-frame-thumbnails
|
||||
|
||||
;; Force thumbnails always (independent of selection or zoom level)
|
||||
:force-frame-thumbnails
|
||||
|
||||
;; Enable a widget to show the auto-layout drop-zones
|
||||
:layout-drop-zones
|
||||
|
||||
|
@ -89,6 +92,9 @@
|
|||
|
||||
;; Show history overlay
|
||||
:history-overlay
|
||||
|
||||
;; Show shape name and id
|
||||
:shape-titles
|
||||
})
|
||||
|
||||
;; These events are excluded when we activate the :events flag
|
||||
|
|
Loading…
Add table
Reference in a new issue