diff --git a/frontend/src/app/main/ui/workspace/tokens/modal.cljs b/frontend/src/app/main/ui/workspace/tokens/modal.cljs index 755aa7a54..5d4312fd7 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modal.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/modal.cljs @@ -7,14 +7,17 @@ (ns app.main.ui.workspace.tokens.modal (:require-macros [app.main.style :as stl]) (:require + ["lodash.debounce" :as debounce] [app.common.data :as d] [app.main.data.modal :as modal] [app.main.data.tokens :as dt] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.workspace.tokens.common :as tokens.common] + [app.main.ui.workspace.tokens.style-dictionary :as sd] [app.util.dom :as dom] [okulary.core :as l] + [promesa.core :as p] [rumext.v2 :as mf])) (defn calculate-position @@ -41,12 +44,47 @@ [key (:value field)]) fields) (into {}))) +(defn fields-to-token + "Converts field to token value that will be stored and processed. + Handles a simple token token type for now." + [token-type fields] + (case token-type + (first fields))) + +;; https://dev.to/haseeb1009/the-useevent-hook-1c8l +(defn use-event-callback + [f] + (let [ref (mf/use-ref)] + (mf/use-layout-effect + (fn [] + (reset! ref f) + js/undefined)) + (mf/use-callback (fn [& args] (some-> @ref (apply args))) []))) + +(defn use-promise-debounce [fn+ on-success on-err] + (let [debounce-promise (mf/use-ref nil) + callback-fn (fn [] + (let [id (random-uuid)] + (mf/set-ref-val! debounce-promise id) + (-> (fn+) + (p/then (fn [result] + (js/console.log "@debounce-promise id" @debounce-promise id) + (when (= @debounce-promise id) + (js/console.log "update" result) + (on-success result)))) + (p/catch on-err)))) + debounced-fn (debounce callback-fn)] + debounced-fn)) + (mf/defc tokens-properties-form {::mf/wrap-props false} - [{:keys [token-type x y position fields token]}] - (let [vport (mf/deref viewport) + [{:keys [token-type x y position fields token] :as args}] + (let [tokens (sd/use-resolved-workspace-tokens {:debug? true}) + vport (mf/deref viewport) style (calculate-position vport position x y) + resolved-value (mf/use-state (get-in tokens [(:id token) :value])) + name (mf/use-var (or (:name token) "")) on-update-name #(reset! name (dom/get-target-val %)) @@ -60,8 +98,15 @@ fields) state (mf/use-state initial-fields) + debounced-update (use-promise-debounce sd/resolve-tokens+ + (fn [tokens] + (let [value (get-in tokens [(:id token) :value])] + (reset! resolved-value value))) + #(reset! resolved-value nil)) + on-update-state-field (fn [idx e] (let [value (dom/get-target-val e)] + (debounced-update) (swap! state assoc-in [idx :value] value))) on-submit (fn [e] @@ -76,7 +121,6 @@ (:id token) (assoc :id (:id token)))] (st/emit! (dt/add-token token)) (modal/hide!)))] - [:form {:class (stl/css :shadow) :style (clj->js style) @@ -86,13 +130,17 @@ :input-props {:default-value @name :auto-focus true :on-change on-update-name}}] - (for [[idx {:keys [type label]}] (d/enumerate @state)] + (for [[idx {:keys [label type]}] (d/enumerate @state)] [:* {:key (str "form-field-" idx)} (case type :box-shadow [:p "TODO BOX SHADOW"] - [:& tokens.common/labeled-input {:label label + [:& tokens.common/labeled-input {:label "Value" :input-props {:default-value @token-value :on-change #(on-update-state-field idx %)}}])]) + (when (and @resolved-value + (not= @resolved-value (:value (first @state)))) + [:div {:class (stl/css :resolved-value)} + [:p @resolved-value]]) [:& tokens.common/labeled-input {:label "Description" :input-props {:default-value @description :on-change #(on-update-description %)}}] diff --git a/frontend/src/app/main/ui/workspace/tokens/modal.scss b/frontend/src/app/main/ui/workspace/tokens/modal.scss index d40a861dd..c191f0bdf 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modal.scss +++ b/frontend/src/app/main/ui/workspace/tokens/modal.scss @@ -19,6 +19,20 @@ gap: $s-8; } +.resolved-value { + @include bodySmallTypography; + padding: $s-4 $s-6; + font-weight: medium; + + color: var(--color-foreground-primary); + border: 1px solid color-mix(in hsl, var(--color-foreground-secondary) 30%, transparent); + + p { + font-size: $fs-12; + margin: 0; + } +} + .shadow { @extend .modal-container-base; @include menuShadow;