diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index cdb907ded..a9bd0a4b1 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -177,12 +177,12 @@ [:div.buttons-stack (when (or (contains? cf/flags :login) (contains? cf/flags :login-with-password)) - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "auth.login-submit") :data-test "login-submit"}]) (when (contains? cf/flags :login-with-ldap) - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "auth.login-with-ldap-submit") :on-click on-submit-ldap}])]]])) diff --git a/frontend/src/app/main/ui/auth/recovery.cljs b/frontend/src/app/main/ui/auth/recovery.cljs index 397edc4d9..99ba7fc40 100644 --- a/frontend/src/app/main/ui/auth/recovery.cljs +++ b/frontend/src/app/main/ui/auth/recovery.cljs @@ -72,7 +72,7 @@ :name :password-2 :label (tr "auth.confirm-password")}]] - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "auth.recovery-submit")}]])) ;; --- Recovery Request Page diff --git a/frontend/src/app/main/ui/auth/recovery_request.cljs b/frontend/src/app/main/ui/auth/recovery_request.cljs index 37e92b226..d292a57e6 100644 --- a/frontend/src/app/main/ui/auth/recovery_request.cljs +++ b/frontend/src/app/main/ui/auth/recovery_request.cljs @@ -32,7 +32,7 @@ (mf/defc recovery-form [{:keys [on-success-callback] :as props}] - (let [form (fm/use-form :spec ::recovery-request-form + (let [form (fm/use-form :spec ::recovery-request-form :validators [handle-error-messages] :initial {}) submitted (mf/use-state false) @@ -82,7 +82,7 @@ :help-icon i/at :type "text"}]] - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "auth.recovery-request-submit") :data-test "recovery-resquest-submit"}]])) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index 01986eccb..43cf56e1f 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -124,7 +124,7 @@ :label (tr "auth.password") :type "password"}]] - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "auth.register-submit") :disabled @submitted? :data-test "register-form-submit"}]])) @@ -259,7 +259,7 @@ [:span ",\u00A0"] [:a {:href "https://penpot.app/privacy" :target "_blank"} (tr "auth.privacy-policy")]]]) - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "auth.register-submit") :disabled @submitted?}]])) diff --git a/frontend/src/app/main/ui/components/forms.cljs b/frontend/src/app/main/ui/components/forms.cljs index deb8f6a46..3356f736e 100644 --- a/frontend/src/app/main/ui/components/forms.cljs +++ b/frontend/src/app/main/ui/components/forms.cljs @@ -236,56 +236,98 @@ i/arrow-slide]]])) (mf/defc radio-buttons - [{:keys [name options form trim on-change-value] :as props}] - (let [form (or form (mf/use-ctx form-ctx)) - value (get-in @form [:data name] "") - on-change-value (or on-change-value (constantly nil)) - on-change (fn [event] - (let [value (-> event dom/get-target dom/get-value)] - (swap! form assoc-in [:touched name] true) - (fm/on-input-change form name value trim) - (on-change-value name value)))] - [:div.custom-radio - (for [item options] - (let [id (str/ffmt "%-%" name (:value item)) - image (:image item)] - [:div.input-radio {:key id :class (when image "with-image")} - [:input {:on-change on-change - :type "radio" - :id id - :name name - :value (:value item) - :checked (= value (:value item))}] - [:label {:for id - :style {:background-image (when image (str/ffmt "url(%)" image))} - :class (when image "with-image")} - (:label item)]]))])) + {::mf/wrap-props false} + [props] + (let [form (or (unchecked-get props "form") + (mf/use-ctx form-ctx)) + name (unchecked-get props "name") -(mf/defc submit-button - [{:keys [label form on-click disabled data-test] :as props}] - (let [form (or form (mf/use-ctx form-ctx))] - [:input.btn-primary.btn-large - {:name "submit" - :class (when (or (not (:valid @form)) (true? disabled)) "btn-disabled") - :disabled (or (not (:valid @form)) (true? disabled)) - :tab-index "0" - :on-click on-click - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-click))) - :value label - :data-test data-test - :type "submit"}])) + current-value (or (dm/get-in @form [:data name] "") + (unchecked-get props "value")) + on-change (unchecked-get props "on-change") + options (unchecked-get props "options") + trim? (unchecked-get props "trim") + encode-fn (d/nilv (unchecked-get props "encode-fn") identity) + decode-fn (d/nilv (unchecked-get props "decode-fn") identity) + + on-change' + (mf/use-fn + (mf/deps on-change form name) + (fn [event] + (let [value (-> event dom/get-target dom/get-value decode-fn)] + (when (some? form) + (swap! form assoc-in [:touched name] true) + (fm/on-input-change form name value trim?)) + + (when (fn? on-change) + (on-change name value)))))] + + [:div.custom-radio + (for [{:keys [image value label]} options] + (let [image? (some? image) + value' (encode-fn value) + key (str/ffmt "%-%" name value')] + [:div.input-radio {:key key :class (when image? "with-image")} + [:input {:on-change on-change' + :type "radio" + :id key + :name name + :value value' + :checked (= value current-value)}] + [:label {:for key + :style {:background-image (when image? (str/ffmt "url(%)" image))} + :class (when image? "with-image")} + label]]))])) + +(mf/defc submit-button* + {::mf/wrap-props false} + [props] + (let [form (or (unchecked-get props "form") + (mf/use-ctx form-ctx)) + + label (unchecked-get props "label") + on-click (unchecked-get props "onClick") + children (unchecked-get props "children") + + class (d/nilv (unchecked-get props "className") "btn-primary btn-large") + name (d/nilv (unchecked-get props "name") "submit") + + disabled? (or (and (some? form) (not (:valid @form))) + (true? (unchecked-get props "disabled"))) + + klass (dm/str class " " (if disabled? "btn-disabled" "")) + + on-key-down + (mf/use-fn + (mf/deps on-click) + (fn [event] + (when (and (kbd/enter? event) (fn? on-click)) + (on-click event)))) + + props (-> (obj/clone props) + (obj/unset! "children") + (obj/set! "disabled" disabled?) + (obj/set! "onKeyDown" on-key-down) + (obj/set! "name" name) + (obj/set! "label" mf/undefined) + (obj/set! "className" klass) + (obj/set! "type" "submit"))] + + [:> "button" props + (if (some? children) + children + [:span label])])) (mf/defc form - [{:keys [on-submit form children class] :as props}] - (let [on-submit (or on-submit (constantly nil))] + {::mf/wrap-props false} + [{:keys [on-submit form children class]}] + (let [on-submit' (mf/use-fn + (fn [event] + (dom/prevent-default event) + (when (fn? on-submit) + (on-submit form event))))] [:& (mf/provider form-ctx) {:value form} - [:form {:class class - :on-submit (fn [event] - (dom/prevent-default event) - (on-submit form event))} - children]])) + [:form {:class class :on-submit on-submit'} children]])) (defn- conj-dedup "A helper that adds item into a vector and removes possible diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs index 43f16aac7..6cc4f9244 100644 --- a/frontend/src/app/main/ui/dashboard/team.cljs +++ b/frontend/src/app/main/ui/dashboard/team.cljs @@ -185,9 +185,10 @@ :on-submit on-submit}]] [:div.action-buttons - [:& fm/submit-button {:label (tr "modals.invite-member-confirm.accept") - :disabled (and (boolean (some current-data-emails current-members-emails)) - (empty? (remove current-members-emails current-data-emails)))}]]]])) + [:> fm/submit-button* + {:label (tr "modals.invite-member-confirm.accept") + :disabled (and (boolean (some current-data-emails current-members-emails)) + (empty? (remove current-members-emails current-data-emails)))}]]]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; MEMBERS SECTION @@ -814,7 +815,7 @@ {:type "button" :value (tr "labels.cancel") :on-click #(modal/hide!)}] - [:& fm/submit-button + [:> fm/submit-button* {:label (if webhook (tr "modals.edit-webhook.submit-label") (tr "modals.create-webhook.submit-label"))}]]]]]])) diff --git a/frontend/src/app/main/ui/dashboard/team_form.cljs b/frontend/src/app/main/ui/dashboard/team_form.cljs index e09501b60..023cfac48 100644 --- a/frontend/src/app/main/ui/dashboard/team_form.cljs +++ b/frontend/src/app/main/ui/dashboard/team_form.cljs @@ -95,7 +95,7 @@ [:div.modal-footer [:div.action-buttons - [:& fm/submit-button + [:> fm/submit-button* {:label (if team (tr "labels.update-team") (tr "labels.create-team"))}]]]]]])) diff --git a/frontend/src/app/main/ui/onboarding/questions.cljs b/frontend/src/app/main/ui/onboarding/questions.cljs index d5cd52a95..ca5d1fb08 100644 --- a/frontend/src/app/main/ui/onboarding/questions.cljs +++ b/frontend/src/app/main/ui/onboarding/questions.cljs @@ -26,7 +26,7 @@ children [:div.buttons [:div.step-next - [:& fm/submit-button + [:> fm/submit-button* {:label (if (< step 4) (tr "questions.next") (tr "questions.start")) :class "step-next"}]] @@ -114,7 +114,7 @@ {:label (tr "questions.never-used-a-tool") :value "never-used-a-tool" :image "images/form/never-used.png"} {:label (tr "questions.other") :value "other"}] :name :experience-design-tool - :on-change-value on-design-tool-change}] + :on-change on-design-tool-change}] [:div.other [:label (tr "questions.other")] [:& fm/input {:name :experience-design-tool-other :label (tr "questions.other") :disabled (not= experience-design-tool "other")}]]])) @@ -152,7 +152,7 @@ {:label (tr "questions.student-teacher") :value "student-teacher"} {:label (tr "questions.other") :value "other"}] :name :role - :on-change-value on-role-change}] + :on-change on-role-change}] [:div.other [:label (tr "questions.other")] [:& fm/input {:name :role-other :label (tr "questions.other") :disabled (not= role "other")}]] diff --git a/frontend/src/app/main/ui/onboarding/team_choice.cljs b/frontend/src/app/main/ui/onboarding/team_choice.cljs index 2dd7ee3de..27d1e3225 100644 --- a/frontend/src/app/main/ui/onboarding/team_choice.cljs +++ b/frontend/src/app/main/ui/onboarding/team_choice.cljs @@ -87,7 +87,7 @@ :name :name :label (tr "onboarding.choice.team-up.create-team-placeholder")}] - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "labels.continue")}]] [:button.skip-action {:on-click on-skip} (tr "onboarding.choice.team-up.create-later")]] @@ -199,8 +199,9 @@ :name name :step 2}))} (tr "labels.back")] - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "onboarding.choice.team-up.invite-members-submit")}]] + [:div.skip-action {:on-click on-skip} [:div.action (tr "onboarding.choice.team-up.invite-members-skip")]]]] diff --git a/frontend/src/app/main/ui/settings/access_tokens.cljs b/frontend/src/app/main/ui/settings/access_tokens.cljs index 2444324ed..3e4947ce9 100644 --- a/frontend/src/app/main/ui/settings/access_tokens.cljs +++ b/frontend/src/app/main/ui/settings/access_tokens.cljs @@ -166,7 +166,7 @@ {:type "button" :value (tr "labels.cancel") :on-click #(modal/hide!)}] - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "modals.create-access-token.submit-label")}]])]]]]])) (mf/defc access-tokens-hero diff --git a/frontend/src/app/main/ui/settings/change_email.cljs b/frontend/src/app/main/ui/settings/change_email.cljs index 26521ed78..996d4668c 100644 --- a/frontend/src/app/main/ui/settings/change_email.cljs +++ b/frontend/src/app/main/ui/settings/change_email.cljs @@ -129,7 +129,7 @@ [:div.modal-footer [:div.action-buttons {:data-test "change-email-submit"} - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "modals.change-email.submit")}]]]]]])) diff --git a/frontend/src/app/main/ui/settings/feedback.cljs b/frontend/src/app/main/ui/settings/feedback.cljs index d510ef7c5..e46c4aac2 100644 --- a/frontend/src/app/main/ui/settings/feedback.cljs +++ b/frontend/src/app/main/ui/settings/feedback.cljs @@ -76,7 +76,7 @@ :name :content :rows 5}]] - [:& fm/submit-button + [:> fm/submit-button* {:label (if @loading (tr "labels.sending") (tr "labels.send")) :disabled @loading}] diff --git a/frontend/src/app/main/ui/settings/options.cljs b/frontend/src/app/main/ui/settings/options.cljs index 6356a9e20..64f52e006 100644 --- a/frontend/src/app/main/ui/settings/options.cljs +++ b/frontend/src/app/main/ui/settings/options.cljs @@ -35,6 +35,7 @@ (st/emit! (du/update-profile (with-meta data mdata))))) (mf/defc options-form + {::mf/wrap-props false} [] (let [profile (mf/deref refs/profile) initial (mf/with-memo [profile] @@ -66,7 +67,7 @@ :options [{:label "Penpot Dark (default)" :value "default"} {:label "Penpot Light" :value "light"}] :data-test "setting-theme"}]]) - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "dashboard.update-settings") :data-test "submit-lang-change"}]])) diff --git a/frontend/src/app/main/ui/settings/password.cljs b/frontend/src/app/main/ui/settings/password.cljs index 48f15b00b..f04262ffa 100644 --- a/frontend/src/app/main/ui/settings/password.cljs +++ b/frontend/src/app/main/ui/settings/password.cljs @@ -98,7 +98,7 @@ :name :password-2 :label (t locale "labels.confirm-password")}]] - [:& fm/submit-button + [:> fm/submit-button* {:label (t locale "dashboard.update-settings") :data-test "submit-password"}]])) diff --git a/frontend/src/app/main/ui/settings/profile.cljs b/frontend/src/app/main/ui/settings/profile.cljs index cbb302b70..dd5ab9eef 100644 --- a/frontend/src/app/main/ui/settings/profile.cljs +++ b/frontend/src/app/main/ui/settings/profile.cljs @@ -69,7 +69,7 @@ [:a {:on-click #(modal/show! :change-email {})} (tr "dashboard.change-email")]]]] - [:& fm/submit-button + [:> fm/submit-button* {:label (tr "dashboard.save-settings") :disabled (empty? (:touched @form))}]