From 35ee732701d40073901339a0e698a33c7db261f9 Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Fri, 21 Jun 2024 14:59:08 +0200 Subject: [PATCH] Debounced update of resolved value --- .../app/main/ui/workspace/tokens/form.cljs | 45 ++++++++++--------- .../ui/workspace/tokens/style_dictionary.cljs | 35 +++++++++++++++ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index dcda447f4..58f7c722c 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -15,6 +15,8 @@ [malli.error :as me] [rumext.v2 :as mf])) +;; Schemas --------------------------------------------------------------------- + (defn token-name-schema "Generate a dynamic schema validation to check if a token name already exists. `existing-token-names` should be a set of strings." @@ -35,9 +37,14 @@ (me/humanize)) nil) +;; Helpers --------------------------------------------------------------------- + (defn finalize-name [name] (str/trim name)) +(defn finalize-value [name] + (str/trim name)) + (mf/defc form {::mf/wrap-props false} [{:keys [token] :as _args}] @@ -71,22 +78,18 @@ (reset! name-errors errors))) disabled? (or @name-errors - (empty? (finalize-name (:name state))))] - - ;; on-update-name (fn [e] - ;; (let [{:keys [errors] :as state} (mf/deref state*) - ;; value (-> (dom/get-target-val e) - ;; (str/trim))] - ;; (cond-> @state* - ;; ;; Remove existing name errors - ;; :always (update :errors set/difference #{:empty}) - ;; (str/empty?) (conj)) - ;; (swap! state* assoc :name (dom/get-target-val e)))) - ;; on-update-description #(swap! state* assoc :description (dom/get-target-val %)) - ;; on-update-field (fn [idx e] - ;; (let [value (dom/get-target-val e)] - ;; (swap! state* assoc-in [idx :value] value))) + (empty? (finalize-name (:name state)))) + ;; Value + value (mf/use-var (or (:value token) "")) + resolved-value (mf/use-state nil) + set-resolve-value (mf/use-callback + (fn [token] + (js/console.log "token" (:resolved-value token)) + (when (:resolved-value token) + (reset! resolved-value (:resolved-value token))))) + value-errors (mf/use-state nil) + on-update-value (sd/use-debonced-resolve-callback tokens set-resolve-value)] ;; on-submit (fn [e] ;; (dom/prevent-default e) @@ -106,19 +109,17 @@ [:div [:& tokens.common/labeled-input {:label "Name" :error? @name-errors - :input-props {:default-value (:name state) + :input-props {:default-value @name :auto-focus true :on-change on-update-name}}] (when @name-errors [:p {:class (stl/css :error)} (me/humanize @name-errors)])] [:& tokens.common/labeled-input {:label "Value" - :input-props {:default-value (:value state) - #_#_:on-change #(on-update-field idx %)}}] - ;; (when (and @resolved-value - ;; (not= @resolved-value (:value (first @state*)))) - ;; [:div {:class (stl/css :resolved-value)} - ;; [:p @resolved-value]]) + :input-props {:default-value @value + :on-change on-update-value}}] + [:div {:class (stl/css :resolved-value)} + [:p @resolved-value]] [:& tokens.common/labeled-input {:label "Description" :input-props {:default-value (:description state) #_#_:on-change #(on-update-description %)}}] diff --git a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs index f1e1c7a7d..c87c9dcc0 100644 --- a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs @@ -4,6 +4,7 @@ ["style-dictionary$default" :as sd] [app.common.data :as d] [app.main.refs :as refs] + [app.util.dom :as dom] [cuerdas.core :as str] [promesa.core :as p] [rumext.v2 :as mf] @@ -77,7 +78,9 @@ (defn resolve-tokens+ [tokens & {:keys [debug?] :as config}] (p/let [sd-tokens (-> (tokens-name-map tokens) + (doto js/console.log) (resolve-sd-tokens+ config))] + (js/console.log "sd-tokens" sd-tokens) (let [resolved-tokens (reduce (fn [acc ^js cur] (let [value (.-value cur) @@ -101,6 +104,38 @@ ;; Hooks ----------------------------------------------------------------------- +(defn use-debonced-resolve-callback + [tokens on-success & {:keys [cached timeout] + :or {cached {} + timeout 500}}] + (let [id-ref (mf/use-ref nil) + cache (mf/use-ref cached) + debounced-resolver-callback + (mf/use-callback + (mf/deps on-success tokens) + (fn [event] + (let [input (dom/get-target-val event) + id (js/Symbol)] + (mf/set-ref-val! id-ref id) + (js/setTimeout + (fn [] + (when (= (mf/ref-val id-ref) id) + (if-let [cached (-> (mf/ref-val cache) + (get tokens))] + (on-success cached) + (let [token-id (random-uuid) + new-tokens (assoc tokens token-id {:id token-id + :value input + :name "TEMP"})] + (-> (resolve-tokens+ new-tokens) + (p/catch js/console.error) + (p/then (fn [resolved-tokens] + (mf/set-ref-val! cache (assoc (mf/ref-val cache) tokens resolved-tokens)) + (when (= (mf/ref-val id-ref) id) + (on-success (get resolved-tokens token-id)))))))))) + timeout))))] + debounced-resolver-callback)) + (defonce !tokens-cache (atom nil)) (defn use-resolved-tokens