diff --git a/frontend/playwright/ui/specs/tokens.spec.js b/frontend/playwright/ui/specs/tokens.spec.js index e6c3239267..ce8b435f87 100644 --- a/frontend/playwright/ui/specs/tokens.spec.js +++ b/frontend/playwright/ui/specs/tokens.spec.js @@ -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(); diff --git a/frontend/src/app/main/ui/workspace/tokens/management/create/form.cljs b/frontend/src/app/main/ui/workspace/tokens/management/create/form.cljs index c391e7bf65..7dea4e7110 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/create/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/create/form.cljs @@ -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})])) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/create/shadow.cljs b/frontend/src/app/main/ui/workspace/tokens/management/create/shadow.cljs index 3df034685e..fa39c35b3d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/create/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/create/shadow.cljs @@ -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 diff --git a/frontend/src/app/main/ui/workspace/tokens/management/create/shadow.scss b/frontend/src/app/main/ui/workspace/tokens/management/create/shadow.scss index 544a39db1a..06c5fdd3d6 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/create/shadow.scss +++ b/frontend/src/app/main/ui/workspace/tokens/management/create/shadow.scss @@ -15,3 +15,9 @@ flex-direction: column; gap: var(--sp-m); } + +.shadow-input-fields { + display: flex; + flex-direction: column; + gap: var(--sp-m); +} \ No newline at end of file diff --git a/frontend/src/app/main/ui/workspace/tokens/management/create/shared/color_picker.cljs b/frontend/src/app/main/ui/workspace/tokens/management/create/shared/color_picker.cljs index dd89c45cd1..efc0799578 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/create/shared/color_picker.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/create/shared/color_picker.cljs @@ -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}]])) \ No newline at end of file + (when token-resolve-result + [:> token-value-hint* {:result token-resolve-result}])])) \ No newline at end of file diff --git a/frontend/src/app/main/ui/workspace/tokens/management/create/shared/composite_tabs.cljs b/frontend/src/app/main/ui/workspace/tokens/management/create/shared/composite_tabs.cljs index bb5c6e4fe4..7c051b7bf1 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/create/shared/composite_tabs.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/create/shared/composite_tabs.cljs @@ -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*