0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-12 07:41:43 -05:00

🎉 Add shared state hook and broadcast channel api

This commit is contained in:
Andrey Antukh 2022-08-09 19:27:19 +02:00
parent 756b6d4fbd
commit 9950c5dc0f
5 changed files with 81 additions and 23 deletions

View file

@ -0,0 +1,52 @@
;; 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) UXBOX Labs SL
(ns app.main.broadcast
"BroadcastChannel API."
(:require
[app.common.transit :as t]
[beicon.core :as rx]
[potok.core :as ptk]))
(defrecord BroadcastMessage [id type data]
cljs.core/IDeref
(-deref [_] data))
(def ^:const default-topic "penpot")
;; The main broadcast channel instance, used for emit data
(defonce default-channel
(js/BroadcastChannel. default-topic))
(defonce stream
(->> (rx/create (fn [subs]
(let [chan (js/BroadcastChannel. default-topic)]
(unchecked-set chan "onmessage" #(rx/push! subs (unchecked-get % "data")))
(fn [] (.close ^js chan)))))
(rx/map t/decode-str)
(rx/map map->BroadcastMessage)
(rx/share)))
(defn emit!
([type data]
(.postMessage ^js default-channel (t/encode-str {:id nil :type type :data data}))
nil)
([id type data]
(.postMessage ^js default-channel (t/encode-str {:id id :type type :data data}))
nil))
(defn type?
([type]
(fn [obj] (= (:type obj) type)))
([obj type]
(= (:type obj) type)))
(defn event
[type data]
(ptk/reify ::event
ptk/EffectEvent
(effect [_ _ _]
(emit! type data))))

View file

@ -9,6 +9,7 @@
[app.common.colors :as colors]
[app.common.data :as d]
[app.common.pages.helpers :as cph]
[app.main.broadcast :as mbc]
[app.main.data.modal :as md]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.layout :as layout]
@ -19,30 +20,18 @@
[beicon.core :as rx]
[potok.core :as ptk]))
(defn change-palette-selected
"Change the library used by the general palette tool"
[selected]
(ptk/reify ::change-palette-selected
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-global :selected-palette] selected))
ptk/EffectEvent
(effect [_ state _]
(let [wglobal (:workspace-global state)]
(layout/persist-layout-state! wglobal)))))
;; A set of keys that are used for shared state identifiers
(def ^:const colorpicker-selected-broadcast-key ::colorpicker-selected)
(def ^:const colorpalette-selected-broadcast-key ::colorpalette-selected)
(defn show-palette
"Show the palette tool and change the library it uses"
[selected]
(ptk/reify ::show-palette
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-global :selected-palette] selected))
ptk/WatchEvent
(watch [_ _ _]
(rx/of (layout/toggle-layout-flag :colorpalette :force? true)))
(rx/of (layout/toggle-layout-flag :colorpalette :force? true)
(mbc/event colorpalette-selected-broadcast-key selected)))
ptk/EffectEvent
(effect [_ state _]

View file

@ -7,9 +7,10 @@
(ns app.main.ui.hooks
"A collection of general purpose react hooks."
(:require
[app.common.uuid :as uuid]
[app.common.data.macros :as dm]
[app.common.pages :as cp]
[app.common.uuid :as uuid]
[app.main.broadcast :as mbc]
[app.main.data.shortcuts :as dsc]
[app.main.refs :as refs]
[app.main.store :as st]
@ -289,9 +290,26 @@
(update-fn value))
state))
(defn use-persistent-state
(defn use-shared-state
"A specialized hook that adds persistence and inter-context reactivity
to the default mf/use-state hook.
The state is automatically persisted under the provided key on
localStorage. And it will keep watching events with type equals to
`key` for new values."
[key default]
(let [state (mf/use-state (get @storage key default))]
(let [id (use-id)
state (mf/use-state (get @storage key default))
stream (mf/with-memo []
(->> mbc/stream
(rx/filter #(= (:type %) key))
(rx/filter #(not= (:id %) id))
(rx/map deref)))]
(mf/with-effect [@state key]
(mbc/emit! id key @state)
(swap! storage assoc key @state))
(use-stream stream (partial reset! state))
state))

View file

@ -21,7 +21,6 @@
[app.util.object :as obj]
[cuerdas.core :as str]
[goog.events :as events]
[okulary.core :as l]
[rumext.alpha :as mf]))
;; --- Components
@ -178,7 +177,7 @@
(let [recent-colors (mf/deref refs/workspace-recent-colors)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/workspace-libraries)
selected (h/use-persistent-state ::selected :recent)
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
colors (mf/use-state [])
on-select (mf/use-fn #(reset! selected %))]

View file

@ -19,7 +19,7 @@
(mf/defc libraries
[{:keys [on-select-color on-add-library-color disable-gradient disable-opacity]}]
(let [selected (h/use-persistent-state ::selected :recent)
(let [selected (h/use-shared-state dc/colorpicker-selected-broadcast-key :recent)
current-colors (mf/use-state [])
shared-libs (mf/deref refs/workspace-libraries)