mirror of
https://github.com/penpot/penpot.git
synced 2025-07-26 09:27:17 +02:00
⚡ Add experimental equality with exceptions props checking to frames
This commit is contained in:
parent
b28cad2250
commit
58f788455f
3 changed files with 90 additions and 34 deletions
|
@ -36,12 +36,17 @@
|
||||||
:else `(. ~this-sym ~(property-symbol field))))
|
:else `(. ~this-sym ~(property-symbol field))))
|
||||||
fields)))
|
fields)))
|
||||||
|
|
||||||
|
|
||||||
|
(defprotocol ICustomRecordEquiv
|
||||||
|
(-equiv-with-exceptions [_ other exceptions]))
|
||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(defn emit-impl-js
|
(defn emit-impl-js
|
||||||
[tagname base-fields]
|
[tagname base-fields]
|
||||||
(let [fields (conj base-fields '$meta '$extmap (with-meta '$hash {:mutable true}))
|
(let [fields (conj base-fields '$meta '$extmap (with-meta '$hash {:mutable true}))
|
||||||
key-sym (gensym "key-")
|
key-sym (gensym "key-")
|
||||||
val-sym (gensym "val-")
|
val-sym (gensym "val-")
|
||||||
|
othr-sym (with-meta 'other {:tag tagname})
|
||||||
this-sym (with-meta 'this {:tag tagname})]
|
this-sym (with-meta 'this {:tag tagname})]
|
||||||
['cljs.core/IRecord
|
['cljs.core/IRecord
|
||||||
'cljs.core/ICloneable
|
'cljs.core/ICloneable
|
||||||
|
@ -58,16 +63,41 @@
|
||||||
(. ~this-sym ~'-$hash)))
|
(. ~this-sym ~'-$hash)))
|
||||||
|
|
||||||
'cljs.core/IEquiv
|
'cljs.core/IEquiv
|
||||||
`(~'-equiv [~this-sym ~val-sym]
|
`(~'-equiv [~this-sym ~othr-sym]
|
||||||
(and (some? ~val-sym)
|
(or (identical? ~this-sym ~othr-sym)
|
||||||
|
(and (some? ~othr-sym)
|
||||||
(identical? (.-constructor ~this-sym)
|
(identical? (.-constructor ~this-sym)
|
||||||
(.-constructor ~val-sym))
|
(.-constructor ~othr-sym))
|
||||||
~@(map (fn [field]
|
~@(map (fn [field]
|
||||||
`(= (.. ~this-sym ~(property-symbol field))
|
`(= (.. ~this-sym ~(property-symbol field))
|
||||||
(.. ~(with-meta val-sym {:tag tagname}) ~(property-symbol field))))
|
(.. ~(with-meta othr-sym {:tag tagname}) ~(property-symbol field))))
|
||||||
base-fields)
|
base-fields)
|
||||||
|
|
||||||
(= (. ~this-sym ~'-$extmap)
|
(= (. ~this-sym ~'-$extmap)
|
||||||
(. ~(with-meta val-sym {:tag tagname}) ~'-$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
|
'cljs.core/IMeta
|
||||||
`(~'-meta [~this-sym] (. ~this-sym ~'-$meta))
|
`(~'-meta [~this-sym] (. ~this-sym ~'-$meta))
|
||||||
|
|
|
@ -68,46 +68,52 @@
|
||||||
|
|
||||||
[:g.frame-children
|
[:g.frame-children
|
||||||
(for [shape shapes]
|
(for [shape shapes]
|
||||||
[:g.ws-shape-wrapper {:key (:id shape)}
|
[:g.ws-shape-wrapper {:key (dm/str (dm/get-prop shape :id))}
|
||||||
(cond
|
(if (not ^boolean (cph/frame-shape? shape))
|
||||||
(not (cph/frame-shape? shape))
|
|
||||||
[:& shape-wrapper
|
[:& shape-wrapper
|
||||||
{:shape shape}]
|
{:shape shape}]
|
||||||
|
(if ^boolean (cph/is-direct-child-of-root? shape)
|
||||||
(cph/is-direct-child-of-root? shape)
|
|
||||||
[:& root-frame-wrapper
|
[:& root-frame-wrapper
|
||||||
{:shape shape
|
{:shape shape
|
||||||
:objects (get frame-objects (:id shape))
|
:objects (get frame-objects (dm/get-prop shape :id))
|
||||||
:thumbnail? (not (contains? active-frames (:id shape)))}]
|
:thumbnail? (not (contains? active-frames (dm/get-prop shape :id)))}]
|
||||||
|
|
||||||
:else
|
|
||||||
[:& nested-frame-wrapper
|
[:& nested-frame-wrapper
|
||||||
{:shape shape
|
{:shape shape
|
||||||
:objects (get frame-objects (:id shape))}])])]]]))
|
:objects (get frame-objects (dm/get-prop shape :id))}]))])]]]))
|
||||||
|
|
||||||
|
(defn- check-shape-wrapper-props
|
||||||
|
[np op]
|
||||||
|
(frame/check-shape (unchecked-get np "shape")
|
||||||
|
(unchecked-get op "shape")))
|
||||||
|
|
||||||
(mf/defc shape-wrapper
|
(mf/defc shape-wrapper
|
||||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))]
|
{::mf/wrap [#(mf/memo' % check-shape-wrapper-props)]
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[props]
|
[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
|
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?
|
thumbnail?
|
||||||
(and (some? active-frames)
|
(and (some? active-frames)
|
||||||
(not (contains? active-frames (:id shape))))
|
(not (contains? active-frames shape-id)))
|
||||||
|
|
||||||
opts #js {:shape shape :thumbnail? thumbnail?}
|
opts #js {:shape shape :thumbnail? thumbnail?}
|
||||||
|
|
||||||
[wrapper wrapper-props]
|
[wrapper wrapper-props]
|
||||||
(if (= :svg-raw (:type shape))
|
(if (= :svg-raw shape-type)
|
||||||
[mf/Fragment nil]
|
[mf/Fragment nil]
|
||||||
["g" #js {:className "workspace-shape-wrapper"}])]
|
["g" #js {:className "workspace-shape-wrapper"}])]
|
||||||
|
|
||||||
(when (and (some? shape) (not (:hidden shape)))
|
(when (and (some? shape)
|
||||||
|
(not ^boolean (:hidden shape)))
|
||||||
[:> wrapper wrapper-props
|
[:> wrapper wrapper-props
|
||||||
(case (:type shape)
|
(case shape-type
|
||||||
:path [:> path/path-wrapper opts]
|
:path [:> path/path-wrapper opts]
|
||||||
:text [:> text/text-wrapper opts]
|
:text [:> text/text-wrapper opts]
|
||||||
:group [:> group-wrapper opts]
|
:group [:> group-wrapper opts]
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
|
[app.common.record :as cr]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.data.workspace.thumbnails :as dwt]
|
[app.main.data.workspace.thumbnails :as dwt]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
|
@ -25,17 +26,36 @@
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[rumext.v2 :as mf]))
|
[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
|
(defn frame-shape-factory
|
||||||
[shape-wrapper]
|
[shape-wrapper]
|
||||||
(let [frame-shape (frame/frame-shape shape-wrapper)]
|
(let [frame-shape (frame/frame-shape shape-wrapper)]
|
||||||
(mf/fnc frame-shape-inner
|
(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/wrap-props false
|
||||||
::mf/forward-ref true}
|
::mf/forward-ref true}
|
||||||
[props ref]
|
[props ref]
|
||||||
|
|
||||||
(let [shape (unchecked-get props "shape")
|
(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)]
|
childs (mf/deref childs-ref)]
|
||||||
|
|
||||||
[:& (mf/provider embed/context) {:value true}
|
[:& (mf/provider embed/context) {:value true}
|
||||||
|
@ -46,7 +66,7 @@
|
||||||
[new-props old-props]
|
[new-props old-props]
|
||||||
(and (= (unchecked-get new-props "thumbnail?")
|
(and (= (unchecked-get new-props "thumbnail?")
|
||||||
(unchecked-get old-props "thumbnail?"))
|
(unchecked-get old-props "thumbnail?"))
|
||||||
(= (unchecked-get new-props "shape")
|
(check-shape (unchecked-get new-props "shape")
|
||||||
(unchecked-get old-props "shape"))))
|
(unchecked-get old-props "shape"))))
|
||||||
|
|
||||||
(defn nested-frame-wrapper-factory
|
(defn nested-frame-wrapper-factory
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue