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:
parent
756b6d4fbd
commit
9950c5dc0f
5 changed files with 81 additions and 23 deletions
52
frontend/src/app/main/broadcast.cljs
Normal file
52
frontend/src/app/main/broadcast.cljs
Normal 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))))
|
|
@ -9,6 +9,7 @@
|
||||||
[app.common.colors :as colors]
|
[app.common.colors :as colors]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
|
[app.main.broadcast :as mbc]
|
||||||
[app.main.data.modal :as md]
|
[app.main.data.modal :as md]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.changes :as dch]
|
||||||
[app.main.data.workspace.layout :as layout]
|
[app.main.data.workspace.layout :as layout]
|
||||||
|
@ -19,30 +20,18 @@
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
(defn change-palette-selected
|
;; A set of keys that are used for shared state identifiers
|
||||||
"Change the library used by the general palette tool"
|
(def ^:const colorpicker-selected-broadcast-key ::colorpicker-selected)
|
||||||
[selected]
|
(def ^:const colorpalette-selected-broadcast-key ::colorpalette-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)))))
|
|
||||||
|
|
||||||
(defn show-palette
|
(defn show-palette
|
||||||
"Show the palette tool and change the library it uses"
|
"Show the palette tool and change the library it uses"
|
||||||
[selected]
|
[selected]
|
||||||
(ptk/reify ::show-palette
|
(ptk/reify ::show-palette
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(assoc-in state [:workspace-global :selected-palette] selected))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(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
|
ptk/EffectEvent
|
||||||
(effect [_ state _]
|
(effect [_ state _]
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
(ns app.main.ui.hooks
|
(ns app.main.ui.hooks
|
||||||
"A collection of general purpose react hooks."
|
"A collection of general purpose react hooks."
|
||||||
(:require
|
(:require
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.pages :as cp]
|
[app.common.pages :as cp]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.broadcast :as mbc]
|
||||||
[app.main.data.shortcuts :as dsc]
|
[app.main.data.shortcuts :as dsc]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -289,9 +290,26 @@
|
||||||
(update-fn value))
|
(update-fn value))
|
||||||
state))
|
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]
|
[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]
|
(mf/with-effect [@state key]
|
||||||
|
(mbc/emit! id key @state)
|
||||||
(swap! storage assoc key @state))
|
(swap! storage assoc key @state))
|
||||||
|
|
||||||
|
(use-stream stream (partial reset! state))
|
||||||
|
|
||||||
state))
|
state))
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[goog.events :as events]
|
[goog.events :as events]
|
||||||
[okulary.core :as l]
|
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
;; --- Components
|
;; --- Components
|
||||||
|
@ -178,7 +177,7 @@
|
||||||
(let [recent-colors (mf/deref refs/workspace-recent-colors)
|
(let [recent-colors (mf/deref refs/workspace-recent-colors)
|
||||||
file-colors (mf/deref refs/workspace-file-colors)
|
file-colors (mf/deref refs/workspace-file-colors)
|
||||||
shared-libs (mf/deref refs/workspace-libraries)
|
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 [])
|
colors (mf/use-state [])
|
||||||
on-select (mf/use-fn #(reset! selected %))]
|
on-select (mf/use-fn #(reset! selected %))]
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
(mf/defc libraries
|
(mf/defc libraries
|
||||||
[{:keys [on-select-color on-add-library-color disable-gradient disable-opacity]}]
|
[{: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 [])
|
current-colors (mf/use-state [])
|
||||||
|
|
||||||
shared-libs (mf/deref refs/workspace-libraries)
|
shared-libs (mf/deref refs/workspace-libraries)
|
||||||
|
|
Loading…
Add table
Reference in a new issue