mirror of
https://github.com/penpot/penpot.git
synced 2025-03-13 16:21:57 -05: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]]
|
||||
[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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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*)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue