0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-31 00:51:19 -05:00

Add experimental equality with exceptions props checking to frames

This commit is contained in:
Andrey Antukh 2023-08-28 15:36:23 +02:00
parent b28cad2250
commit 58f788455f
3 changed files with 90 additions and 34 deletions
common/src/app/common
frontend/src/app/main/ui/workspace

View file

@ -36,12 +36,17 @@
:else `(. ~this-sym ~(property-symbol field))))
fields)))
(defprotocol ICustomRecordEquiv
(-equiv-with-exceptions [_ other exceptions]))
#?(:clj
(defn emit-impl-js
[tagname base-fields]
(let [fields (conj base-fields '$meta '$extmap (with-meta '$hash {:mutable true}))
key-sym (gensym "key-")
val-sym (gensym "val-")
othr-sym (with-meta 'other {:tag tagname})
this-sym (with-meta 'this {:tag tagname})]
['cljs.core/IRecord
'cljs.core/ICloneable
@ -58,16 +63,41 @@
(. ~this-sym ~'-$hash)))
'cljs.core/IEquiv
`(~'-equiv [~this-sym ~val-sym]
(and (some? ~val-sym)
(identical? (.-constructor ~this-sym)
(.-constructor ~val-sym))
~@(map (fn [field]
`(= (.. ~this-sym ~(property-symbol field))
(.. ~(with-meta val-sym {:tag tagname}) ~(property-symbol field))))
base-fields)
(= (. ~this-sym ~'-$extmap)
(. ~(with-meta val-sym {:tag tagname}) ~'-$extmap))))
`(~'-equiv [~this-sym ~othr-sym]
(or (identical? ~this-sym ~othr-sym)
(and (some? ~othr-sym)
(identical? (.-constructor ~this-sym)
(.-constructor ~othr-sym))
~@(map (fn [field]
`(= (.. ~this-sym ~(property-symbol field))
(.. ~(with-meta othr-sym {:tag tagname}) ~(property-symbol field))))
base-fields)
(= (. ~this-sym ~'-$extmap)
(. ~(with-meta othr-sym {:tag tagname}) ~'-$extmap)))))
`ICustomRecordEquiv
`(~'-equiv-with-exceptions [~this-sym ~othr-sym ~'exceptions]
(or (identical? ~this-sym ~othr-sym)
(and (some? ~othr-sym)
(identical? (.-constructor ~this-sym)
(.-constructor ~othr-sym))
(and ~@(->> base-fields
(map (fn [field]
`(= (.. ~this-sym ~(property-symbol field))
(.. ~(with-meta othr-sym {:tag tagname}) ~(property-symbol field))))))
(== (count (. ~this-sym ~'-$extmap))
(count (. ~othr-sym ~'-$extmap))))
(reduce-kv (fn [~'_ ~'k ~'v]
(if (contains? ~'exceptions ~'k)
true
(if (= (get (. ~this-sym ~'-$extmap) ~'k ::not-exists) ~'v)
true
(reduced false))))
true
(. ~othr-sym ~'-$extmap)))))
'cljs.core/IMeta
`(~'-meta [~this-sym] (. ~this-sym ~'-$meta))

View file

@ -68,46 +68,52 @@
[:g.frame-children
(for [shape shapes]
[:g.ws-shape-wrapper {:key (:id shape)}
(cond
(not (cph/frame-shape? shape))
[:g.ws-shape-wrapper {:key (dm/str (dm/get-prop shape :id))}
(if (not ^boolean (cph/frame-shape? shape))
[:& shape-wrapper
{:shape shape}]
(if ^boolean (cph/is-direct-child-of-root? shape)
[:& root-frame-wrapper
{:shape shape
:objects (get frame-objects (dm/get-prop shape :id))
:thumbnail? (not (contains? active-frames (dm/get-prop shape :id)))}]
[:& nested-frame-wrapper
{:shape shape
:objects (get frame-objects (dm/get-prop shape :id))}]))])]]]))
(cph/is-direct-child-of-root? shape)
[:& root-frame-wrapper
{:shape shape
:objects (get frame-objects (:id shape))
:thumbnail? (not (contains? active-frames (:id shape)))}]
:else
[:& nested-frame-wrapper
{:shape shape
:objects (get frame-objects (:id shape))}])])]]]))
(defn- check-shape-wrapper-props
[np op]
(frame/check-shape (unchecked-get np "shape")
(unchecked-get op "shape")))
(mf/defc shape-wrapper
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))]
{::mf/wrap [#(mf/memo' % check-shape-wrapper-props)]
::mf/wrap-props false}
[props]
(let [shape (obj/get props "shape")
(let [shape (unchecked-get props "shape")
shape-type (dm/get-prop shape :type)
shape-id (dm/get-prop shape :id)
;; FIXME: WARN: this breaks react rule of hooks (hooks can't be under conditional)
active-frames
(when (cph/is-direct-child-of-root? shape) (mf/use-ctx ctx/active-frames))
(when (cph/is-direct-child-of-root? shape)
(mf/use-ctx ctx/active-frames))
thumbnail?
(and (some? active-frames)
(not (contains? active-frames (:id shape))))
(not (contains? active-frames shape-id)))
opts #js {:shape shape :thumbnail? thumbnail?}
[wrapper wrapper-props]
(if (= :svg-raw (:type shape))
(if (= :svg-raw shape-type)
[mf/Fragment nil]
["g" #js {:className "workspace-shape-wrapper"}])]
(when (and (some? shape) (not (:hidden shape)))
(when (and (some? shape)
(not ^boolean (:hidden shape)))
[:> wrapper wrapper-props
(case (:type shape)
(case shape-type
:path [:> path/path-wrapper opts]
:text [:> text/text-wrapper opts]
:group [:> group-wrapper opts]

View file

@ -9,6 +9,7 @@
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.pages.helpers :as cph]
[app.common.record :as cr]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.thumbnails :as dwt]
[app.main.refs :as refs]
@ -25,17 +26,36 @@
[beicon.core :as rx]
[rumext.v2 :as mf]))
(def ^:private excluded-attrs
#{:blocked
:hide-fill-on-export
:collapsed
:remote-synced
:exports})
(defn check-shape
[new-shape old-shape]
(cr/-equiv-with-exceptions old-shape new-shape excluded-attrs))
(defn check-frame-props
[np op]
(check-shape (unchecked-get np "shape")
(unchecked-get op "shape")))
(defn frame-shape-factory
[shape-wrapper]
(let [frame-shape (frame/frame-shape shape-wrapper)]
(mf/fnc frame-shape-inner
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))]
{::mf/wrap [#(mf/memo' % check-frame-props)]
::mf/wrap-props false
::mf/forward-ref true}
[props ref]
(let [shape (unchecked-get props "shape")
childs-ref (mf/use-memo (mf/deps (:id shape)) #(refs/children-objects (:id shape)))
shape-id (dm/get-prop shape :id)
childs-ref (mf/with-memo [shape-id]
(refs/children-objects shape-id))
childs (mf/deref childs-ref)]
[:& (mf/provider embed/context) {:value true}
@ -46,8 +66,8 @@
[new-props old-props]
(and (= (unchecked-get new-props "thumbnail?")
(unchecked-get old-props "thumbnail?"))
(= (unchecked-get new-props "shape")
(unchecked-get old-props "shape"))))
(check-shape (unchecked-get new-props "shape")
(unchecked-get old-props "shape"))))
(defn nested-frame-wrapper-factory
[shape-wrapper]