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

View file

@ -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))

View file

@ -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]

View file

@ -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