0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-06 14:50:20 -05:00

Validation in modal

This commit is contained in:
Florian Schroedl 2024-06-19 11:09:01 +02:00
parent 168a5d57d4
commit 0a73c3aa95
2 changed files with 67 additions and 5 deletions

View file

@ -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 %)}}]

View file

@ -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;