This commit is contained in:
Eva Marco
2025-11-05 16:54:12 +01:00
parent d5e4b6f57e
commit 6d82a01a37
6 changed files with 82 additions and 42 deletions

View File

@@ -1318,7 +1318,7 @@ test.describe("Tokens: Apply token", () => {
const firstColorValue = await colorInput.inputValue();
// User adds a second shadow
const addButton = firstShadowFields.getByTestId("shadow-add-button-0");
const addButton = firstShadowFields.getByTestId("shadow-add-button");
await addButton.click();
const secondShadowFields = tokensUpdateCreateModal.getByTestId(
@@ -1327,7 +1327,7 @@ test.describe("Tokens: Apply token", () => {
await expect(secondShadowFields).toBeVisible();
// User adds a third shadow
const addButton2 = secondShadowFields.getByTestId("shadow-add-button-1");
const addButton2 = secondShadowFields.getByTestId("shadow-add-button");
await addButton2.click();
const thirdShadowFields = tokensUpdateCreateModal.getByTestId(
@@ -1353,7 +1353,7 @@ test.describe("Tokens: Apply token", () => {
await removeButton2.click();
// Verify second shadow is removed
await expect(secondShadowFields.getByTestId("shadow-add-button-3")).not.toBeVisible();
await expect(secondShadowFields.getByTestId("shadow-add-button")).not.toBeVisible();
// Verify that the first shadow kept its values
const firstOffsetXValue = await firstShadowFields.getByLabel("X").inputValue();

View File

@@ -658,13 +658,13 @@
(mf/defc composite-form*
"Wrapper around form* that manages composite/reference tab state.
Takes the same props as form* plus a function to determine if a token value is a reference."
[{:keys [token is-reference-fn composite-tab reference-icon title update-composite-backup-value] :rest props}]
[{:keys [token is-reference-fn composite-tab reference-icon title update-composite-backup-value type on-add-shadow] :rest props}]
(let [active-tab* (mf/use-state (if (is-reference-fn (:value token)) :reference :composite))
active-tab (deref active-tab*)
custom-input-token-value-props
(mf/use-memo
(mf/deps active-tab composite-tab reference-icon title update-composite-backup-value is-reference-fn)
(mf/deps active-tab composite-tab reference-icon title update-composite-backup-value is-reference-fn type)
(fn []
{:active-tab active-tab
:set-active-tab #(reset! active-tab* %)
@@ -672,6 +672,8 @@
:reference-icon reference-icon
:reference-label (tr "workspace.tokens.reference-composite")
:title title
:type type
:on-add-shadow on-add-shadow
:update-composite-backup-value update-composite-backup-value
:is-reference-fn is-reference-fn}))
@@ -728,7 +730,7 @@
(mf/defc shadow-form*
[{:keys [token] :rest props}]
(let [on-get-token-value
(mf/use-callback
(mf/use-fn
(fn [e prev-composite-value]
(let [prev-composite-value (or prev-composite-value [])
[idx token-type :as token-type-at-index] (obj/get e "tokenTypeAtIndex")
@@ -742,7 +744,7 @@
:else (assoc-in prev-composite-value token-type-at-index input-value)))))
update-composite-backup-value
(mf/use-callback
(mf/use-fn
(fn [prev-composite-value e]
(let [[idx token-type :as token-type-at-index] (obj/get e "tokenTypeAtIndex")
token-value (case token-type
@@ -754,7 +756,19 @@
(if valid?
(assoc-in (or prev-composite-value []) token-type-at-index token-value)
;; Remove empty values so they don't retrigger validation when switching tabs
(update prev-composite-value idx dissoc token-type)))))]
(update prev-composite-value idx dissoc token-type)))))
on-add-shadow
#(prn "Add shadow clicked")
;; (mf/use-fn
;; (mf/deps shadows update-composite-value)
;; (fn []
;; (update-composite-backup-value
;; (fn [state]
;; (let [new-state (update state :composite (fnil conj []) {})]
;; (reset! shadows* (:composite new-state))
;; new-state)))))
]
[:> composite-form*
(mf/spread-props props {:token token
:composite-tab shadow-value-inputs*
@@ -762,6 +776,8 @@
:is-reference-fn cto/typography-composite-token-reference?
:title (tr "workspace.tokens.shadow-title")
:validate-token validate-shadow-token
:type :shadow
:on-add-shadow on-add-shadow
:on-get-token-value on-get-token-value
:update-composite-backup-value update-composite-backup-value})]))

View File

@@ -11,11 +11,9 @@
[app.common.types.token :as cto]
[app.main.data.style-dictionary :as sd]
[app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.select :refer [select*]]
[app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.workspace.tokens.management.create.input-tokens-value :refer [input-token*]]
[app.main.ui.workspace.tokens.management.create.shared.color-picker :refer [color-picker*]]
[app.util.i18n :refer [tr]]
@@ -24,7 +22,7 @@
(mf/defc inset-type-select*
{::mf/private true}
[{:keys [default-value shadow-idx label on-change]}]
[{:keys [default-value shadow-idx on-change]}]
(let [selected* (mf/use-state (or (str default-value) "false"))
selected (deref selected*)
@@ -32,25 +30,29 @@
(mf/use-fn
(mf/deps on-change selected shadow-idx)
(fn [value e]
(obj/set! e "tokenValue" (if (= "true" value) true false))
(on-change e)
(reset! selected* (str value))))]
#_(obj/set! e "tokenValue" (if (= "true" value) true false))
(prn value)
;; (on-change e)
#_(reset! selected* value)))
options
(mf/with-memo []
[{:id "drop-shadow" :label "drop-shadow" :icon i/drop-shadow}
{:id "inner-shadow" :label "inner-shadow" :icon i/inner-shadow}])]
[:div {:class (stl/css :input-row)}
[:div {:class (stl/css :inset-label)} label]
[:& radio-buttons {:selected selected
:on-change on-change
:name (str "inset-select-" shadow-idx)}
[:& radio-button {:value "false"
:title "false"
:icon "❌"
:id (str "inset-default-" shadow-idx)}]
[:& radio-button {:value "true"
:title "true"
:icon "✅"
:id (str "inset-false-" shadow-idx)}]]]))
[:> select* {:default-selected selected
:variant "ghost"
:options options
:on-change on-change}]]))
(def ^:private shadow-inputs
#(d/ordered-map
:inset
{:label (tr "workspace.tokens.shadow-inset")
:placeholder (tr "workspace.tokens.shadow-inset")}
:color
{:label (tr "workspace.tokens.shadow-color")
:placeholder (tr "workspace.tokens.shadow-color")}
:offsetX
{:label (tr "workspace.tokens.shadow-x")
:placeholder (tr "workspace.tokens.shadow-x")}
@@ -62,13 +64,11 @@
:placeholder (tr "workspace.tokens.shadow-blur")}
:spread
{:label (tr "workspace.tokens.shadow-spread")
:placeholder (tr "workspace.tokens.shadow-spread")}
:color
{:label (tr "workspace.tokens.shadow-color")
:placeholder (tr "workspace.tokens.shadow-color")}
:inset
{:label (tr "workspace.tokens.shadow-inset")
:placeholder (tr "workspace.tokens.shadow-inset")}))
:placeholder (tr "workspace.tokens.shadow-spread")}))
(def ^:private input-icon
{:offsetX i/character-x
:offsetY i/character-y})
(mf/defc shadow-color-picker-wrapper*
"Wrapper for color-picker* that passes shadow color state from parent.
@@ -99,7 +99,6 @@
{::mf/private true}
[{:keys [default-value label placeholder shadow-idx input-type on-update-value on-external-update-value token-resolve-result errors-by-key shadow-color]}]
(let [color-input-ref (mf/use-ref)
on-change
(mf/use-fn
(mf/deps shadow-idx input-type on-update-value)
@@ -130,24 +129,31 @@
:shadow-idx shadow-idx
:label label
:on-change on-change}]
:color
[:> shadow-color-picker-wrapper*
{:placeholder placeholder
:label label
:aria-label label
:default-value default-value
:input-ref color-input-ref
:on-update-value on-change
:on-external-update-value on-external-update-value'
:token-resolve-result token-prop
:shadow-color shadow-color
:shadow-color (or shadow-color nil)
:data-testid (str "shadow-color-input-" shadow-idx)}]
[:div {:class (stl/css :input-row)
:data-testid (str "shadow-" (name input-type) "-input-" shadow-idx)}
[:> input-token*
{:label label
{:aria-label label
:icon (get input-icon input-type)
:placeholder placeholder
:default-value default-value
:on-change on-change
:slot-start (cond (= input-type :blur)
(mf/html [:span {:class (stl/css :shadow-prop-label)} "Blur"])
(= input-type :spread)
(mf/html [:span {:class (stl/css :shadow-prop-label)} "Spread"]))
:token-resolve-result token-prop}]])))
(mf/defc shadow-input-fields*
@@ -157,7 +163,8 @@
(mf/use-fn
(mf/deps shadow-idx on-remove-shadow)
#(on-remove-shadow shadow-idx))]
[:div {:data-testid (str "shadow-input-fields-" shadow-idx)}
[:div {:data-testid (str "shadow-input-fields-" shadow-idx)
:class (stl/css :shadow-input-fields)}
[:> icon-button* {:icon i/add
:type "button"
:on-click on-add-shadow

View File

@@ -15,3 +15,9 @@
flex-direction: column;
gap: var(--sp-m);
}
.shadow-input-fields {
display: flex;
flex-direction: column;
gap: var(--sp-m);
}

View File

@@ -69,7 +69,7 @@
(let [{:keys [color on-display-colorpicker]} custom-input-token-value-props
color-ramp-open* (mf/use-state false)
color-ramp-open? (deref color-ramp-open*)
_ (.log js/console (clj->js token-resolve-result))
on-click-swatch
(mf/use-fn
(mf/deps color-ramp-open? on-display-colorpicker)
@@ -125,4 +125,5 @@
[:> ramp*
{:color (some-> color (tinycolor/valid-color))
:on-change on-change'}])
[:> token-value-hint* {:result token-resolve-result}]]))
(when token-resolve-result
[:> token-value-hint* {:result token-resolve-result}])]))

View File

@@ -2,6 +2,8 @@
(:require-macros [app.main.style :as stl])
(:require
[app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.icons :as deprecated-icon]
[app.main.ui.workspace.tokens.management.create.input-tokens-value :refer [input-token*]]
[app.util.dom :as dom]
@@ -39,6 +41,8 @@
reference-label
set-active-tab
title
type
on-add-shadow
update-composite-backup-value]} custom-input-token-value-props
reference-tab-active? (= :reference active-tab)
;; Backup value ref
@@ -90,7 +94,13 @@
[:& radio-button {:icon deprecated-icon/tokens
:value "reference"
:title (tr "workspace.tokens.use-reference")
:id "reference-opt"}]]]
:id "reference-opt"}]]
(when (= type :shadow)
[:> icon-button* {:icon i/add
:type "button"
:on-click on-add-shadow
:data-testid "shadow-add-button"
:aria-label (tr "workspace.tokens.shadow-add-shadow")}])]
[:div {:class (stl/css :typography-inputs)}
(if reference-tab-active?
[:> composite-reference-input*