mirror of
https://github.com/penpot/penpot.git
synced 2026-02-10 14:43:17 -05:00
Compare commits
3 Commits
niwinz-dev
...
eva-create
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0b66fddea | ||
|
|
a7607f48b6 | ||
|
|
4f81a7f592 |
@@ -83,6 +83,7 @@
|
||||
:name name
|
||||
:resolved (get option :resolved-value)
|
||||
:ref ref
|
||||
:role "option"
|
||||
:focused (= id focused)
|
||||
:on-click on-click}]
|
||||
|
||||
@@ -94,6 +95,7 @@
|
||||
:aria-label (get option :aria-label)
|
||||
:icon (get option :icon)
|
||||
:ref ref
|
||||
:role "option"
|
||||
:focused (= id focused)
|
||||
:dimmed (true? (:dimmed option))
|
||||
:on-click on-click}]))))
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
(ns app.main.ui.ds.controls.utilities.combobox-engine
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.main.data.style-dictionary :as sd]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.input :as ds]
|
||||
[app.main.ui.ds.controls.select :refer [get-option handle-focus-change]]
|
||||
[app.main.ui.ds.controls.shared.options-dropdown :refer [options-dropdown*]]
|
||||
[app.main.ui.ds.controls.utilities.utils :as csu]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.forms :as fc]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.forms :as fm]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.object :as obj]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
||||
(defn use-combobox-engine [{:keys [items on-select]}]
|
||||
|
||||
(let [state* (mf/use-state
|
||||
{:open? false
|
||||
:input-value ""
|
||||
:active-id nil})
|
||||
|
||||
update! (fn [f args]
|
||||
(apply swap! state* f args))
|
||||
|
||||
open! #(swap! state* assoc :open? true)
|
||||
close! #(swap! state* assoc :open? false)
|
||||
toggle! #(swap! state* update :open? not)
|
||||
|
||||
find-index
|
||||
(fn [id]
|
||||
(some (fn [[i item]]
|
||||
(when (= (:id item) id) i))
|
||||
(map-indexed vector items)))
|
||||
|
||||
arrow-down!
|
||||
(fn []
|
||||
(swap! state*
|
||||
update
|
||||
:active-id
|
||||
(fn [id]
|
||||
(let [current-idx (find-index id)
|
||||
next-idx (if current-idx
|
||||
(inc current-idx)
|
||||
0)
|
||||
next-idx (min (dec (count items)) next-idx)]
|
||||
(:id (nth items next-idx nil))))))
|
||||
|
||||
arrow-up!
|
||||
(fn []
|
||||
(swap! state*
|
||||
update
|
||||
:active-id
|
||||
(fn [id]
|
||||
(let [current-idx (find-index id)
|
||||
prev-idx (max 0 (dec (or current-idx 0)))]
|
||||
(:id (nth items prev-idx nil))))))]
|
||||
|
||||
{:state @state*
|
||||
:open! open!
|
||||
:close! close!
|
||||
:update! update!
|
||||
:toggle! toggle!
|
||||
:arrow-down! arrow-down!
|
||||
:arrow-up! arrow-up!}))
|
||||
95
frontend/src/app/main/ui/ds/controls/utilities/utils.cljs
Normal file
95
frontend/src/app/main/ui/ds/controls/utilities/utils.cljs
Normal file
@@ -0,0 +1,95 @@
|
||||
(ns app.main.ui.ds.controls.utilities.utils
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.token :as cto]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(defn- token->dropdown-option
|
||||
[token]
|
||||
{:id (str (get token :id))
|
||||
:type :token
|
||||
:resolved-value (get token :value)
|
||||
:name (get token :name)})
|
||||
|
||||
(defn- generate-dropdown-options
|
||||
[tokens no-sets]
|
||||
(if (empty? tokens)
|
||||
[{:type :empty
|
||||
:label (if no-sets
|
||||
(tr "ds.inputs.numeric-input.no-applicable-tokens")
|
||||
(tr "ds.inputs.numeric-input.no-matches"))}]
|
||||
(->> tokens
|
||||
(map (fn [[type items]]
|
||||
(cons {:group true
|
||||
:type :group
|
||||
:id (dm/str "group-" (name type))
|
||||
:name (name type)}
|
||||
(map token->dropdown-option items))))
|
||||
(interpose [{:separator true
|
||||
:id "separator"
|
||||
:type :separator}])
|
||||
(apply concat)
|
||||
(vec)
|
||||
(not-empty))))
|
||||
|
||||
(defn- extract-partial-brace-text
|
||||
[s]
|
||||
(when-let [start (str/last-index-of s "{")]
|
||||
(subs s (inc start))))
|
||||
|
||||
(defn- filter-token-groups-by-name
|
||||
[tokens filter-text]
|
||||
(let [lc-filter (str/lower filter-text)]
|
||||
(into {}
|
||||
(keep (fn [[group tokens]]
|
||||
(let [filtered (filter #(str/includes? (str/lower (:name %)) lc-filter) tokens)]
|
||||
(when (seq filtered)
|
||||
[group filtered]))))
|
||||
tokens)))
|
||||
|
||||
(defn- sort-groups-and-tokens
|
||||
"Sorts both the groups and the tokens inside them alphabetically.
|
||||
|
||||
Input:
|
||||
A map where:
|
||||
- keys are groups (keywords or strings, e.g. :dimensions, :colors)
|
||||
- values are vectors of token maps, each containing at least a :name key
|
||||
|
||||
Example input:
|
||||
{:dimensions [{:name \"tres\"} {:name \"quini\"}]
|
||||
:colors [{:name \"azul\"} {:name \"rojo\"}]}
|
||||
|
||||
Output:
|
||||
A sorted map where:
|
||||
- groups are ordered alphabetically by key
|
||||
- tokens inside each group are sorted alphabetically by :name
|
||||
|
||||
Example output:
|
||||
{:colors [{:name \"azul\"} {:name \"rojo\"}]
|
||||
:dimensions [{:name \"quini\"} {:name \"tres\"}]}"
|
||||
|
||||
[groups->tokens]
|
||||
(into (sorted-map) ;; ensure groups are ordered alphabetically by their key
|
||||
(for [[group tokens] groups->tokens]
|
||||
[group (sort-by :name tokens)])))
|
||||
|
||||
(defn get-token-dropdown-options
|
||||
[tokens filter-term]
|
||||
(delay
|
||||
(let [tokens (if (delay? tokens) @tokens tokens)
|
||||
|
||||
sorted-tokens (sort-groups-and-tokens tokens)
|
||||
partial (extract-partial-brace-text filter-term)
|
||||
options (if (seq partial)
|
||||
(filter-token-groups-by-name sorted-tokens partial)
|
||||
sorted-tokens)
|
||||
no-sets? (nil? sorted-tokens)]
|
||||
(generate-dropdown-options options no-sets?))))
|
||||
|
||||
(defn filter-tokens-for-input
|
||||
[raw-tokens input-type]
|
||||
(delay
|
||||
(-> (deref raw-tokens)
|
||||
(select-keys (get cto/tokens-by-input input-type))
|
||||
(not-empty))))
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
;; 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.workspace.tokens.management.forms.border-radius
|
||||
(:require
|
||||
[app.common.types.token :as cto]
|
||||
[app.main.ui.workspace.tokens.management.forms.controls :as token.controls]
|
||||
[app.main.ui.workspace.tokens.management.forms.generic-form :as generic]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
||||
(mf/defc form*
|
||||
[{:keys [token token-type] :rest props}]
|
||||
(let [token
|
||||
(mf/with-memo [token]
|
||||
(if token
|
||||
(update token :value cto/join-font-family)
|
||||
{:type token-type}))
|
||||
props (mf/spread-props props {:token token
|
||||
:token-type token-type
|
||||
:input-component token.controls/combobox*})]
|
||||
[:> generic/form* props]))
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.ui.workspace.tokens.management.forms.controls.color-input :as color]
|
||||
[app.main.ui.workspace.tokens.management.forms.controls.combobox :as combobox]
|
||||
[app.main.ui.workspace.tokens.management.forms.controls.fonts-combobox :as fonts]
|
||||
[app.main.ui.workspace.tokens.management.forms.controls.input :as input]
|
||||
[app.main.ui.workspace.tokens.management.forms.controls.select :as select]))
|
||||
@@ -16,4 +17,6 @@
|
||||
(dm/export fonts/fonts-combobox*)
|
||||
(dm/export fonts/composite-fonts-combobox*)
|
||||
|
||||
(dm/export select/select-indexed*)
|
||||
(dm/export select/select-indexed*)
|
||||
|
||||
(dm/export combobox/combobox*)
|
||||
@@ -0,0 +1,327 @@
|
||||
;; 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.workspace.tokens.management.forms.controls.combobox
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.main.data.style-dictionary :as sd]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.input :as ds]
|
||||
[app.main.ui.ds.controls.select :refer [get-option handle-focus-change]]
|
||||
[app.main.ui.ds.controls.shared.options-dropdown :refer [options-dropdown*]]
|
||||
[app.main.ui.ds.controls.utilities.utils :as csu]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.forms :as fc]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.forms :as fm]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.object :as obj]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- focusable-option?
|
||||
[option]
|
||||
(and (:id option)
|
||||
(not= :group (:type option))
|
||||
(not= :separator (:type option))))
|
||||
|
||||
(defn- first-focusable-id
|
||||
[options]
|
||||
(some #(when (focusable-option? %) (:id %)) options))
|
||||
|
||||
(defn- next-focus-index
|
||||
[options focused-id direction]
|
||||
(let [len (count options)
|
||||
start-index (or (d/index-of-pred options #(= focused-id (:id %))) -1)
|
||||
indices (case direction
|
||||
:down (range (inc start-index) (+ len start-index))
|
||||
:up (range (dec start-index) (- start-index len) -1))]
|
||||
(some (fn [i]
|
||||
(let [j (mod i len)]
|
||||
(when (focusable-option? (nth options j))
|
||||
j)))
|
||||
indices)))
|
||||
|
||||
(defn move-focus! [options focused-id* direction nodes-ref]
|
||||
(let [options (if (delay? options) @options options)
|
||||
new-index (next-focus-index options @focused-id* direction)]
|
||||
(when new-index
|
||||
(handle-focus-change options focused-id* new-index (mf/ref-val nodes-ref)))))
|
||||
|
||||
(defn- resolve-value
|
||||
[tokens prev-token token-name value]
|
||||
(let [valid-token-name?
|
||||
(and (string? token-name)
|
||||
(re-matches cto/token-name-validation-regex token-name))
|
||||
|
||||
token
|
||||
{:value value
|
||||
:name (if (or (not valid-token-name?) (str/blank? token-name))
|
||||
"__PENPOT__TOKEN__NAME__PLACEHOLDER__"
|
||||
token-name)}
|
||||
tokens
|
||||
(-> tokens
|
||||
;; Remove previous token when renaming a token
|
||||
(dissoc (:name prev-token))
|
||||
(update (:name token) #(ctob/make-token (merge % prev-token token))))]
|
||||
|
||||
(->> tokens
|
||||
(sd/resolve-tokens-interactive)
|
||||
(rx/mapcat
|
||||
(fn [resolved-tokens]
|
||||
(let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token))]
|
||||
(if resolved-value
|
||||
(rx/of {:value resolved-value})
|
||||
(rx/of {:error (first errors)}))))))))
|
||||
|
||||
(mf/defc combobox*
|
||||
[{:keys [name tokens token token-type empty-to-end align ref] :rest props}]
|
||||
|
||||
(let [form (mf/use-ctx fc/context)
|
||||
|
||||
input-name name
|
||||
token-name (get-in @form [:data :name] nil)
|
||||
|
||||
is-open* (mf/use-state false)
|
||||
is-open (deref is-open*)
|
||||
|
||||
|
||||
listbox-id (mf/use-id)
|
||||
filter-term* (mf/use-state "")
|
||||
filter-term (deref filter-term*)
|
||||
|
||||
focused-id* (mf/use-state nil)
|
||||
focused-id (deref focused-id*)
|
||||
|
||||
options-ref (mf/use-ref nil)
|
||||
internal-ref (mf/use-ref nil)
|
||||
nodes-ref (mf/use-ref nil)
|
||||
icon-button-ref (mf/use-ref nil)
|
||||
ref (or ref internal-ref)
|
||||
|
||||
touched?
|
||||
(and (contains? (:data @form) input-name)
|
||||
(get-in @form [:touched input-name]))
|
||||
|
||||
error
|
||||
(get-in @form [:errors input-name])
|
||||
|
||||
value
|
||||
(get-in @form [:data input-name] "")
|
||||
|
||||
raw-tokens-by-type (mf/use-ctx muc/active-tokens-by-type)
|
||||
|
||||
filtered-tokens-by-type
|
||||
(mf/with-memo [raw-tokens-by-type token-type]
|
||||
(csu/filter-tokens-for-input raw-tokens-by-type token-type))
|
||||
|
||||
dropdown-options
|
||||
(mf/with-memo [filtered-tokens-by-type filter-term]
|
||||
(csu/get-token-dropdown-options filtered-tokens-by-type filter-term))
|
||||
|
||||
set-option-ref
|
||||
(mf/use-fn
|
||||
(fn [node]
|
||||
(let [state (mf/ref-val nodes-ref)
|
||||
state (d/nilv state #js {})
|
||||
id (dom/get-data node "id")
|
||||
state (obj/set! state id node)]
|
||||
(mf/set-ref-val! nodes-ref state))))
|
||||
|
||||
toggle-dropdown
|
||||
(mf/use-fn
|
||||
(mf/deps)
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(swap! is-open* not)))
|
||||
on-blur
|
||||
(mf/use-fn
|
||||
(mf/deps)
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(reset! is-open* false)))
|
||||
|
||||
resolve-stream
|
||||
(mf/with-memo [token]
|
||||
(if (contains? token :value)
|
||||
(rx/behavior-subject (:value token))
|
||||
(rx/subject)))
|
||||
|
||||
on-change
|
||||
(mf/use-fn
|
||||
(mf/deps resolve-stream input-name form)
|
||||
(fn [event]
|
||||
(let [value (-> event dom/get-target dom/get-input-value)]
|
||||
(fm/on-input-change form input-name value)
|
||||
(rx/push! resolve-stream value))))
|
||||
|
||||
on-option-click
|
||||
(mf/use-fn
|
||||
(mf/deps value resolve-stream)
|
||||
(fn [event]
|
||||
(let [node (dom/get-current-target event)
|
||||
id (dom/get-data node "id")
|
||||
options (mf/ref-val options-ref)
|
||||
options (if (delay? options) @options options)
|
||||
option (get-option options id)
|
||||
name (get option :name)
|
||||
token-ref (str "{" name "}")
|
||||
final-val (str value " " token-ref)]
|
||||
(fm/on-input-change form input-name final-val true)
|
||||
(rx/push! resolve-stream final-val)
|
||||
(reset! filter-term* "")
|
||||
(reset! is-open* false))))
|
||||
|
||||
on-option-enter
|
||||
(mf/use-fn
|
||||
(mf/deps focused-id value)
|
||||
(fn [_]
|
||||
(let [options (mf/ref-val options-ref)
|
||||
options (if (delay? options) @options options)
|
||||
option (get-option options focused-id)
|
||||
name (get option :name)
|
||||
token-ref (str "{" name "}")
|
||||
final-val (str value " " token-ref)]
|
||||
(fm/on-input-change form input-name final-val true)
|
||||
(rx/push! resolve-stream final-val)
|
||||
(reset! filter-term* "")
|
||||
(reset! is-open* false))))
|
||||
|
||||
on-button-key-down
|
||||
(mf/use-fn
|
||||
(mf/deps is-open)
|
||||
(fn [event]
|
||||
(let [enter? (kbd/enter? event)]
|
||||
(when enter?
|
||||
(if is-open
|
||||
(on-option-enter event)
|
||||
(reset! is-open* true))))))
|
||||
|
||||
on-key-down
|
||||
(mf/use-fn
|
||||
(mf/deps is-open)
|
||||
(fn [event]
|
||||
(let [up? (kbd/up-arrow? event)
|
||||
down? (kbd/down-arrow? event)
|
||||
enter? (kbd/enter? event)
|
||||
esc? (kbd/esc? event)
|
||||
open-dropdown (kbd/is-key? event "{")
|
||||
close-dropdown (kbd/is-key? event "}")
|
||||
options (mf/ref-val options-ref)
|
||||
options (if (delay? options) @options options)]
|
||||
|
||||
(cond
|
||||
open-dropdown
|
||||
(reset! is-open* true)
|
||||
|
||||
close-dropdown
|
||||
(reset! is-open* false)
|
||||
|
||||
down?
|
||||
(do
|
||||
(dom/prevent-default event)
|
||||
(if is-open
|
||||
(move-focus! options focused-id* :down nodes-ref)
|
||||
(do
|
||||
(toggle-dropdown event)
|
||||
(reset! focused-id* (first-focusable-id options)))))
|
||||
|
||||
up?
|
||||
(when is-open
|
||||
(dom/prevent-default event)
|
||||
(move-focus! options focused-id* :up nodes-ref))
|
||||
|
||||
enter?
|
||||
(do
|
||||
(dom/prevent-default event)
|
||||
(if is-open
|
||||
(on-option-enter event)
|
||||
(toggle-dropdown event)))
|
||||
|
||||
esc?
|
||||
(do
|
||||
(dom/prevent-default event)
|
||||
(reset! is-open* false))))))
|
||||
|
||||
hint*
|
||||
(mf/use-state {})
|
||||
|
||||
hint
|
||||
(deref hint*)
|
||||
|
||||
props
|
||||
(mf/spread-props props {:on-change on-change
|
||||
:value value
|
||||
:variant "comfortable"
|
||||
:hint-message (:message hint)
|
||||
:on-key-down on-key-down
|
||||
:hint-type (:type hint)
|
||||
:ref ref
|
||||
:role "combobox"
|
||||
:aria-activedescendant focused-id
|
||||
:slot-end
|
||||
(when (some? @filtered-tokens-by-type)
|
||||
(mf/html
|
||||
[:> icon-button*
|
||||
{:variant "action"
|
||||
:icon i/arrow-down
|
||||
:ref icon-button-ref
|
||||
:tooltip-class (stl/css :button-tooltip)
|
||||
:class (stl/css :invisible-button)
|
||||
:on-key-down on-button-key-down
|
||||
:aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown")
|
||||
:on-click toggle-dropdown}]))})
|
||||
props
|
||||
(if (and error touched?)
|
||||
(mf/spread-props props {:hint-type "error"
|
||||
:hint-message (:message error)})
|
||||
props)]
|
||||
|
||||
(mf/with-effect [resolve-stream tokens token input-name token-name]
|
||||
(let [subs (->> resolve-stream
|
||||
(rx/debounce 300)
|
||||
(rx/mapcat (partial resolve-value tokens token token-name))
|
||||
(rx/map (fn [result]
|
||||
(d/update-when result :error
|
||||
(fn [error]
|
||||
((:error/fn error) (:error/value error))))))
|
||||
(rx/subs! (fn [{:keys [error value]}]
|
||||
(let [touched? (get-in @form [:touched input-name])]
|
||||
(when touched?
|
||||
(if error
|
||||
(do
|
||||
(swap! form assoc-in [:extra-errors input-name] {:message error})
|
||||
(reset! hint* {:message error :type "error"}))
|
||||
(let [message (tr "workspace.tokens.resolved-value" value)]
|
||||
(swap! form update :extra-errors dissoc input-name)
|
||||
(reset! hint* {:message message :type "hint"}))))))))]
|
||||
(fn []
|
||||
(rx/dispose! subs))))
|
||||
|
||||
(mf/with-effect [dropdown-options]
|
||||
(mf/set-ref-val! options-ref dropdown-options))
|
||||
|
||||
[:div {:class (stl/css :combobox-wrapper)
|
||||
;; :on-blur on-blur
|
||||
}
|
||||
[:> ds/input* props]
|
||||
(when ^boolean is-open
|
||||
(let [options (if (delay? dropdown-options) @dropdown-options dropdown-options)]
|
||||
[:> options-dropdown* {:on-click on-option-click
|
||||
:id listbox-id
|
||||
:options options
|
||||
:focused focused-id
|
||||
:selected nil
|
||||
:align :right
|
||||
:style {:top "56px"}
|
||||
:empty-to-end empty-to-end
|
||||
:ref set-option-ref}]))]))
|
||||
@@ -0,0 +1,3 @@
|
||||
.combobox-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
[app.common.files.tokens :as cft]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.workspace.tokens.management.forms.border-radius :as test]
|
||||
[app.main.ui.workspace.tokens.management.forms.color :as color]
|
||||
[app.main.ui.workspace.tokens.management.forms.font-family :as font-family]
|
||||
[app.main.ui.workspace.tokens.management.forms.generic-form :as generic]
|
||||
@@ -50,4 +51,5 @@
|
||||
:text-case [:> generic/form* text-case-props]
|
||||
:text-decoration [:> generic/form* text-decoration-props]
|
||||
:font-weight [:> generic/form* font-weight-props]
|
||||
:border-radius [:> test/form* props]
|
||||
[:> generic/form* props])))
|
||||
@@ -22,6 +22,7 @@
|
||||
[app.main.data.workspace.tokens.remapping :as remap]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
@@ -127,6 +128,10 @@
|
||||
(and (:name token) (:value token))
|
||||
(assoc (:name token) token)))
|
||||
|
||||
active-tokens-by-type
|
||||
(mf/with-memo [tokens]
|
||||
(delay (ctob/group-by-type tokens)))
|
||||
|
||||
schema
|
||||
(mf/with-memo [tokens-tree-in-selected-set active-tab]
|
||||
(make-schema tokens-tree-in-selected-set active-tab))
|
||||
@@ -253,7 +258,8 @@
|
||||
error-message (first error-messages)]
|
||||
(swap! form assoc-in [:extra-errors :value] {:message error-message}))))))))]
|
||||
|
||||
[:> fc/form* {:class (stl/css :form-wrapper)
|
||||
[(mf/provider muc/active-tokens-by-type) {:value active-tokens-by-type}
|
||||
[:> fc/form* {:class (stl/css :form-wrapper)
|
||||
:form form
|
||||
:on-submit on-submit}
|
||||
[:div {:class (stl/css :token-rows)}
|
||||
@@ -296,6 +302,7 @@
|
||||
:label (tr "workspace.tokens.token-value")
|
||||
:name :value
|
||||
:token token
|
||||
:token-type token-type
|
||||
:tokens tokens}])]
|
||||
|
||||
[:div {:class (stl/css :input-row)}
|
||||
@@ -327,4 +334,4 @@
|
||||
|
||||
[:> fc/form-submit* {:variant "primary"
|
||||
:on-submit on-submit}
|
||||
(tr "labels.save")]]]]))
|
||||
(tr "labels.save")]]]]]))
|
||||
|
||||
Reference in New Issue
Block a user