0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-21 06:02:32 -05:00

Move callback function to component

This commit is contained in:
Florian Schroedl 2024-06-24 15:24:22 +02:00
parent 28f25da9e8
commit c98162d0bf
3 changed files with 55 additions and 66 deletions

View file

@ -14,6 +14,7 @@
[cuerdas.core :as str]
[malli.core :as m]
[malli.error :as me]
[promesa.core :as p]
[rumext.v2 :as mf]))
;; Schemas ---------------------------------------------------------------------
@ -33,11 +34,6 @@
[:string {:min 1 :max 255}]
non-existing-token-schema])))
(comment
(-> (m/explain (token-name-schema #{"foo"}) nil)
(me/humanize))
nil)
;; Helpers ---------------------------------------------------------------------
(defn finalize-name [name]
@ -46,6 +42,57 @@
(defn finalize-value [name]
(str/trim name))
;; Component -------------------------------------------------------------------
(defn use-debonced-resolve-callback
[name-ref token tokens callback & {:keys [cached timeout]
:or {cached {}
timeout 160}}]
(let [timeout-id-ref (mf/use-ref nil)
cache (mf/use-ref cached)
debounced-resolver-callback
(mf/use-callback
(mf/deps token callback tokens)
(fn [event]
(let [input (dom/get-target-val event)
timeout-id (js/Symbol)
;; Dont execute callback when the timout-id-ref is outdated because this function got called again
timeout-outdated-cb? #(not= (mf/ref-val timeout-id-ref) timeout-id)]
(mf/set-ref-val! timeout-id-ref timeout-id)
(js/setTimeout
(fn []
(when (not (timeout-outdated-cb?))
(if-let [cached (get (mf/ref-val cache) tokens)]
(callback cached)
(let [token-references (sd/find-token-references input)
;; When creating a new token we dont have a token name yet,
;; so we use a temporary token name that hopefully doesn't clash with any of the users token names.
token-name (if (empty? @name-ref) "__TOKEN_STUDIO_SYSTEM.TEMP" @name-ref)
direct-self-reference? (get token-references token-name)
empty-input? (empty? (str/trim input))]
(cond
empty-input? (callback nil)
direct-self-reference? (callback :error/token-direct-self-reference)
:else
(let [token-id (or (:id token) (random-uuid))
new-tokens (update tokens token-id merge {:id token-id
:value input
:name token-name})]
(-> (sd/resolve-tokens+ new-tokens)
(p/finally
(fn [resolved-tokens _err]
(when-not (timeout-outdated-cb?)
(let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens token-id)]
(cond
resolved-value (do
(mf/set-ref-val! cache (assoc (mf/ref-val cache) input resolved-tokens))
(callback resolved-token))
(= #{:style-dictionary/missing-reference} errors) (callback :error/token-missing-reference)
:else (callback :error/unknown-error)))))))))))))
timeout))))]
debounced-resolver-callback))
(mf/defc form
{::mf/wrap-props false}
[{:keys [token] :as _args}]
@ -63,7 +110,6 @@
:description ""}
token))
state @state*
_ (js/console.log "render")
form-touched (mf/use-state nil)
update-form-touched (mf/use-callback
@ -90,11 +136,11 @@
set-resolve-value (mf/use-callback
(fn [token-or-err]
(let [value (cond
(= token-or-err :error/token-self-reference) :error/token-self-reference
(= token-or-err :error/token-direct-self-reference) :error/token-self-reference
(= token-or-err :error/token-missing-reference) :error/token-missing-reference
(:resolved-value token-or-err) (:resolved-value token-or-err))]
(reset! token-resolve-result value))))
on-update-value (sd/use-debonced-resolve-callback name token tokens set-resolve-value)
on-update-value (use-debonced-resolve-callback name token tokens set-resolve-value)
value-error? (when (keyword? @token-resolve-result)
(= (namespace @token-resolve-result) "error"))
@ -136,6 +182,7 @@
(case @token-resolve-result
:error/token-self-reference "Token has self reference"
:error/token-missing-reference "Token has missing reference"
:error/unknown-error ""
nil "Enter token value"
[:p @token-resolve-result])]
[:& tokens.common/labeled-input {:label "Description"

View file

@ -30,10 +30,6 @@
(map second)
(into #{})))
(defn token-self-reference? [token-name value-string]
(let [refs (find-token-references value-string)]
(get refs token-name)))
(defn tokens->style-dictionary+
"Resolves references and math expressions using StyleDictionary.
Returns a promise with the resolved dictionary."
@ -115,55 +111,6 @@
;; Hooks -----------------------------------------------------------------------
(def new-token-temp-name
"TOKEN_STUDIO_SYSTEM.TEMP")
(defn use-debonced-resolve-callback
[name-ref token tokens callback & {:keys [cached timeout]
:or {cached {}
timeout 160}}]
(let [timeout-id-ref (mf/use-ref nil)
cache (mf/use-ref cached)
debounced-resolver-callback
(mf/use-callback
(mf/deps token callback tokens)
(fn [event]
(let [input (dom/get-target-val event)
timeout-id (js/Symbol)]
(mf/set-ref-val! timeout-id-ref timeout-id)
(js/setTimeout
(fn []
(when (= (mf/ref-val timeout-id-ref) timeout-id)
(let [cached (-> (mf/ref-val cache)
(get tokens))
token-name (if (empty? @name-ref) new-token-temp-name @name-ref)]
(cond
cached (callback cached)
(token-self-reference? token-name input) (callback :error/token-self-reference)
:else (let [token-id (or (:id token) (random-uuid))
new-tokens (update tokens token-id merge {:id token-id
:value input
:name token-name})]
(-> (resolve-tokens+ new-tokens)
(p/finally
(fn [resolved-tokens _err]
(js/console.log "input" input (empty? (str/trim input)))
(cond
;; Ignore outdated callbacks because the user input changed since it tried to resolve
(not= (mf/ref-val timeout-id-ref) timeout-id) nil
(empty? (str/trim input)) (callback nil)
:else (let [resolved-token (get resolved-tokens token-id)]
(js/console.log "resolved-token" resolved-token)
(if (:resolved-value resolved-token)
(do
(mf/set-ref-val! cache (assoc (mf/ref-val cache) input resolved-tokens))
(callback resolved-token))
(callback :error/token-missing-reference))))))))))))
timeout))))]
debounced-resolver-callback))
(defonce !tokens-cache (atom nil))
(defn use-resolved-tokens

View file

@ -18,8 +18,3 @@
(t/is (nil? (wtsd/find-token-references "1 + 2")))
;; Edge-case: Ignore unmatched closing parens
(t/is (= #{"foo" "bar"} (wtsd/find-token-references "{foo}} + {bar}"))))
(t/deftest test-token-self-reference?
(t/is (some? (wtsd/token-self-reference? "some.value" "{md} + {some.value}")))
(t/is (nil? (wtsd/token-self-reference? "some.value" "some.value")))
(t/is (nil? (wtsd/token-self-reference? "sm" "{md} + {lg}"))))