♻️ Redesign form input tokens (#6294)

* ♻️ Redesign form input tokens

* ♻️ Redesign form input tokens

---------

Co-authored-by: Xavier Julian <xaviju@proton.me>
This commit is contained in:
Xaviju 2025-05-05 09:05:14 +02:00 committed by GitHub
parent f8602810eb
commit 486f036a11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 470 additions and 190 deletions

View file

@ -18,7 +18,8 @@
[app.main.ui.ds.foundations.typography :refer [typography-list]]
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
[app.main.ui.ds.foundations.typography.text :refer [text*]]
[app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon* token-status-list]]
[app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon*
token-status-list]]
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
[app.main.ui.ds.notifications.actionable :refer [actionable*]]
[app.main.ui.ds.notifications.context-notification :refer [context-notification*]]

View file

@ -5,50 +5,62 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.ds.controls.input
(:require-macros
[app.common.data.macros :as dm]
[app.main.style :as stl])
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.main.constants :refer [max-input-length]]
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
[app.util.dom :as dom]
[app.main.ui.ds.controls.utilities.hint-message :refer [hint-message*]]
[app.main.ui.ds.controls.utilities.input-field :refer [input-field*]]
[app.main.ui.ds.controls.utilities.label :refer [label*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon-list]]
[cuerdas.core :as str]
[rumext.v2 :as mf]))
(def ^:private schema:input
[:map
[:id {:optional true} :string]
[:label {:optional true} :string]
[:class {:optional true} :string]
[:is-optional {:optional true} :boolean]
[:placeholder {:optional true} :string]
[:icon {:optional true}
[:and :string [:fn #(contains? icon-list %)]]]
[:type {:optional true} :string]
[:max-length {:optional true} :int]
[:variant {:optional true} :string]])
[:variant {:optional true} [:maybe [:enum "seamless" "dense" "comfortable"]]]
[:hint-message {:optional true} [:maybe :string]]
[:hint-type {:optional true} [:maybe [:enum "hint" "error" "warning"]]]])
(mf/defc input*
{::mf/props :obj
::mf/forward-ref true
::mf/schema schema:input}
[{:keys [icon class type max-length variant] :rest props} ref]
(let [ref (or ref (mf/use-ref))
type (d/nilv type "text")
props (mf/spread-props props
{:class (stl/css-case
:input true
:input-with-icon (some? icon))
:ref ref
:maxlength (d/nilv max-length (str max-input-length))
:type type})
[{:keys [id class label is-optional type max-length variant hint-message hint-type children] :rest props} ref]
(let [id (or id (mf/use-id))
variant (d/nilv variant "dense")
is-optional (d/nilv is-optional false)
type (d/nilv type "text")
max-length (d/nilv max-length max-input-length)
has-hint (and (some? hint-message) (not (str/blank? hint-message)))
has-label (not (str/blank? label))
ref (or ref (mf/use-ref))
props (mf/spread-props props {:ref ref
:type type
:id id
:hint-type hint-type
:max-length max-length
:has-hint has-hint
:variant variant})]
[:div {:class (dm/str class " " (stl/css-case :input-wrapper true
:variant-dense (= variant "dense")
:variant-comfortable (= variant "comfortable")
:has-hint has-hint))}
(when has-label
[:> label* {:for id :is-optional is-optional} label])
[:> input-field* props children]
(when has-hint
[:> hint-message* {:id id
:message hint-message
:type hint-type}])]))
on-icon-click
(mf/use-fn
(mf/deps ref)
(fn [_event]
(let [input-node (mf/ref-val ref)]
(dom/select-node input-node)
(dom/focus! input-node))))]
[:> :span {:class (dm/str class " " (stl/css-case :container true
:input-seamless (= variant "seamless")))}
(when (some? icon)
[:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}])
[:> :input props]]))

View file

@ -5,13 +5,10 @@ import * as InputStories from "./input.stories";
# Input
The `input*` component is a wrapper to the HTML `<input>` element with custom styling
and additional elements that adds context and, in some cases, adds extra
functionality.
The `input*` component is a wrapper composed of `label*`, `input-field*`, and `hint-message*` components, functioning as a form element that adapts its UI based on configuration, making it suitable for different areas of the interface.
<Canvas of={InputStories.Default} />
## Technical notes
### Icons
@ -29,8 +26,6 @@ These are available in the `app.main.ds.foundations.assets.icon` namespace.
[:> input* {:icon i/effects}]
```
<Canvas of={InputStories.WithIcon} />
## Usage guidelines (design)
### Where to use

View file

@ -4,98 +4,11 @@
//
// Copyright (c) KALEIDOS INC
@use "../_borders.scss" as *;
@use "../_sizes.scss" as *;
@use "../typography.scss" as *;
@use "../spacing.scss" as *;
.container {
--input-bg-color: var(--color-background-tertiary);
--input-fg-color: var(--color-foreground-primary);
--input-icon-color: var(--color-foreground-secondary);
--input-outline-color: none;
display: inline-flex;
column-gap: var(--sp-xs);
align-items: center;
position: relative;
.input-wrapper {
display: flex;
flex-direction: column;
gap: var(--sp-xs);
inline-size: 100%;
background: var(--input-bg-color);
border-radius: $br-8;
padding: 0 var(--sp-s);
outline-offset: #{$b-1};
outline: $b-1 solid var(--input-outline-color);
&:hover {
--input-bg-color: var(--color-background-quaternary);
}
&:has(*:focus-visible) {
--input-bg-color: var(--color-background-primary);
--input-outline-color: var(--color-accent-primary);
}
&:has(*:disabled) {
--input-bg-color: var(--color-background-primary);
--input-outline-color: var(--color-background-quaternary);
}
}
.input-seamless {
--input-bg-color: none;
--input-outline-color: none;
--input-height: auto;
--input-margin: 0;
padding: 0;
border: none;
&:hover {
--input-bg-color: none;
--input-outline-color: none;
}
&:has(*:focus-visible) {
--input-bg-color: none;
--input-outline-color: none;
}
}
.input {
margin: var(--input-margin, unset); // remove settings from global css
padding: 0;
appearance: none;
height: var(--input-height, #{$sz-32});
border: none;
background: none;
inline-size: 100%;
@include use-typography("body-small");
color: var(--input-fg-color);
&:focus-visible {
outline: none;
}
&::selection {
background: var(--color-accent-select);
}
&::placeholder {
--input-fg-color: var(--color-foreground-secondary);
}
&:is(:autofill, :autofill:hover, :autofill:focus, :autofill:active) {
-webkit-text-fill-color: var(--input-fg-color);
-webkit-background-clip: text;
caret-color: var(--input-bg-color);
}
}
.input-with-icon {
margin-inline-start: var(--sp-xxs);
}
.icon {
color: var(--color-foreground-secondary);
}

View file

@ -14,34 +14,74 @@ export default {
title: "Controls/Input",
component: Components.Input,
argTypes: {
defaultValue: {
control: { type: "text" },
},
label: {
control: { type: "text" },
},
placeholder: {
control: { type: "text" },
},
isOptional: { control: { type: "boolean" } },
icon: {
options: icons,
control: { type: "select" },
},
value: {
type: {
options: ["text", "email", "password"],
control: { type: "select" },
},
hintMessage: {
control: { type: "text" },
},
disabled: { control: "boolean" },
hintType: {
options: ["hint", "error", "warning"],
control: { type: "select" },
},
variant: {
options: ["dense", "comfortable"],
control: { type: "select" },
},
disabled: {
control: { type: "boolean" },
},
},
args: {
id: "input",
label: "Label",
isOptional: false,
defaultValue: "Value",
placeholder: "Placeholder",
type: "text",
icon: "search",
hintMessage: "This is a hint text to help user.",
hintType: "hint",
variant: "dense",
disabled: false,
value: "Lorem ipsum",
},
parameters: {
controls: { exclude: ["id"] },
},
render: ({ ...args }) => <Input {...args} />,
};
export const Default = {};
export const WithIcon = {
export const Dense = {
args: {
icon: "effects",
variant: "dense",
},
};
export const WithPlaceholder = {
export const Comfortable = {
args: {
icon: "effects",
value: undefined,
placeholder: "Mixed",
variant: "comfortable",
},
};
export const Seamless = {
args: {
variant: "seamless",
},
};

View file

@ -0,0 +1,35 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.ds.controls.utilities.hint-message
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[rumext.v2 :as mf]))
(def ^:private schema::hint-message
[:map
[:message :string]
[:id :string]
[:type {:optional true} [:enum "hint" "error" "warning"]]
[:class {:optional true} :string]])
(mf/defc hint-message*
{::mf/props :obj
::mf/schema schema::hint-message}
[{:keys [id class message type] :rest props}]
(let [type (d/nilv type :hint)]
[:> "div" {:class (dm/str class " " (stl/css-case
:hint-message true
:type-hint (= type "hint")
:type-warning (= type "warning")
:type-error (= type "error")))
:aria-live (when (or (= type "warning") (= type "error")) "polite")}
(when (some? message)
[:span {:class (stl/css :hint-message-text)
:id (str id "-hint")}
message])]))

View file

@ -0,0 +1,27 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) KALEIDOS INC
@use "../../typography.scss" as *;
@use "../../colors.scss" as *;
.hint-message {
--hint-color: var(--color-foreground-secondary);
@include use-typography("body-small");
color: var(--hint-color);
}
.type-hint {
--hint-color: var(--color-foreground-secondary);
}
.type-warning {
--hint-color: var(--color-accent-warning);
}
.type-error {
--hint-color: var(--color-foreground-error);
}

View file

@ -0,0 +1,72 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.ds.controls.utilities.input-field
(:require-macros
[app.common.data.macros :as dm]
[app.main.style :as stl])
(:require
[app.common.data :as d]
[app.main.constants :refer [max-input-length]]
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
[app.util.dom :as dom]
[rumext.v2 :as mf]))
(def ^:private schema:input-field
[:map
[:class {:optional true} :string]
[:id :string]
[:icon {:optional true}
[:and :string [:fn #(contains? icon-list %)]]]
[:has-hint {:optional true} :boolean]
[:hint-type {:optional true} [:maybe [:enum "hint" "error" "warning"]]]
[:type {:optional true} :string]
[:max-length {:optional true} :int]
[:variant {:optional true} [:enum "seamless" "dense" "comfortable"]]])
(mf/defc input-field*
{::mf/props :obj
::mf/forward-ref true
::mf/schema schema:input-field}
[{:keys [id icon has-hint hint-type class type max-length variant children] :rest props} ref]
(let [input-ref (mf/use-ref)
type (d/nilv type "text")
variant (d/nilv variant "dense")
props (mf/spread-props props
{:class (stl/css-case
:input true
:input-with-icon (some? icon))
:ref (or ref input-ref)
:aria-invalid (when (and has-hint
(= hint-type "error"))
"true")
:aria-describedby (when has-hint
(str id "-hint"))
:type (d/nilv type "text")
:id id
:max-length (d/nilv max-length max-input-length)})
on-icon-click
(mf/use-fn
(mf/deps ref)
(fn [_event]
(let [input-node (mf/ref-val ref)]
(dom/select-node input-node)
(dom/focus! input-node))))]
[:div {:class (dm/str class " " (stl/css-case :input-wrapper true
:has-hint has-hint
:hint-type-hint (= hint-type "hint")
:hint-type-warning (= hint-type "warning")
:hint-type-error (= hint-type "error")
:variant-seamless (= variant "seamless")
:variant-dense (= variant "dense")
:variant-comfortable (= variant "comfortable")))}
(when (some? icon)
[:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}])
[:> "input" props]
(when (some? children)
[:div {:class (stl/css :input-actions)} children])]))

View file

@ -0,0 +1,121 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) KALEIDOS INC
@use "../../_borders.scss" as *;
@use "../../_sizes.scss" as *;
@use "../../typography.scss" as *;
@use "../../colors.scss" as *;
.input-wrapper {
--input-bg-color: var(--color-background-tertiary);
--input-fg-color: var(--color-foreground-primary);
--input-icon-color: var(--color-foreground-secondary);
--input-outline-color: none;
--input-height: #{$sz-32};
--input-margin: unset;
display: inline-flex;
column-gap: var(--sp-xs);
align-items: center;
position: relative;
inline-size: 100%;
background: var(--input-bg-color);
border-radius: $br-8;
padding: 0 var(--sp-s);
outline-offset: #{$b-1};
outline: $b-1 solid var(--input-outline-color);
&:hover {
--input-bg-color: var(--color-background-quaternary);
}
&:has(*:focus-visible) {
--input-bg-color: var(--color-background-primary);
--input-outline-color: var(--color-accent-primary);
}
&:has(*:disabled) {
--input-bg-color: var(--color-background-primary);
--input-outline-color: var(--color-background-quaternary);
}
}
.variant-dense {
@include use-typography("body-small");
}
.variant-comfortable {
@include use-typography("body-medium");
}
.variant-seamless {
--input-bg-color: none;
--input-outline-color: none;
--input-height: auto;
--input-margin: 0;
padding: 0;
border: none;
&:hover {
--input-bg-color: none;
--input-outline-color: none;
}
&:has(*:focus-visible) {
--input-bg-color: none;
--input-outline-color: none;
}
}
.input {
margin: var(--input-margin); // remove settings from global css
padding: 0;
appearance: none;
height: var(--input-height);
border: none;
background: none;
inline-size: 100%;
font-family: inherit;
font-size: inherit;
font-weight: inherit;
line-height: inherit;
color: var(--input-fg-color);
&:focus-visible {
outline: none;
}
&::selection {
background: var(--color-accent-select);
}
&::placeholder {
--input-fg-color: var(--color-foreground-secondary);
}
&:is(:autofill, :autofill:hover, :autofill:focus, :autofill:active) {
-webkit-text-fill-color: var(--input-fg-color);
-webkit-background-clip: text;
background-clip: text;
caret-color: var(--input-bg-color);
}
}
.input-with-icon {
margin-inline-start: var(--sp-xxs);
}
.hint-type-error:has(.has-hint) {
--input-outline-color: var(--color-foreground-error);
}
.icon {
color: var(--color-foreground-secondary);
}

View file

@ -0,0 +1,31 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.ds.controls.utilities.label
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[rumext.v2 :as mf]))
(def ^:private schema::label
[:map
[:for :string]
[:is-optional {:optional true} :boolean]
[:class {:optional true} :string]])
(mf/defc label*
{::mf/props :obj
::mf/schema schema::label}
[{:keys [class for is-optional children] :rest props}]
(let [is-optional (or is-optional false)
props (mf/spread-props props {:class (dm/str class " " (stl/css :label))
:for for})]
[:> "label" props
[:*
(when (some? children)
[:span {:class (stl/css :label-text)} children])
(when is-optional
[:span {:class (stl/css :label-optional)} "(Optional)"])]]))

View file

@ -0,0 +1,28 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) KALEIDOS INC
@use "../../typography.scss" as *;
@use "../../colors.scss" as *;
@use "../../spacing.scss" as *;
.label {
--label-color: var(--color-foreground-primary);
--label-optional-color: var(--color-foreground-secondary);
@include use-typography("body-small");
color: var(--label-color);
display: flex;
gap: var(--sp-xs);
align-items: center;
}
.label-text {
color: var(--label-color);
}
.label-optional {
color: var(--label-optional-color);
}

View file

@ -4,7 +4,7 @@
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.tokens.components.controls.input-tokens
(ns app.main.ui.workspace.tokens.components.controls.input-tokens-value
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
@ -13,9 +13,8 @@
[app.main.ui.ds.controls.input :refer [input*]]
[rumext.v2 :as mf]))
(def ^:private schema::input-tokens
(def ^:private schema::input-tokens-value
[:map
[:id :string]
[:label :string]
[:placeholder {:optional true} :string]
[:default-value {:optional true} [:maybe :string]]
@ -24,19 +23,20 @@
[:error {:optional true} :boolean]
[:value {:optional true} :string]])
(mf/defc input-tokens*
(mf/defc input-tokens-value*
{::mf/props :obj
::mf/forward-ref true
::mf/schema schema::input-tokens}
[{:keys [class label id max-length error value children] :rest props} ref]
(let [ref (or ref (mf/use-ref))
::mf/schema schema::input-tokens-value}
[{:keys [class label max-length error value children] :rest props} ref]
(let [id (mf/use-id)
input-ref (mf/use-ref)
props (mf/spread-props props {:id id
:type "text"
:class (stl/css :input)
:aria-invalid error
:max-length (d/nilv max-length max-input-length)
:value value
:ref ref})]
:ref (or ref input-ref)})]
[:div {:class (dm/str class " " (stl/css-case :wrapper true
:input-error error))}
[:label {:for id :class (stl/css :label)} label]

View file

@ -34,6 +34,7 @@
.input-wrapper {
display: flex;
flex: 1;
align-items: center;
&:has(.input-swatch) {
@ -51,3 +52,7 @@
inset-inline-start: var(--sp-s);
z-index: 2;
}
.input {
flex: 1;
}

View file

@ -12,6 +12,7 @@
[app.common.data.macros :as dm]
[app.common.files.tokens :as cft]
[app.common.types.tokens-lib :as ctob]
[app.main.constants :refer [max-input-length]]
[app.main.data.modal :as modal]
[app.main.data.style-dictionary :as sd]
[app.main.data.tinycolor :as tinycolor]
@ -23,6 +24,8 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.controls.input :refer [input*]]
[app.main.ui.ds.controls.utilities.hint-message :refer [hint-message*]]
[app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
[app.main.ui.ds.foundations.typography.text :refer [text*]]
@ -30,7 +33,7 @@
[app.main.ui.workspace.colorpicker :as colorpicker]
[app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector*]]
[app.main.ui.workspace.tokens.components.controls.input-token-color-bullet :refer [input-token-color-bullet*]]
[app.main.ui.workspace.tokens.components.controls.input-tokens :refer [input-tokens*]]
[app.main.ui.workspace.tokens.components.controls.input-tokens-value :refer [input-tokens-value*]]
[app.util.dom :as dom]
[app.util.functions :as uf]
[app.util.i18n :refer [tr]]
@ -277,6 +280,7 @@
token-name-ref (mf/use-var (:name token))
name-ref (mf/use-ref nil)
name-errors (mf/use-state nil)
validate-name
(mf/use-fn
(mf/deps selected-set-tokens-tree)
@ -405,20 +409,22 @@
;; Description
description-ref (mf/use-var (:description token))
description-errors (mf/use-state nil)
description-errors* (mf/use-state nil)
description-errors (deref description-errors*)
validate-descripion (mf/use-fn #(m/explain token-description-schema %))
on-update-description-debounced (mf/use-fn
(uf/debounce (fn [e]
(let [value (dom/get-target-val e)
errors (validate-descripion value)]
(reset! description-errors errors)))))
(reset! description-errors* errors)))))
on-update-description
(mf/use-fn
(mf/deps on-update-description-debounced)
(fn [e]
(reset! description-ref (dom/get-target-val e))
(on-update-description-debounced e)))
valid-description-field? (not @description-errors)
valid-description-field? (not description-errors)
;; Form
disabled? (or (not valid-name-field?)
@ -523,26 +529,26 @@
[:div {:class (stl/css :input-row)}
(let [token-title (str/lower (:title token-properties))]
[:> input-tokens*
{:id "token-name"
:placeholder (tr "workspace.token.enter-token-name", token-title)
:error (boolean @name-errors)
:auto-focus true
:label (tr "workspace.token.token-name")
:default-value @token-name-ref
:ref name-ref
:max-length 256
:on-blur on-blur-name
:on-change on-update-name}])
[:> input* {:id "token-name"
:label (tr "workspace.token.token-name")
:placeholder (tr "workspace.token.enter-token-name", token-title)
:max-length max-input-length
:variant "comfortable"
:auto-focus true
:default-value @token-name-ref
:ref name-ref
:on-blur on-blur-name
:on-change on-update-name}])
(for [error (->> (:errors @name-errors)
(map #(-> (assoc @name-errors :errors [%])
(me/humanize))))]
[:> text* {:as "p"
:key error
:typography "body-small"
:class (stl/css :error)}
error])
(me/humanize)))
(map first))]
[:> hint-message* {:key error
:message error
:type "error"
:id "token-name-hint"}])
(when (and warning-name-change? (= action "edit"))
[:div {:class (stl/css :warning-name-change-notification-wrapper)}
@ -550,7 +556,7 @@
{:level :warning :appearance :ghost} (tr "workspace.token.warning-name-change")]])]
[:div {:class (stl/css :input-row)}
[:> input-tokens*
[:> input-tokens-value*
{:id "token-value"
:placeholder (tr "workspace.token.token-value-enter")
:label (tr "workspace.token.token-value")
@ -567,21 +573,14 @@
[:> ramp* {:color (some-> color (tinycolor/valid-color))
:on-change on-update-color}])
[:& token-value-or-errors {:result-or-errors token-resolve-result}]]
[:div {:class (stl/css :input-row)}
[:> input-tokens*
{:id "token-description"
:placeholder (tr "workspace.token.enter-token-description")
:label (tr "workspace.token.token-description")
:max-length 256
:default-value @description-ref
:on-blur on-update-description
:on-change on-update-description}]
(when @description-errors
[:> text* {:as "p"
:typography "body-small"
:class (stl/css :error)}
(me/humanize @description-errors)])]
[:> input* {:label (tr "workspace.token.token-description")
:placeholder (tr "workspace.token.enter-token-description")
:max-length max-input-length
:variant "comfortable"
:default-value @description-ref
:on-blur on-update-description
:on-change on-update-description}]]
[:div {:class (stl/css-case :button-row true
:with-delete (= action "edit"))}

View file

@ -10,6 +10,7 @@
[app.common.data.macros :as dm]
[app.common.logic.tokens :as clt]
[app.common.types.tokens-lib :as ctob]
[app.main.constants :refer [max-input-length]]
[app.main.data.event :as ev]
[app.main.data.modal :as modal]
[app.main.data.workspace.tokens.library-edit :as dwtl]
@ -19,11 +20,11 @@
[app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.combobox :refer [combobox*]]
[app.main.ui.ds.controls.input :refer [input*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as ic]
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
[app.main.ui.ds.foundations.typography.text :refer [text*]]
[app.main.ui.icons :as i]
[app.main.ui.workspace.tokens.components.controls.input-tokens :refer [input-tokens*]]
[app.main.ui.workspace.tokens.sets :as wts]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
@ -202,14 +203,13 @@
:on-change on-update-group}]]
[:div {:class (stl/css :group-input-wrapper)}
[:> input-tokens* {:id "theme-input"
:label (tr "workspace.token.label.theme")
:type "text"
:max-length 256
:placeholder (tr "workspace.token.label.theme-placeholder")
:on-change on-update-name
:value (mf/ref-val theme-name-ref)
:auto-focus true}]]]))
[:> input* {:label (tr "workspace.token.label.theme")
:placeholder (tr "workspace.token.label.theme-placeholder")
:max-length max-input-length
:variant "comfortable"
:default-value (mf/ref-val theme-name-ref)
:auto-focus true
:on-change on-update-name}]]]))
(mf/defc theme-modal-buttons*
[{:keys [close-modal on-save-form disabled?] :as props}]