mirror of
https://github.com/penpot/penpot.git
synced 2025-05-19 14:36:10 +02:00
✨ Add schema validation to all DS components
This commit is contained in:
parent
2a90ca6546
commit
076cb0e35b
11 changed files with 91 additions and 43 deletions
|
@ -12,13 +12,18 @@
|
||||||
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
||||||
[rumext.v2 :as mf]))
|
[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/defc button*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:button}
|
||||||
[{:keys [variant icon children class] :rest props}]
|
[{: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")
|
(let [variant (or variant "primary")
|
||||||
class (dm/str class " " (stl/css-case :button true
|
class (dm/str class " " (stl/css-case :button true
|
||||||
:button-primary (= variant "primary")
|
:button-primary (= variant "primary")
|
||||||
|
|
|
@ -14,12 +14,20 @@
|
||||||
|
|
||||||
(def button-variants (set '("primary" "secondary" "ghost" "destructive")))
|
(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/defc icon-button*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:icon-button}
|
||||||
[{:keys [class icon variant aria-label] :rest props}]
|
[{: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")
|
(let [variant (or variant "primary")
|
||||||
class (dm/str class " " (stl/css-case :icon-button true
|
class (dm/str class " " (stl/css-case :icon-button true
|
||||||
:icon-button-primary (= variant "primary")
|
:icon-button-primary (= variant "primary")
|
||||||
|
|
|
@ -13,10 +13,18 @@
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[rumext.v2 :as mf]))
|
[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/defc input*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:input}
|
||||||
[{:keys [icon class type ref] :rest props}]
|
[{:keys [icon class type ref] :rest props}]
|
||||||
(assert (or (nil? icon) (contains? icon-list icon)))
|
|
||||||
(let [ref (or ref (mf/use-ref))
|
(let [ref (or ref (mf/use-ref))
|
||||||
type (or type "text")
|
type (or type "text")
|
||||||
icon-class (stl/css-case :input true
|
icon-class (stl/css-case :input true
|
||||||
|
|
|
@ -88,15 +88,6 @@
|
||||||
(contains? option :aria-label)))
|
(contains? option :aria-label)))
|
||||||
(contains? option :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
|
(defn- get-option
|
||||||
[options id]
|
[options id]
|
||||||
(or (array/find #(= id (obj/get % "id")) options)
|
(or (array/find #(= id (obj/get % "id")) options)
|
||||||
|
@ -123,10 +114,18 @@
|
||||||
(reset! open* false)
|
(reset! open* false)
|
||||||
(reset! focused* nil))
|
(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/defc select*
|
||||||
{::mf/props :obj
|
{::mf/props :obj
|
||||||
::mf/schema schema:select}
|
::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)
|
(let [open* (mf/use-state false)
|
||||||
open (deref open*)
|
open (deref open*)
|
||||||
on-click
|
on-click
|
||||||
|
|
|
@ -277,10 +277,17 @@
|
||||||
(def ^:private icon-size-m 16)
|
(def ^:private icon-size-m 16)
|
||||||
(def ^:private icon-size-s 12)
|
(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/defc icon*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:icon}
|
||||||
[{:keys [id size class] :rest props}]
|
[{:keys [id size class] :rest props}]
|
||||||
(assert (contains? icon-list id) "invalid icon id")
|
|
||||||
(let [class (dm/str (or class "") " " (stl/css :icon))
|
(let [class (dm/str (or class "") " " (stl/css :icon))
|
||||||
props (mf/spread-props props {:class class :width icon-size-m :height icon-size-m})
|
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)
|
size-px (cond (= size "s") icon-size-s :else icon-size-m)
|
||||||
|
|
|
@ -19,14 +19,16 @@
|
||||||
(defn- valid-typography? [value]
|
(defn- valid-typography? [value]
|
||||||
(contains? t/typography-list 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/defc heading*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:heading}
|
||||||
[{:keys [level typography class children] :rest props}]
|
[{: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")
|
(let [level (or level "1")
|
||||||
tag (dm/str "h" level)
|
tag (dm/str "h" level)
|
||||||
|
|
|
@ -15,12 +15,16 @@
|
||||||
(defn- valid-typography? [value]
|
(defn- valid-typography? [value]
|
||||||
(contains? t/typography-list value))
|
(contains? t/typography-list value))
|
||||||
|
|
||||||
(mf/defc text*
|
(def ^:private schema:text
|
||||||
{::mf/props :obj}
|
[:map
|
||||||
[{:keys [as typography children class] :rest props}]
|
[:as {:optional true} :string]
|
||||||
|
[:class {:optional true} :string]
|
||||||
|
[:typography [:and :string [:fn #(valid-typography? (dm/str %))]]]])
|
||||||
|
|
||||||
(assert (valid-typography? (dm/str typography))
|
(mf/defc text*
|
||||||
(dm/str typography " is an unknown typography"))
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:text}
|
||||||
|
[{:keys [as typography children class] :rest props}]
|
||||||
|
|
||||||
(let [as (if (or (empty? as) (nil? as)) "p" as)
|
(let [as (if (or (empty? as) (nil? as)) "p" as)
|
||||||
class (dm/str (or class "") " " (stl/css-case :display-typography (= typography t/display)
|
class (dm/str (or class "") " " (stl/css-case :display-typography (= typography t/display)
|
||||||
|
|
|
@ -20,11 +20,17 @@
|
||||||
"error" i/delete-text
|
"error" i/delete-text
|
||||||
"success" i/status-tick})
|
"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/defc toast*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:toast}
|
||||||
[{:keys [class level children on-close] :rest props}]
|
[{: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
|
(let [class (dm/str (stl/css-case :toast true
|
||||||
:toast-info (= level "info")
|
:toast-info (= level "info")
|
||||||
:toast-warning (= level "warning")
|
:toast-warning (= level "warning")
|
||||||
|
|
|
@ -8,7 +8,6 @@ import * as React from "react";
|
||||||
import Components from "@target/components";
|
import Components from "@target/components";
|
||||||
|
|
||||||
const { Toast } = Components;
|
const { Toast } = Components;
|
||||||
const { icons } = Components.meta;
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: "Notifications/Toast",
|
title: "Notifications/Toast",
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:class class})]
|
:class class})]
|
||||||
|
|
||||||
[:> "svg" props
|
[:> "svg" props
|
||||||
[:title title]
|
[:title title]
|
||||||
[:g
|
[:g
|
||||||
|
@ -33,8 +32,17 @@
|
||||||
:d
|
:d
|
||||||
"M134.482 157.147v25l518.57.008.002-25-518.572-.008z"}]]]))
|
"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/defc loader*
|
||||||
{::mf/props :obj}
|
{::mf/props :obj
|
||||||
|
::mf/schema schema:loader}
|
||||||
[{:keys [class width height title overlay children] :rest props}]
|
[{:keys [class width height title overlay children] :rest props}]
|
||||||
|
|
||||||
(let [w (or width (when (some? height) (mth/ceil (* height (/ 100 27)))) 100)
|
(let [w (or width (when (some? height) (mth/ceil (* height (/ 100 27)))) 100)
|
||||||
|
|
|
@ -107,16 +107,18 @@
|
||||||
|
|
||||||
(def ^:private schema:tab-switcher
|
(def ^:private schema:tab-switcher
|
||||||
[:map
|
[:map
|
||||||
|
[:tabs [:vector {:min 1} schema:tab]]
|
||||||
[:class {:optional true} :string]
|
[:class {:optional true} :string]
|
||||||
[:action-button-position {:optional true}
|
[:on-change-tab {:optional true} fn?]
|
||||||
[:enum "start" "end"]]
|
|
||||||
[:default-selected {:optional true} :string]
|
[: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/defc tab-switcher*
|
||||||
{::mf/props :obj
|
{::mf/props :obj
|
||||||
::mf/schema schema:tab-switcher}
|
::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))
|
(let [selected* (mf/use-state #(get-selected-tab-id tabs default-selected))
|
||||||
selected (deref selected*)
|
selected (deref selected*)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue