mirror of
https://github.com/penpot/penpot.git
synced 2025-08-01 07:39:07 +02:00
✨ Fix spacing token for frame children
This commit is contained in:
parent
f7627e515a
commit
1f15e9b81e
6 changed files with 182 additions and 106 deletions
|
@ -92,19 +92,32 @@
|
||||||
|
|
||||||
(def opacity-keys (schema-keys schema:opacity))
|
(def opacity-keys (schema-keys schema:opacity))
|
||||||
|
|
||||||
(def ^:private schema:spacing
|
(def ^:private schema:spacing-gap
|
||||||
[:map
|
[:map
|
||||||
[:row-gap {:optional true} token-name-ref]
|
[:row-gap {:optional true} token-name-ref]
|
||||||
[:column-gap {:optional true} token-name-ref]
|
[:column-gap {:optional true} token-name-ref]])
|
||||||
|
|
||||||
|
(def ^:private schema:spacing-padding
|
||||||
|
[:map
|
||||||
[:p1 {:optional true} token-name-ref]
|
[:p1 {:optional true} token-name-ref]
|
||||||
[:p2 {:optional true} token-name-ref]
|
[:p2 {:optional true} token-name-ref]
|
||||||
[:p3 {:optional true} token-name-ref]
|
[:p3 {:optional true} token-name-ref]
|
||||||
[:p4 {:optional true} token-name-ref]
|
[:p4 {:optional true} token-name-ref]])
|
||||||
|
|
||||||
|
(def ^:private schema:spacing-margin
|
||||||
|
[:map
|
||||||
[:m1 {:optional true} token-name-ref]
|
[:m1 {:optional true} token-name-ref]
|
||||||
[:m2 {:optional true} token-name-ref]
|
[:m2 {:optional true} token-name-ref]
|
||||||
[:m3 {:optional true} token-name-ref]
|
[:m3 {:optional true} token-name-ref]
|
||||||
[:m4 {:optional true} token-name-ref]])
|
[:m4 {:optional true} token-name-ref]])
|
||||||
|
|
||||||
|
(def ^:private schema:spacing
|
||||||
|
(reduce mu/union [schema:spacing-gap
|
||||||
|
schema:spacing-padding
|
||||||
|
schema:spacing-margin]))
|
||||||
|
|
||||||
|
(def spacing-margin-keys (schema-keys schema:spacing-margin))
|
||||||
|
|
||||||
(def spacing-keys (schema-keys schema:spacing))
|
(def spacing-keys (schema-keys schema:spacing))
|
||||||
|
|
||||||
(def ^:private schema:dimensions
|
(def ^:private schema:dimensions
|
||||||
|
|
|
@ -31,88 +31,6 @@
|
||||||
|
|
||||||
(declare token-properties)
|
(declare token-properties)
|
||||||
|
|
||||||
;; Events to apply / unapply tokens to shapes ------------------------------------------------------------
|
|
||||||
|
|
||||||
(defn apply-token
|
|
||||||
"Apply `attributes` that match `token` for `shape-ids`.
|
|
||||||
|
|
||||||
Optionally remove attributes from `attributes-to-remove`,
|
|
||||||
this is useful for applying a single attribute from an attributes set
|
|
||||||
while removing other applied tokens from this set."
|
|
||||||
[{:keys [attributes attributes-to-remove token shape-ids on-update-shape]}]
|
|
||||||
(ptk/reify ::apply-token
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state _]
|
|
||||||
;; We do not allow to apply tokens while text editor is open.
|
|
||||||
(when (empty? (get state :workspace-editor-state))
|
|
||||||
(when-let [tokens (some-> (dsh/lookup-file-data state)
|
|
||||||
(get :tokens-lib)
|
|
||||||
(ctob/get-tokens-in-active-sets))]
|
|
||||||
(->> (sd/resolve-tokens tokens)
|
|
||||||
(rx/mapcat
|
|
||||||
(fn [resolved-tokens]
|
|
||||||
(let [undo-id (js/Symbol)
|
|
||||||
objects (dsh/lookup-page-objects state)
|
|
||||||
|
|
||||||
shape-ids (or (->> (select-keys objects shape-ids)
|
|
||||||
(filter (fn [[_ shape]]
|
|
||||||
(ctt/any-appliable-attr? attributes (:type shape))))
|
|
||||||
(keys))
|
|
||||||
[])
|
|
||||||
|
|
||||||
resolved-value (get-in resolved-tokens [(cft/token-identifier token) :resolved-value])
|
|
||||||
tokenized-attributes (cft/attributes-map attributes token)]
|
|
||||||
(rx/of
|
|
||||||
(st/emit! (ptk/event ::ev/event {::ev/name "apply-tokens"}))
|
|
||||||
(dwu/start-undo-transaction undo-id)
|
|
||||||
(dwsh/update-shapes shape-ids (fn [shape]
|
|
||||||
(cond-> shape
|
|
||||||
attributes-to-remove
|
|
||||||
(update :applied-tokens #(apply (partial dissoc %) attributes-to-remove))
|
|
||||||
:always
|
|
||||||
(update :applied-tokens merge tokenized-attributes))))
|
|
||||||
(when on-update-shape
|
|
||||||
(on-update-shape resolved-value shape-ids attributes))
|
|
||||||
(dwu/commit-undo-transaction undo-id)))))))))))
|
|
||||||
|
|
||||||
(defn unapply-token
|
|
||||||
"Removes `attributes` that match `token` for `shape-ids`.
|
|
||||||
|
|
||||||
Doesn't update shape attributes."
|
|
||||||
[{:keys [attributes token shape-ids] :as _props}]
|
|
||||||
(ptk/reify ::unapply-token
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ _]
|
|
||||||
(rx/of
|
|
||||||
(let [remove-token #(when % (cft/remove-attributes-for-token attributes token %))]
|
|
||||||
(dwsh/update-shapes
|
|
||||||
shape-ids
|
|
||||||
(fn [shape]
|
|
||||||
(update shape :applied-tokens remove-token))))))))
|
|
||||||
|
|
||||||
(defn toggle-token
|
|
||||||
[{:keys [token shapes]}]
|
|
||||||
(ptk/reify ::on-toggle-token
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ _ _]
|
|
||||||
(let [{:keys [attributes all-attributes on-update-shape]}
|
|
||||||
(get token-properties (:type token))
|
|
||||||
|
|
||||||
unapply-tokens?
|
|
||||||
(cft/shapes-token-applied? token shapes (or all-attributes attributes))
|
|
||||||
|
|
||||||
shape-ids (map :id shapes)]
|
|
||||||
(if unapply-tokens?
|
|
||||||
(rx/of
|
|
||||||
(unapply-token {:attributes (or all-attributes attributes)
|
|
||||||
:token token
|
|
||||||
:shape-ids shape-ids}))
|
|
||||||
(rx/of
|
|
||||||
(apply-token {:attributes attributes
|
|
||||||
:token token
|
|
||||||
:shape-ids shape-ids
|
|
||||||
:on-update-shape on-update-shape})))))))
|
|
||||||
|
|
||||||
;; Events to update the value of attributes with applied tokens ---------------------------------------------------------
|
;; Events to update the value of attributes with applied tokens ---------------------------------------------------------
|
||||||
|
|
||||||
;; (note that dwsh/update-shapes function returns an event)
|
;; (note that dwsh/update-shapes function returns an event)
|
||||||
|
@ -380,6 +298,123 @@
|
||||||
{:ignore-touched true
|
{:ignore-touched true
|
||||||
:page-id page-id})))))
|
:page-id page-id})))))
|
||||||
|
|
||||||
|
;; Events to apply / unapply tokens to shapes ------------------------------------------------------------
|
||||||
|
|
||||||
|
(defn apply-token
|
||||||
|
"Apply `attributes` that match `token` for `shape-ids`.
|
||||||
|
|
||||||
|
Optionally remove attributes from `attributes-to-remove`,
|
||||||
|
this is useful for applying a single attribute from an attributes set
|
||||||
|
while removing other applied tokens from this set."
|
||||||
|
[{:keys [attributes attributes-to-remove token shape-ids on-update-shape]}]
|
||||||
|
(ptk/reify ::apply-token
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
;; We do not allow to apply tokens while text editor is open.
|
||||||
|
(when (empty? (get state :workspace-editor-state))
|
||||||
|
(when-let [tokens (some-> (dsh/lookup-file-data state)
|
||||||
|
(get :tokens-lib)
|
||||||
|
(ctob/get-tokens-in-active-sets))]
|
||||||
|
(->> (sd/resolve-tokens tokens)
|
||||||
|
(rx/mapcat
|
||||||
|
(fn [resolved-tokens]
|
||||||
|
(let [undo-id (js/Symbol)
|
||||||
|
objects (dsh/lookup-page-objects state)
|
||||||
|
selected-shapes (select-keys objects shape-ids)
|
||||||
|
|
||||||
|
shape-ids (or (->> selected-shapes
|
||||||
|
(filter (fn [[_ shape]]
|
||||||
|
(or
|
||||||
|
(and (ctsl/any-layout-immediate-child? objects shape)
|
||||||
|
(some ctt/spacing-margin-keys attributes))
|
||||||
|
(ctt/any-appliable-attr? attributes (:type shape)))))
|
||||||
|
(keys))
|
||||||
|
[])
|
||||||
|
|
||||||
|
resolved-value (get-in resolved-tokens [(cft/token-identifier token) :resolved-value])
|
||||||
|
tokenized-attributes (cft/attributes-map attributes token)]
|
||||||
|
(rx/of
|
||||||
|
(st/emit! (ptk/event ::ev/event {::ev/name "apply-tokens"}))
|
||||||
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
(dwsh/update-shapes shape-ids (fn [shape]
|
||||||
|
(cond-> shape
|
||||||
|
attributes-to-remove
|
||||||
|
(update :applied-tokens #(apply (partial dissoc %) attributes-to-remove))
|
||||||
|
:always
|
||||||
|
(update :applied-tokens merge tokenized-attributes))))
|
||||||
|
(when on-update-shape
|
||||||
|
(on-update-shape resolved-value shape-ids attributes))
|
||||||
|
(dwu/commit-undo-transaction undo-id)))))))))))
|
||||||
|
|
||||||
|
(defn apply-spacing-token
|
||||||
|
"Handles edge-case for spacing token when applying token via toggle button.
|
||||||
|
Splits out `shape-ids` into seperate default actions:
|
||||||
|
- Layouts take the `default` update function
|
||||||
|
- Shapes inside layout will only take margin"
|
||||||
|
[{:keys [token shapes]}]
|
||||||
|
(ptk/reify ::apply-spacing-token
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [objects (dsh/lookup-page-objects state)
|
||||||
|
|
||||||
|
{:keys [attributes on-update-shape]}
|
||||||
|
(get token-properties (:type token))
|
||||||
|
|
||||||
|
{:keys [other frame-children]}
|
||||||
|
(group-by #(if (ctsl/any-layout-immediate-child? objects %) :frame-children :other) shapes)]
|
||||||
|
|
||||||
|
(rx/of
|
||||||
|
(apply-token {:attributes attributes
|
||||||
|
:token token
|
||||||
|
:shape-ids (map :id other)
|
||||||
|
:on-update-shape on-update-shape})
|
||||||
|
(apply-token {:attributes ctt/spacing-margin-keys
|
||||||
|
:token token
|
||||||
|
:shape-ids (map :id frame-children)
|
||||||
|
:on-update-shape update-layout-item-margin}))))))
|
||||||
|
|
||||||
|
(defn unapply-token
|
||||||
|
"Removes `attributes` that match `token` for `shape-ids`.
|
||||||
|
|
||||||
|
Doesn't update shape attributes."
|
||||||
|
[{:keys [attributes token shape-ids] :as _props}]
|
||||||
|
(ptk/reify ::unapply-token
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(rx/of
|
||||||
|
(let [remove-token #(when % (cft/remove-attributes-for-token attributes token %))]
|
||||||
|
(dwsh/update-shapes
|
||||||
|
shape-ids
|
||||||
|
(fn [shape]
|
||||||
|
(update shape :applied-tokens remove-token))))))))
|
||||||
|
|
||||||
|
(defn toggle-token
|
||||||
|
[{:keys [token shapes]}]
|
||||||
|
(ptk/reify ::on-toggle-token
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(let [{:keys [attributes all-attributes on-update-shape]}
|
||||||
|
(get token-properties (:type token))
|
||||||
|
|
||||||
|
unapply-tokens?
|
||||||
|
(cft/shapes-token-applied? token shapes (or all-attributes attributes))
|
||||||
|
|
||||||
|
shape-ids (map :id shapes)]
|
||||||
|
(if unapply-tokens?
|
||||||
|
(rx/of
|
||||||
|
(unapply-token {:attributes (or all-attributes attributes)
|
||||||
|
:token token
|
||||||
|
:shape-ids shape-ids}))
|
||||||
|
(rx/of
|
||||||
|
(case (:type token)
|
||||||
|
:spacing
|
||||||
|
(apply-spacing-token {:token token
|
||||||
|
:shapes shapes})
|
||||||
|
(apply-token {:attributes attributes
|
||||||
|
:token token
|
||||||
|
:shape-ids shape-ids
|
||||||
|
:on-update-shape on-update-shape}))))))))
|
||||||
|
|
||||||
;; Map token types to different properties used along the cokde ---------------------------------------------
|
;; Map token types to different properties used along the cokde ---------------------------------------------
|
||||||
|
|
||||||
;; FIXME: the values should be lazy evaluated, probably a function,
|
;; FIXME: the values should be lazy evaluated, probably a function,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.types.shape.layout :as ctsl]
|
||||||
[app.common.types.token :as ctt]
|
[app.common.types.token :as ctt]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
@ -61,6 +62,10 @@
|
||||||
(mf/with-memo [selected objects]
|
(mf/with-memo [selected objects]
|
||||||
(into [] (keep (d/getf objects)) selected))
|
(into [] (keep (d/getf objects)) selected))
|
||||||
|
|
||||||
|
is-selected-inside-layout
|
||||||
|
(mf/with-memo [selected-shapes objects]
|
||||||
|
(some #(ctsl/any-layout-immediate-child? objects %) selected-shapes))
|
||||||
|
|
||||||
active-theme-tokens
|
active-theme-tokens
|
||||||
(mf/with-memo [tokens-lib]
|
(mf/with-memo [tokens-lib]
|
||||||
(if tokens-lib
|
(if tokens-lib
|
||||||
|
@ -148,6 +153,7 @@
|
||||||
:is-open (get open-status type false)
|
:is-open (get open-status type false)
|
||||||
:type type
|
:type type
|
||||||
:selected-shapes selected-shapes
|
:selected-shapes selected-shapes
|
||||||
|
:is-selected-inside-layout is-selected-inside-layout
|
||||||
:active-theme-tokens active-theme-tokens'
|
:active-theme-tokens active-theme-tokens'
|
||||||
:tokens tokens}]))
|
:tokens tokens}]))
|
||||||
|
|
||||||
|
@ -155,5 +161,6 @@
|
||||||
[:> token-group* {:key (name type)
|
[:> token-group* {:key (name type)
|
||||||
:type type
|
:type type
|
||||||
:selected-shapes selected-shapes
|
:selected-shapes selected-shapes
|
||||||
|
:is-selected-inside-layout :is-selected-inside-layout
|
||||||
:active-theme-tokens active-theme-tokens'
|
:active-theme-tokens active-theme-tokens'
|
||||||
:tokens []}])]))
|
:tokens []}])]))
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.files.tokens :as cft]
|
[app.common.files.tokens :as cft]
|
||||||
|
[app.common.types.shape.layout :as ctsl]
|
||||||
[app.common.types.token :as ctt]
|
[app.common.types.token :as ctt]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
@ -34,11 +35,13 @@
|
||||||
(some #(contains? m %) ks))
|
(some #(contains? m %) ks))
|
||||||
|
|
||||||
(defn clean-separators
|
(defn clean-separators
|
||||||
"Cleans up `:separator` inside of `items`
|
"Cleans up `:separator` inside of `items` with these rules:
|
||||||
Will clean consecutive items like `[:separator :separator {}]`
|
- Clean consecutive items like `[:separator :separator {}]`
|
||||||
And will return nil for lists consisting only of `:separator` items."
|
- Returns nil for lists consisting only of `:separator` items.
|
||||||
|
- Removes `:separator` at the beginning of the `items`"
|
||||||
[items]
|
[items]
|
||||||
(let [items' (dedupe items)]
|
(let [items' (->> (dedupe items)
|
||||||
|
(drop-while #(= % :separator)))]
|
||||||
(when-not (every? #(= % :separator) items')
|
(when-not (every? #(= % :separator) items')
|
||||||
items')))
|
items')))
|
||||||
|
|
||||||
|
@ -190,7 +193,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn spacing-attribute-actions [{:keys [token selected-shapes allowed-shape-attributes] :as context-data}]
|
(defn spacing-attribute-actions [{:keys [token selected-shapes allowed-shape-attributes is-selected-inside-layout] :as context-data}]
|
||||||
(let [padding-attr-labels {:p1 "Padding top"
|
(let [padding-attr-labels {:p1 "Padding top"
|
||||||
:p2 "Padding right"
|
:p2 "Padding right"
|
||||||
:p3 "Padding bottom"
|
:p3 "Padding bottom"
|
||||||
|
@ -209,7 +212,9 @@
|
||||||
:m2 "Margin right"
|
:m2 "Margin right"
|
||||||
:m3 "Margin bottom"
|
:m3 "Margin bottom"
|
||||||
:m4 "Margin left"}
|
:m4 "Margin left"}
|
||||||
margin-items (when (key-in-map? allowed-shape-attributes margin-attr-labels)
|
margin-items (when (or
|
||||||
|
is-selected-inside-layout
|
||||||
|
(key-in-map? allowed-shape-attributes margin-attr-labels))
|
||||||
(layout-spacing-items {:token token
|
(layout-spacing-items {:token token
|
||||||
:selected-shapes selected-shapes
|
:selected-shapes selected-shapes
|
||||||
:all-attr-labels margin-attr-labels
|
:all-attr-labels margin-attr-labels
|
||||||
|
@ -224,11 +229,13 @@
|
||||||
:hint (tr "workspace.tokens.gaps")
|
:hint (tr "workspace.tokens.gaps")
|
||||||
:on-update-shape dwta/update-layout-spacing}
|
:on-update-shape dwta/update-layout-spacing}
|
||||||
context-data)]
|
context-data)]
|
||||||
(concat gap-items
|
(->> (concat
|
||||||
(when padding-items [:separator])
|
gap-items
|
||||||
padding-items
|
[:separator]
|
||||||
(when margin-items [:separator])
|
padding-items
|
||||||
margin-items)))
|
[:separator]
|
||||||
|
margin-items)
|
||||||
|
(clean-separators))))
|
||||||
|
|
||||||
(defn sizing-attribute-actions [context-data]
|
(defn sizing-attribute-actions [context-data]
|
||||||
(->>
|
(->>
|
||||||
|
@ -446,9 +453,17 @@
|
||||||
|
|
||||||
(mf/defc token-context-menu-tree
|
(mf/defc token-context-menu-tree
|
||||||
[{:keys [width errors] :as mdata}]
|
[{:keys [width errors] :as mdata}]
|
||||||
(let [objects (mf/deref refs/workspace-page-objects)
|
(let [objects (mf/deref refs/workspace-page-objects)
|
||||||
selected (mf/deref refs/selected-shapes)
|
selected (mf/deref refs/selected-shapes)
|
||||||
selected-shapes (into [] (keep (d/getf objects)) selected)
|
|
||||||
|
selected-shapes
|
||||||
|
(mf/with-memo [selected objects]
|
||||||
|
(into [] (keep (d/getf objects)) selected))
|
||||||
|
|
||||||
|
is-selected-inside-layout
|
||||||
|
(mf/with-memo [selected-shapes objects]
|
||||||
|
(some #(ctsl/any-layout-immediate-child? objects %) selected-shapes))
|
||||||
|
|
||||||
token-name (:token-name mdata)
|
token-name (:token-name mdata)
|
||||||
token (mf/deref (refs/workspace-token-in-selected-set token-name))
|
token (mf/deref (refs/workspace-token-in-selected-set token-name))
|
||||||
selected-token-set-name (mf/deref refs/selected-token-set-name)]
|
selected-token-set-name (mf/deref refs/selected-token-set-name)]
|
||||||
|
@ -457,7 +472,8 @@
|
||||||
:token token
|
:token token
|
||||||
:errors errors
|
:errors errors
|
||||||
:selected-token-set-name selected-token-set-name
|
:selected-token-set-name selected-token-set-name
|
||||||
:selected-shapes selected-shapes}]]))
|
:selected-shapes selected-shapes
|
||||||
|
:is-selected-inside-layout is-selected-inside-layout}]]))
|
||||||
|
|
||||||
(mf/defc token-context-menu
|
(mf/defc token-context-menu
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
(mf/defc token-group*
|
(mf/defc token-group*
|
||||||
{::mf/private true}
|
{::mf/private true}
|
||||||
[{:keys [type tokens selected-shapes active-theme-tokens is-open]}]
|
[{:keys [type tokens selected-shapes is-selected-inside-layout active-theme-tokens is-open]}]
|
||||||
(let [{:keys [modal title]}
|
(let [{:keys [modal title]}
|
||||||
(get dwta/token-properties type)
|
(get dwta/token-properties type)
|
||||||
editing-ref (mf/deref refs/workspace-editor-state)
|
editing-ref (mf/deref refs/workspace-editor-state)
|
||||||
|
@ -115,6 +115,7 @@
|
||||||
{:key (:name token)
|
{:key (:name token)
|
||||||
:token token
|
:token token
|
||||||
:selected-shapes selected-shapes
|
:selected-shapes selected-shapes
|
||||||
|
:is-selected-inside-layout is-selected-inside-layout
|
||||||
:active-theme-tokens active-theme-tokens
|
:active-theme-tokens active-theme-tokens
|
||||||
:on-click on-token-pill-click
|
:on-click on-token-pill-click
|
||||||
:on-context-menu on-context-menu}])]])]]))
|
:on-context-menu on-context-menu}])]])]]))
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
[app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon*]]
|
[app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon*]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
|
[clojure.set :as set]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
@ -164,17 +165,20 @@
|
||||||
(cft/shapes-applied-all? ids-by-attributes shape-ids attributes)))
|
(cft/shapes-applied-all? ids-by-attributes shape-ids attributes)))
|
||||||
|
|
||||||
(defn attributes-match-selection?
|
(defn attributes-match-selection?
|
||||||
[selected-shapes attrs]
|
[selected-shapes attrs & {:keys [selected-inside-layout?]}]
|
||||||
(some (fn [shape]
|
(or
|
||||||
(ctt/any-appliable-attr? attrs (:type shape)))
|
;; Edge-case for allowing margin attribute on shapes inside layout parent
|
||||||
selected-shapes))
|
(and selected-inside-layout? (set/subset? ctt/spacing-margin-keys attrs))
|
||||||
|
(some (fn [shape]
|
||||||
|
(ctt/any-appliable-attr? attrs (:type shape)))
|
||||||
|
selected-shapes)))
|
||||||
|
|
||||||
(def token-types-with-status-icon
|
(def token-types-with-status-icon
|
||||||
#{:color :border-radius :rotation :sizing :dimensions :opacity :spacing :stroke-width})
|
#{:color :border-radius :rotation :sizing :dimensions :opacity :spacing :stroke-width})
|
||||||
|
|
||||||
(mf/defc token-pill*
|
(mf/defc token-pill*
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [on-click token on-context-menu selected-shapes active-theme-tokens]}]
|
[{:keys [on-click token on-context-menu selected-shapes is-selected-inside-layout active-theme-tokens]}]
|
||||||
(let [{:keys [name value errors type]} token
|
(let [{:keys [name value errors type]} token
|
||||||
|
|
||||||
has-selected? (pos? (count selected-shapes))
|
has-selected? (pos? (count selected-shapes))
|
||||||
|
@ -201,7 +205,7 @@
|
||||||
has-selected?
|
has-selected?
|
||||||
(not applied?)
|
(not applied?)
|
||||||
(not half-applied?)
|
(not half-applied?)
|
||||||
(not (attributes-match-selection? selected-shapes attributes)))
|
(not (attributes-match-selection? selected-shapes attributes {:selected-inside-layout? is-selected-inside-layout})))
|
||||||
|
|
||||||
;; FIXME: move to context or props
|
;; FIXME: move to context or props
|
||||||
can-edit? (:can-edit (deref refs/permissions))
|
can-edit? (:can-edit (deref refs/permissions))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue