0
Fork 0
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:
Eva Marco 2024-09-06 16:42:06 +02:00
parent 2a90ca6546
commit 076cb0e35b
11 changed files with 91 additions and 43 deletions

View file

@ -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")

View file

@ -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")

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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")

View file

@ -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",

View file

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

View file

@ -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*)