From 076cb0e35b690153c3ccd4d88646152c9b4329a9 Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Fri, 6 Sep 2024 16:42:06 +0200 Subject: [PATCH] :sparkles: Add schema validation to all DS components --- .../src/app/main/ui/ds/buttons/button.cljs | 13 +++++++++---- .../app/main/ui/ds/buttons/icon_button.cljs | 16 ++++++++++++---- .../src/app/main/ui/ds/controls/input.cljs | 12 ++++++++++-- .../src/app/main/ui/ds/controls/select.cljs | 19 +++++++++---------- .../main/ui/ds/foundations/assets/icon.cljs | 11 +++++++++-- .../ui/ds/foundations/typography/heading.cljs | 14 ++++++++------ .../ui/ds/foundations/typography/text.cljs | 14 +++++++++----- .../app/main/ui/ds/notifications/toast.cljs | 12 +++++++++--- .../ui/ds/notifications/toast.stories.jsx | 1 - .../src/app/main/ui/ds/product/loader.cljs | 12 ++++++++++-- frontend/src/app/main/ui/ds/tab_switcher.cljs | 10 ++++++---- 11 files changed, 91 insertions(+), 43 deletions(-) diff --git a/frontend/src/app/main/ui/ds/buttons/button.cljs b/frontend/src/app/main/ui/ds/buttons/button.cljs index 9dfb2c9b4..cfb30409d 100644 --- a/frontend/src/app/main/ui/ds/buttons/button.cljs +++ b/frontend/src/app/main/ui/ds/buttons/button.cljs @@ -12,13 +12,18 @@ [app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]] [rumext.v2 :as mf])) -(def button-variants (set '("primary" "secondary" "ghost" "destructive"))) +(def ^:private schema:button + [:map + [:class {:optional true} :string] + [:icon {:optional true} + [:and :string [:fn #(contains? icon-list %)]]] + [:variant {:optional true} + [:maybe [:enum "primary" "secondary" "ghost" "destructive"]]]]) (mf/defc button* - {::mf/props :obj} + {::mf/props :obj + ::mf/schema schema:button} [{:keys [variant icon children class] :rest props}] - (assert (or (nil? variant) (contains? button-variants variant) "expected valid variant")) - (assert (or (nil? icon) (contains? icon-list icon) "expected valid icon id")) (let [variant (or variant "primary") class (dm/str class " " (stl/css-case :button true :button-primary (= variant "primary") diff --git a/frontend/src/app/main/ui/ds/buttons/icon_button.cljs b/frontend/src/app/main/ui/ds/buttons/icon_button.cljs index 1a80f9b19..dadb285af 100644 --- a/frontend/src/app/main/ui/ds/buttons/icon_button.cljs +++ b/frontend/src/app/main/ui/ds/buttons/icon_button.cljs @@ -14,12 +14,20 @@ (def button-variants (set '("primary" "secondary" "ghost" "destructive"))) + +(def ^:private schema:icon-button + [:map + [:class {:optional true} :string] + [:icon {:optional true} + [:and :string [:fn #(contains? icon-list %)]]] + [:aria-label :string] + [:variant {:optional true} + [:maybe [:enum "primary" "secondary" "ghost" "destructive"]]]]) + (mf/defc icon-button* - {::mf/props :obj} + {::mf/props :obj + ::mf/schema schema:icon-button} [{:keys [class icon variant aria-label] :rest props}] - (assert (contains? icon-list icon) "expected valid icon id") - (assert (or (not variant) (contains? button-variants variant)) "expected valid variant") - (assert (some? aria-label) "aria-label must be provided") (let [variant (or variant "primary") class (dm/str class " " (stl/css-case :icon-button true :icon-button-primary (= variant "primary") diff --git a/frontend/src/app/main/ui/ds/controls/input.cljs b/frontend/src/app/main/ui/ds/controls/input.cljs index 1a4422b8d..9d0eaa765 100644 --- a/frontend/src/app/main/ui/ds/controls/input.cljs +++ b/frontend/src/app/main/ui/ds/controls/input.cljs @@ -13,10 +13,18 @@ [app.util.dom :as dom] [rumext.v2 :as mf])) +(def ^:private schema:input + [:map + [:class {:optional true} :string] + [:icon {:optional true} + [:and :string [:fn #(contains? icon-list %)]]] + [:type {:optional true} :string] + [:ref {:optional true} some?]]) + (mf/defc input* - {::mf/props :obj} + {::mf/props :obj + ::mf/schema schema:input} [{:keys [icon class type ref] :rest props}] - (assert (or (nil? icon) (contains? icon-list icon))) (let [ref (or ref (mf/use-ref)) type (or type "text") icon-class (stl/css-case :input true diff --git a/frontend/src/app/main/ui/ds/controls/select.cljs b/frontend/src/app/main/ui/ds/controls/select.cljs index 5389ed854..e50e6a45f 100644 --- a/frontend/src/app/main/ui/ds/controls/select.cljs +++ b/frontend/src/app/main/ui/ds/controls/select.cljs @@ -88,15 +88,6 @@ (contains? option :aria-label))) (contains? option :label)))]]) -(def ^:private schema:select - [:map - [:disabled {:optional true} :boolean] - [:class {:optional true} :string] - [:icon {:optional true} - [:and :string [:fn #(contains? icon-list %)]]] - [:default-selected {:optional true} :string] - [:options [:vector {:min 1} schema:select-option]]]) - (defn- get-option [options id] (or (array/find #(= id (obj/get % "id")) options) @@ -123,10 +114,18 @@ (reset! open* false) (reset! focused* nil)) +(def ^:private schema:select + [:map + [:options [:vector {:min 1} schema:select-option]] + [:class {:optional true} :string] + [:disabled {:optional true} :boolean] + [:default-selected {:optional true} :string] + [:on-change {:optional true} fn?]]) + (mf/defc select* {::mf/props :obj ::mf/schema schema:select} - [{:keys [disabled default-selected on-change options class] :rest props}] + [{:keys [options class disabled default-selected on-change] :rest props}] (let [open* (mf/use-state false) open (deref open*) on-click diff --git a/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs index ee80566f6..b2952e58e 100644 --- a/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs +++ b/frontend/src/app/main/ui/ds/foundations/assets/icon.cljs @@ -277,10 +277,17 @@ (def ^:private icon-size-m 16) (def ^:private icon-size-s 12) +(def ^:private schema:icon + [:map + [:class {:optional true} :string] + [:id [:and :string [:fn #(contains? icon-list %)]]] + [:size {:optional true} + [:enum "s" "m"]]]) + (mf/defc icon* - {::mf/props :obj} + {::mf/props :obj + ::mf/schema schema:icon} [{:keys [id size class] :rest props}] - (assert (contains? icon-list id) "invalid icon id") (let [class (dm/str (or class "") " " (stl/css :icon)) props (mf/spread-props props {:class class :width icon-size-m :height icon-size-m}) size-px (cond (= size "s") icon-size-s :else icon-size-m) diff --git a/frontend/src/app/main/ui/ds/foundations/typography/heading.cljs b/frontend/src/app/main/ui/ds/foundations/typography/heading.cljs index 374ae545f..515b529e6 100644 --- a/frontend/src/app/main/ui/ds/foundations/typography/heading.cljs +++ b/frontend/src/app/main/ui/ds/foundations/typography/heading.cljs @@ -19,14 +19,16 @@ (defn- valid-typography? [value] (contains? t/typography-list value)) +(def ^:private schema:heading + [:map + [:level {:optional true} [:and :int [:fn #(valid-level? %)]]] + [:class {:optional true} :string] + [:typography [:and :string [:fn #(valid-typography? (dm/str %))]]]]) + (mf/defc heading* - {::mf/props :obj} + {::mf/props :obj + ::mf/schema schema:heading} [{:keys [level typography class children] :rest props}] - (assert (or (valid-level? level) - (nil? level)) - (dm/str "Invalid level: " level ". Valid numbers are 1 to 6.")) - (assert (valid-typography? (dm/str typography)) - (dm/str typography " is an unknown typography")) (let [level (or level "1") tag (dm/str "h" level) diff --git a/frontend/src/app/main/ui/ds/foundations/typography/text.cljs b/frontend/src/app/main/ui/ds/foundations/typography/text.cljs index 6f9baa2dd..9ae781dc3 100644 --- a/frontend/src/app/main/ui/ds/foundations/typography/text.cljs +++ b/frontend/src/app/main/ui/ds/foundations/typography/text.cljs @@ -15,12 +15,16 @@ (defn- valid-typography? [value] (contains? t/typography-list value)) -(mf/defc text* - {::mf/props :obj} - [{:keys [as typography children class] :rest props}] +(def ^:private schema:text + [:map + [:as {:optional true} :string] + [:class {:optional true} :string] + [:typography [:and :string [:fn #(valid-typography? (dm/str %))]]]]) - (assert (valid-typography? (dm/str typography)) - (dm/str typography " is an unknown typography")) +(mf/defc text* + {::mf/props :obj + ::mf/schema schema:text} + [{:keys [as typography children class] :rest props}] (let [as (if (or (empty? as) (nil? as)) "p" as) class (dm/str (or class "") " " (stl/css-case :display-typography (= typography t/display) diff --git a/frontend/src/app/main/ui/ds/notifications/toast.cljs b/frontend/src/app/main/ui/ds/notifications/toast.cljs index 343ec6fc5..e38d25e28 100644 --- a/frontend/src/app/main/ui/ds/notifications/toast.cljs +++ b/frontend/src/app/main/ui/ds/notifications/toast.cljs @@ -20,11 +20,17 @@ "error" i/delete-text "success" i/status-tick}) +(def ^:private schema:toast + [:map + [:class {:optional true} :string] + [:level {:optional true} + [:enum "info" "warning" "error" "success"]] + [:on-close {:optional true} fn?]]) + (mf/defc toast* - {::mf/props :obj} + {::mf/props :obj + ::mf/schema schema:toast} [{:keys [class level children on-close] :rest props}] - (assert (or (nil? level) (contains? levels level)) "expected valid level or nil") - (assert (or (nil? on-close) (fn? on-close))) (let [class (dm/str (stl/css-case :toast true :toast-info (= level "info") :toast-warning (= level "warning") diff --git a/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx b/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx index 34e835b9a..91f702743 100644 --- a/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx +++ b/frontend/src/app/main/ui/ds/notifications/toast.stories.jsx @@ -8,7 +8,6 @@ import * as React from "react"; import Components from "@target/components"; const { Toast } = Components; -const { icons } = Components.meta; export default { title: "Notifications/Toast", diff --git a/frontend/src/app/main/ui/ds/product/loader.cljs b/frontend/src/app/main/ui/ds/product/loader.cljs index 4249e2e22..9df8fa704 100644 --- a/frontend/src/app/main/ui/ds/product/loader.cljs +++ b/frontend/src/app/main/ui/ds/product/loader.cljs @@ -23,7 +23,6 @@ :width width :height height :class class})] - [:> "svg" props [:title title] [:g @@ -33,8 +32,17 @@ :d "M134.482 157.147v25l518.57.008.002-25-518.572-.008z"}]]])) +(def ^:private schema:loader + [:map + [:class {:optional true} :string] + [:width {:optional true} :int] + [:height {:optional true} :int] + [:title {:optional true} :string] + [:overlay {:optional true} :boolean]]) + (mf/defc loader* - {::mf/props :obj} + {::mf/props :obj + ::mf/schema schema:loader} [{:keys [class width height title overlay children] :rest props}] (let [w (or width (when (some? height) (mth/ceil (* height (/ 100 27)))) 100) diff --git a/frontend/src/app/main/ui/ds/tab_switcher.cljs b/frontend/src/app/main/ui/ds/tab_switcher.cljs index 521ec239f..0e2106790 100644 --- a/frontend/src/app/main/ui/ds/tab_switcher.cljs +++ b/frontend/src/app/main/ui/ds/tab_switcher.cljs @@ -107,16 +107,18 @@ (def ^:private schema:tab-switcher [:map + [:tabs [:vector {:min 1} schema:tab]] [:class {:optional true} :string] - [:action-button-position {:optional true} - [:enum "start" "end"]] + [:on-change-tab {:optional true} fn?] [:default-selected {:optional true} :string] - [:tabs [:vector {:min 1} schema:tab]]]) + [:action-button {:optional true} some?] + [:action-button-position {:optional true} + [:enum "start" "end"]]]) (mf/defc tab-switcher* {::mf/props :obj ::mf/schema schema:tab-switcher} - [{:keys [class tabs on-change-tab default-selected action-button-position action-button] :rest props}] + [{:keys [tabs class on-change-tab default-selected action-button-position action-button] :rest props}] (let [selected* (mf/use-state #(get-selected-tab-id tabs default-selected)) selected (deref selected*)