Merge pull request #7182 from penpot/niwinz-measures-menu-changes

♻️ Add efficiency refactor for sidebar
This commit is contained in:
Andrey Antukh 2025-08-28 08:40:44 +02:00 committed by GitHub
commit bf1e26c4e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 987 additions and 665 deletions

View File

@ -517,7 +517,7 @@
([objects id] ([objects id]
(item-absolute? (get objects id))) (item-absolute? (get objects id)))
([shape] ([shape]
(true? (:layout-item-absolute shape)))) (true? (get shape :layout-item-absolute))))
(defn position-absolute? (defn position-absolute?
([objects id] ([objects id]

View File

@ -30,7 +30,20 @@
(def workspace-read-only? (mf/create-context nil)) (def workspace-read-only? (mf/create-context nil))
(def is-component? (mf/create-context false)) (def is-component? (mf/create-context false))
(def sidebar (mf/create-context nil))
(def sidebar
"A context that intends to store the current sidebar position,
usefull for components that behaves distinctly if they are showed in
right sidebar or left sidebar.
Possible values: `:right:` and `:left`."
(mf/create-context nil))
(def permissions (mf/create-context nil)) (def permissions (mf/create-context nil))
(def can-edit? (mf/create-context nil)) (def can-edit? (mf/create-context nil))
(def active-tokens-by-type
"Active tokens by type, used mainly for provide tokens data to the
right sidebar menu options components."
(mf/create-context nil))

View File

@ -65,14 +65,17 @@
(defn- get-option-by-name (defn- get-option-by-name
[options name] [options name]
(d/seek #(= name (get % :name)) options)) (let [options (if (delay? options) (deref options) options)]
(d/seek #(= name (get % :name)) options)))
(defn- get-token-op (defn- get-token-op
[tokens name] [tokens name]
(->> tokens (let [tokens (if (delay? tokens) @tokens tokens)
vals xform (filter #(= (:name %) name))]
(apply concat) (reduce-kv (fn [result _ tokens]
(some #(when (= (:name %) name) %)))) (into result xform tokens))
[]
tokens)))
(defn- clean-token-name (defn- clean-token-name
[s] [s]
@ -114,14 +117,14 @@
(subs s (inc start)))) (subs s (inc start))))
(defn- filter-token-groups-by-name (defn- filter-token-groups-by-name
[tokens-by-type filter-text] [tokens filter-text]
(let [lc-filter (str/lower filter-text)] (let [lc-filter (str/lower filter-text)]
(into {} (into {}
(keep (fn [[group tokens]] (keep (fn [[group tokens]]
(let [filtered (filter #(str/includes? (str/lower (:name %)) lc-filter) tokens)] (let [filtered (filter #(str/includes? (str/lower (:name %)) lc-filter) tokens)]
(when (seq filtered) (when (seq filtered)
[group filtered])))) [group filtered]))))
tokens-by-type))) tokens)))
(defn- focusable-option? (defn- focusable-option?
[option] [option]
@ -183,7 +186,9 @@
is-selected-on-focus nillable is-selected-on-focus nillable
tokens applied-token empty-to-end tokens applied-token empty-to-end
on-change on-blur on-focus on-detach on-change on-blur on-focus on-detach
property align ref] :rest props}] property align ref]
:rest props}]
(let [;; NOTE: we use mfu/bean here for transparently handle (let [;; NOTE: we use mfu/bean here for transparently handle
;; options provide as clojure data structures or javascript ;; options provide as clojure data structures or javascript
;; plain objects and lists. ;; plain objects and lists.
@ -253,12 +258,14 @@
dropdown-options dropdown-options
(mf/with-memo [tokens filter-id] (mf/with-memo [tokens filter-id]
(let [partial (extract-partial-brace-text filter-id) (delay
options (if (seq partial) (let [tokens (if (delay? tokens) @tokens tokens)
(filter-token-groups-by-name tokens partial) partial (extract-partial-brace-text filter-id)
tokens) options (if (seq partial)
no-sets? (nil? tokens)] (filter-token-groups-by-name tokens partial)
(generate-dropdown-options options no-sets?))) tokens)
no-sets? (nil? tokens)]
(generate-dropdown-options options no-sets?))))
selected-id* selected-id*
(mf/use-state (fn [] (mf/use-state (fn []
@ -351,23 +358,27 @@
on-option-click on-option-click
(mf/use-fn (mf/use-fn
(mf/deps dropdown-options on-token-apply) (mf/deps on-token-apply)
(fn [event] (fn [event]
(let [node (dom/get-current-target event) (let [node (dom/get-current-target event)
id (dom/get-data node "id") id (dom/get-data node "id")
option (get-option dropdown-options id) options (mf/ref-val options-ref)
value (get option :resolved-value) options (if (delay? options) @options options)
name (get option :name)] option (get-option options id)
value (get option :resolved-value)
name (get option :name)]
(on-token-apply id value name) (on-token-apply id value name)
(reset! filter-id* "")))) (reset! filter-id* ""))))
on-option-enter on-option-enter
(mf/use-fn (mf/use-fn
(mf/deps dropdown-options focused-id on-token-apply) (mf/deps focused-id on-token-apply)
(fn [_] (fn [_]
(let [option (get-option dropdown-options focused-id) (let [options (mf/ref-val options-ref)
value (get option :resolved-value) options (if (delay? options) @options options)
name (get option :name)] option (get-option options focused-id)
value (get option :resolved-value)
name (get option :name)]
(on-token-apply focused-id value name) (on-token-apply focused-id value name)
(reset! filter-id* "")))) (reset! filter-id* ""))))
@ -386,9 +397,9 @@
(when (fn? on-blur) (when (fn? on-blur)
(on-blur event))))) (on-blur event)))))
handle-key-down on-key-down
(mf/use-fn (mf/use-fn
(mf/deps dropdown-options is-open apply-value update-input is-open focused-id handle-focus-change) (mf/deps is-open apply-value update-input is-open focused-id handle-focus-change)
(fn [event] (fn [event]
(mf/set-ref-val! dirty-ref true) (mf/set-ref-val! dirty-ref true)
(let [up? (kbd/up-arrow? event) (let [up? (kbd/up-arrow? event)
@ -398,7 +409,8 @@
node (mf/ref-val ref) node (mf/ref-val ref)
open-tokens (kbd/is-key? event "{") open-tokens (kbd/is-key? event "{")
close-tokens (kbd/is-key? event "}") close-tokens (kbd/is-key? event "}")
options (mf/ref-val options-ref)] options (mf/ref-val options-ref)
options (if (delay? options) @options options)]
(cond (cond
(and (some? options) open-tokens) (and (some? options) open-tokens)
@ -418,8 +430,8 @@
(dom/prevent-default event) (dom/prevent-default event)
(if focused-id (if focused-id
(on-option-enter event) (on-option-enter event)
(let [option-id (first-focusable-id dropdown-options) (let [option-id (first-focusable-id options)
option (get-option dropdown-options option-id) option (get-option options option-id)
value (get option :resolved-value) value (get option :resolved-value)
name (get option :name)] name (get option :name)]
(on-token-apply option-id value name) (on-token-apply option-id value name)
@ -461,7 +473,7 @@
(update-input (fmt/format-number new-val)) (update-input (fmt/format-number new-val))
(apply-value (dm/str new-val)))))))) (apply-value (dm/str new-val))))))))
handle-focus on-focus
(mf/use-fn (mf/use-fn
(mf/deps on-focus select-on-focus) (mf/deps on-focus select-on-focus)
(fn [event] (fn [event]
@ -473,7 +485,7 @@
;; In webkit browsers the mouseup event will be called after the on-focus causing and unselect ;; In webkit browsers the mouseup event will be called after the on-focus causing and unselect
(.addEventListener target "mouseup" dom/prevent-default #js {:once true}))))) (.addEventListener target "mouseup" dom/prevent-default #js {:once true})))))
handle-mouse-wheel on-mouse-wheel
(mf/use-fn (mf/use-fn
(mf/deps apply-value parse-value min max nillable ref default step min max) (mf/deps apply-value parse-value min max nillable ref default step min max)
(fn [event] (fn [event]
@ -580,8 +592,8 @@
placeholder) placeholder)
:default-value (or (mf/ref-val last-value*) (fmt/format-number value)) :default-value (or (mf/ref-val last-value*) (fmt/format-number value))
:on-blur on-blur :on-blur on-blur
:on-key-down handle-key-down :on-key-down on-key-down
:on-focus handle-focus :on-focus on-focus
:on-change store-raw-value :on-change store-raw-value
:disabled disabled :disabled disabled
:slot-start (when icon :slot-start (when icon
@ -603,11 +615,12 @@
token-props token-props
(when (and token-applied (not= :multiple token-applied)) (when (and token-applied (not= :multiple token-applied))
(let [token (get-option-by-name dropdown-options token-applied) (let [token (get-option-by-name dropdown-options token-applied)
id (get token :id) id (get token :id)
label (get token :name) label (get token :name)
token-value (or (get token :resolved-value) token-value (or (get token :resolved-value)
(or (mf/ref-val last-value*) (fmt/format-number value)))] (or (mf/ref-val last-value*)
(fmt/format-number value)))]
(mf/spread-props props (mf/spread-props props
{:id id {:id id
:label label :label label
@ -649,9 +662,9 @@
(when-let [node (mf/ref-val ref)] (when-let [node (mf/ref-val ref)]
(dom/set-value! node value')))) (dom/set-value! node value'))))
(mf/with-layout-effect [handle-mouse-wheel] (mf/with-layout-effect [on-mouse-wheel]
(when-let [node (mf/ref-val ref)] (when-let [node (mf/ref-val ref)]
(let [key (events/listen node "wheel" handle-mouse-wheel #js {:passive false})] (let [key (events/listen node "wheel" on-mouse-wheel #js {:passive false})]
#(events/unlistenByKey key)))) #(events/unlistenByKey key))))
(mf/with-effect [dropdown-options] (mf/with-effect [dropdown-options]
@ -666,11 +679,12 @@
[:> input-field* input-props]) [:> input-field* input-props])
(when ^boolean is-open (when ^boolean is-open
[:> options-dropdown* {:on-click on-option-click (let [options (if (delay? dropdown-options) @dropdown-options dropdown-options)]
:id listbox-id [:> options-dropdown* {:on-click on-option-click
:options dropdown-options :id listbox-id
:selected selected-id :options options
:focused focused-id :selected selected-id
:align align :focused focused-id
:empty-to-end empty-to-end :align align
:ref set-option-ref}])])) :empty-to-end empty-to-end
:ref set-option-ref}]))]))

View File

@ -20,8 +20,9 @@
(defn get-option (defn get-option
[options id] [options id]
(or (d/seek #(= id (get % :id)) options) (let [options (if (delay? options) @options options)]
(nth options 0))) (or (d/seek #(= id (get % :id)) options)
(nth options 0))))
(defn- get-selected-option-id (defn- get-selected-option-id
[options default] [options default]

View File

@ -13,8 +13,8 @@ const Padded = ({ children }) => (
<div style={{ padding: "10px" }}>{children}</div> <div style={{ padding: "10px" }}>{children}</div>
); );
const TabSwitcherWrapper = ({tabs, ...props}) => { const TabSwitcherWrapper = ({ tabs, ...props }) => {
const navTabs = tabs.map(({content, ...item}) => { const navTabs = tabs.map(({ content, ...item }) => {
return item; return item;
}); });
@ -28,7 +28,12 @@ const TabSwitcherWrapper = ({tabs, ...props}) => {
}, {}); }, {});
return ( return (
<TabSwitcher tabs={navTabs} selected={selected} onChange={setSelected} {...props}> <TabSwitcher
tabs={navTabs}
selected={selected}
onChange={setSelected}
{...props}
>
{content[selected]} {content[selected]}
</TabSwitcher> </TabSwitcher>
); );
@ -77,12 +82,7 @@ export default {
}, },
parameters: { parameters: {
controls: { controls: {
exclude: [ exclude: ["tabs", "actionButton", "default", "actionButtonPosition"],
"tabs",
"actionButton",
"default",
"actionButtonPosition",
],
}, },
}, },
render: ({ ...args }) => <TabSwitcherWrapper {...args} />, render: ({ ...args }) => <TabSwitcherWrapper {...args} />,

View File

@ -160,11 +160,7 @@
tooltip-brect (assoc tooltip-brect :height (or saved-height (:height tooltip-brect)) :width (or saved-width (:width tooltip-brect))) tooltip-brect (assoc tooltip-brect :height (or saved-height (:height tooltip-brect)) :width (or saved-width (:width tooltip-brect)))
window-size (dom/get-window-size)] window-size (dom/get-window-size)]
(when-let [[placement placement-rect] (find-matching-placement placement tooltip-brect origin-brect window-size offset)] (when-let [[placement placement-rect] (find-matching-placement placement tooltip-brect origin-brect window-size offset)]
(let [height (if (or (= placement "right") (= placement "left")) (let [height (:height placement-rect)]
(- (:height placement-rect) arrow-height)
(:height placement-rect))]
(dom/set-data! tooltip "height" (:height tooltip-brect))
(dom/set-data! tooltip "width" (:width tooltip-brect))
(dom/set-css-property! tooltip "block-size" (dm/str height "px")) (dom/set-css-property! tooltip "block-size" (dm/str height "px"))
(dom/set-css-property! tooltip "inset-block-start" (dm/str (:top placement-rect) "px")) (dom/set-css-property! tooltip "inset-block-start" (dm/str (:top placement-rect) "px"))
(dom/set-css-property! tooltip "inset-inline-start" (dm/str (:left placement-rect) "px"))) (dom/set-css-property! tooltip "inset-inline-start" (dm/str (:left placement-rect) "px")))
@ -253,7 +249,7 @@
:on-focus on-show :on-focus on-show
:on-blur on-hide :on-blur on-hide
:on-key-down handle-key-down :on-key-down handle-key-down
:class (stl/css :tooltip-trigger) :class [class (stl/css :tooltip-trigger)]
:aria-describedby id}) :aria-describedby id})
content content
(if (fn? content) (if (fn? content)
@ -262,7 +258,7 @@
[:> :div props [:> :div props
children children
[:div {:class [class (stl/css :tooltip)] [:div {:class (stl/css :tooltip)
:id id :id id
:popover "auto" :popover "auto"
:role "tooltip"} :role "tooltip"}

View File

@ -29,8 +29,7 @@
[app.main.ui.workspace.nudge] [app.main.ui.workspace.nudge]
[app.main.ui.workspace.palette :refer [palette]] [app.main.ui.workspace.palette :refer [palette]]
[app.main.ui.workspace.plugins] [app.main.ui.workspace.plugins]
[app.main.ui.workspace.sidebar :refer [left-sidebar* right-sidebar*]] [app.main.ui.workspace.sidebar :refer [sidebar*]]
[app.main.ui.workspace.sidebar.collapsable-button :refer [collapsed-button]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]] [app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
[app.main.ui.workspace.tokens.export] [app.main.ui.workspace.tokens.export]
[app.main.ui.workspace.tokens.export.modal] [app.main.ui.workspace.tokens.export.modal]
@ -114,18 +113,14 @@
@palete-size)}]]] @palete-size)}]]]
(when-not hide-ui? (when-not hide-ui?
[:* [:> sidebar* {:layout layout
(if (:collapse-left-sidebar layout) ;; FIXME
[:& collapsed-button] :file-id (get file :id)
[:> left-sidebar* {:layout layout :page-id page-id
:file file :file file
:page-id page-id}]) :selected selected
[:> right-sidebar* {:section options-mode :section options-mode
:selected selected :drawing-tool (get drawing :tool)}])]))
:drawing-tool (get drawing :tool)
:layout layout
:file file
:page-id page-id}]])]))
(mf/defc workspace-loader* (mf/defc workspace-loader*
{::mf/private true} {::mf/private true}

View File

@ -8,9 +8,11 @@
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.types.tokens-lib :as ctob]
[app.main.constants :refer [sidebar-default-width sidebar-default-max-width]] [app.main.constants :refer [sidebar-default-width sidebar-default-max-width]]
[app.main.data.common :as dcm] [app.main.data.common :as dcm]
[app.main.data.event :as ev] [app.main.data.event :as ev]
[app.main.data.style-dictionary :as sd]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.features :as features] [app.main.features :as features]
[app.main.refs :as refs] [app.main.refs :as refs]
@ -25,6 +27,7 @@
[app.main.ui.workspace.left-header :refer [left-header*]] [app.main.ui.workspace.left-header :refer [left-header*]]
[app.main.ui.workspace.right-header :refer [right-header*]] [app.main.ui.workspace.right-header :refer [right-header*]]
[app.main.ui.workspace.sidebar.assets :refer [assets-toolbox*]] [app.main.ui.workspace.sidebar.assets :refer [assets-toolbox*]]
[app.main.ui.workspace.sidebar.collapsable-button :refer [collapsed-button*]]
[app.main.ui.workspace.sidebar.debug :refer [debug-panel*]] [app.main.ui.workspace.sidebar.debug :refer [debug-panel*]]
[app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info*]] [app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info*]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]] [app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
@ -96,7 +99,7 @@
(mf/defc left-sidebar* (mf/defc left-sidebar*
{::mf/memo true} {::mf/memo true}
[{:keys [layout file page-id] :as props}] [{:keys [layout file page-id tokens-lib active-tokens resolved-active-tokens]}]
(let [options-mode (mf/deref refs/options-mode-global) (let [options-mode (mf/deref refs/options-mode-global)
project (mf/deref refs/project) project (mf/deref refs/project)
file-id (get file :id) file-id (get file :id)
@ -147,7 +150,7 @@
:left-settings-bar true :left-settings-bar true
:global/two-row (<= width 300) :global/two-row (<= width 300)
:global/three-row (and (> width 300) (<= width 400)) :global/three-row (and (> width 300) (<= width 400))
:global/four-row (> width 400)) :global/four-row (> width 400))
tabs-action-button tabs-action-button
(mf/with-memo [] (mf/with-memo []
@ -197,7 +200,10 @@
:file-id file-id}] :file-id file-id}]
:tokens :tokens
[:> tokens-sidebar-tab*] [:> tokens-sidebar-tab*
{:tokens-lib tokens-lib
:active-tokens active-tokens
:resolved-active-tokens resolved-active-tokens}]
:layers :layers
[:> layers-content* [:> layers-content*
@ -255,8 +261,7 @@
[:> history-toolbox*]])])) [:> history-toolbox*]])]))
(mf/defc right-sidebar* (mf/defc right-sidebar*
{::mf/memo true} [{:keys [layout section file page-id drawing-tool active-tokens] :as props}]
[{:keys [layout section file page-id drawing-tool] :as props}]
(let [is-comments? (= drawing-tool :comments) (let [is-comments? (= drawing-tool :comments)
is-history? (contains? layout :document-history) is-history? (contains? layout :document-history)
is-inspect? (= section :inspect) is-inspect? (= section :inspect)
@ -289,45 +294,84 @@
(fn [] (fn []
(set-width (if (> width sidebar-default-width) (set-width (if (> width sidebar-default-width)
sidebar-default-width sidebar-default-width
sidebar-default-max-width))))] sidebar-default-max-width))))
active-tokens-by-type
(mf/with-memo [active-tokens]
(delay (ctob/group-by-type active-tokens)))]
[:> (mf/provider muc/sidebar) {:value :right} [:> (mf/provider muc/sidebar) {:value :right}
[:aside [:> (mf/provider muc/active-tokens-by-type) {:value active-tokens-by-type}
{:class (stl/css-case :right-settings-bar true
:not-expand (not can-be-expanded?)
:expanded (> width sidebar-default-width))
:id "right-sidebar-aside" [:aside
:data-testid "right-sidebar" {:class (stl/css-case :right-settings-bar true
:data-size (str width) :not-expand (not can-be-expanded?)
:style {:--width (if can-be-expanded? :expanded (> width sidebar-default-width))
(dm/str width "px")
(dm/str sidebar-default-width "px"))}}
(when can-be-expanded? :id "right-sidebar-aside"
[:div {:class (stl/css :resize-area) :data-testid "right-sidebar"
:on-pointer-down on-pointer-down :data-size (str width)
:on-lost-pointer-capture on-lost-pointer-capture :style {:--width (if can-be-expanded?
:on-pointer-move on-pointer-move}]) (dm/str width "px")
(dm/str sidebar-default-width "px"))}}
[:> right-header* (when can-be-expanded?
{:file file [:div {:class (stl/css :resize-area)
:layout layout :on-pointer-down on-pointer-down
:page-id page-id}] :on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move}])
[:div {:class (stl/css :settings-bar-inside)} [:> right-header*
(cond {:file file
dbg-shape-panel? :layout layout
[:> debug-shape-info*] :page-id page-id}]
is-comments? [:div {:class (stl/css :settings-bar-inside)}
[:> comments-sidebar* {}] (cond
dbg-shape-panel?
[:> debug-shape-info*]
is-history? is-comments?
[:> history-content* {}] [:> comments-sidebar* {}]
:else is-history?
(let [props (mf/spread-props props [:> history-content* {}]
{:on-change-section on-change-section
:on-expand on-expand})] :else
[:> options-toolbox* props]))]]])) (let [props (mf/spread-props props
{:on-change-section on-change-section
:on-expand on-expand})]
[:> options-toolbox* props]))]]]]))
(mf/defc sidebar*
[{:keys [layout file file-id page-id section drawing-tool selected]}]
(let [tokens-lib
(mf/deref refs/tokens-lib)
active-tokens
(mf/with-memo [tokens-lib]
(if tokens-lib
(ctob/get-tokens-in-active-sets tokens-lib)
{}))
resolved-active-tokens
(sd/use-resolved-tokens* active-tokens)]
[:*
(if (:collapse-left-sidebar layout)
[:> collapsed-button*]
[:> left-sidebar* {:layout layout
:file file
:page-id page-id
:tokens-lib tokens-lib
:active-tokens active-tokens
:resolved-active-tokens resolved-active-tokens}])
[:> right-sidebar* {:section section
:selected selected
:drawing-tool drawing-tool
:layout layout
:file file
:file-id file-id
:page-id page-id
:tokens-lib tokens-lib
:active-tokens resolved-active-tokens}]]))

View File

@ -13,8 +13,8 @@
[app.util.i18n :refer [tr]] [app.util.i18n :refer [tr]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc collapsed-button (mf/defc collapsed-button*
{::mf/wrap-props false} {::mf/memo true}
[] []
(let [on-click (mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))] (let [on-click (mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))]
[:div {:id "left-sidebar-aside" [:div {:id "left-sidebar-aside"

View File

@ -20,8 +20,8 @@
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]] [app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
[app.main.ui.inspect.right-sidebar :as hrs] [app.main.ui.inspect.right-sidebar :as hrs]
[app.main.ui.workspace.sidebar.options.drawing :as drawing] [app.main.ui.workspace.sidebar.options.drawing :as drawing]
[app.main.ui.workspace.sidebar.options.menus.align :refer [align-options]] [app.main.ui.workspace.sidebar.options.menus.align :refer [align-options*]]
[app.main.ui.workspace.sidebar.options.menus.bool :refer [bool-options]] [app.main.ui.workspace.sidebar.options.menus.bool :refer [bool-options*]]
[app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu]] [app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu]] [app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu]]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell] [app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
@ -32,7 +32,6 @@
[app.main.ui.workspace.sidebar.options.shapes.circle :as circle] [app.main.ui.workspace.sidebar.options.shapes.circle :as circle]
[app.main.ui.workspace.sidebar.options.shapes.frame :as frame] [app.main.ui.workspace.sidebar.options.shapes.frame :as frame]
[app.main.ui.workspace.sidebar.options.shapes.group :as group] [app.main.ui.workspace.sidebar.options.shapes.group :as group]
[app.main.ui.workspace.sidebar.options.shapes.image :as image]
[app.main.ui.workspace.sidebar.options.shapes.multiple :as multiple] [app.main.ui.workspace.sidebar.options.shapes.multiple :as multiple]
[app.main.ui.workspace.sidebar.options.shapes.path :as path] [app.main.ui.workspace.sidebar.options.shapes.path :as path]
[app.main.ui.workspace.sidebar.options.shapes.rect :as rect] [app.main.ui.workspace.sidebar.options.shapes.rect :as rect]
@ -57,14 +56,13 @@
[:* [:*
(case shape-type (case shape-type
:frame [:> frame/options* props] :frame [:> frame/options* props]
:group [:& group/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :libraries libraries}] :group [:> group/options* {:shape shape :shape-with-children shapes-with-children :file-id file-id :libraries libraries}]
:text [:& text/options {:shape shape :file-id file-id :libraries libraries}] :text [:> text/options* {:shape shape :file-id file-id :libraries libraries}]
:rect [:& rect/options {:shape shape}] :rect [:> rect/options* {:shape shape}]
:circle [:& circle/options {:shape shape}] :circle [:> circle/options* {:shape shape}]
:path [:& path/options {:shape shape}] :path [:> path/options* {:shape shape}]
:image [:& image/options {:shape shape}] :svg-raw [:> svg-raw/options* {:shape shape}]
:svg-raw [:& svg-raw/options {:shape shape}] :bool [:> bool/options* {:shape shape}]
:bool [:& bool/options {:shape shape}]
nil) nil)
[:& exports-menu [:& exports-menu
{:ids [(:id shape)] {:ids [(:id shape)]
@ -73,7 +71,7 @@
:page-id page-id :page-id page-id
:file-id file-id}]])) :file-id file-id}]]))
(mf/defc specialized-panel (mf/defc specialized-panel*
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [panel]}] [{:keys [panel]}]
(when (= (:type panel) :component-swap) (when (= (:type panel) :component-swap)
@ -92,8 +90,8 @@
(map #(dm/get-in objects [edition :layout-grid-cells %])))] (map #(dm/get-in objects [edition :layout-grid-cells %])))]
[:div {:class (stl/css :element-options :design-options)} [:div {:class (stl/css :element-options :design-options)}
[:& align-options] [:> align-options*]
[:& bool-options] [:> bool-options*]
(cond (cond
(and edit-grid? (d/not-empty? selected-cells)) (and edit-grid? (d/not-empty? selected-cells))
@ -107,7 +105,7 @@
:values (get objects edition)}] :values (get objects edition)}]
(not (nil? sp-panel)) (not (nil? sp-panel))
[:& specialized-panel {:panel sp-panel}] [:> specialized-panel* {:panel sp-panel}]
(d/not-empty? drawing) (d/not-empty? drawing)
[:> drawing/drawing-options* [:> drawing/drawing-options*
@ -125,7 +123,7 @@
:shapes-with-children shapes-with-children}] :shapes-with-children shapes-with-children}]
:else :else
[:& multiple/options [:> multiple/options*
{:shapes-with-children shapes-with-children {:shapes-with-children shapes-with-children
:shapes selected-shapes :shapes selected-shapes
:page-id page-id :page-id page-id
@ -210,12 +208,9 @@
(mf/defc options-toolbox* (mf/defc options-toolbox*
{::mf/memo true} {::mf/memo true}
[{:keys [section selected on-change-section on-expand]}] [{:keys [page-id file-id section selected on-change-section on-expand]}]
(let [page-id (mf/use-ctx ctx/current-page-id) (let [shapes (mf/deref refs/selected-objects)
file-id (mf/use-ctx ctx/current-file-id)
shapes (mf/deref refs/selected-objects)
shapes-with-children (mf/deref refs/selected-shapes-with-children)] shapes-with-children (mf/deref refs/selected-shapes-with-children)]
[:> options-content* {:shapes shapes [:> options-content* {:shapes shapes
:selected selected :selected selected
:shapes-with-children shapes-with-children :shapes-with-children shapes-with-children

View File

@ -16,7 +16,8 @@
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc align-options (mf/defc align-options*
{::mf/memo true}
[] []
(let [selected (mf/deref refs/selected-shapes) (let [selected (mf/deref refs/selected-shapes)
;; don't need to watch objects, only read the value ;; don't need to watch objects, only read the value

View File

@ -22,7 +22,8 @@
(def ^:private flatten-icon (def ^:private flatten-icon
(i/icon-xref :boolean-flatten (stl/css :flatten-icon))) (i/icon-xref :boolean-flatten (stl/css :flatten-icon)))
(mf/defc bool-options (mf/defc bool-options*
{::mf/memo true}
[] []
(let [selected (mf/deref refs/selected-objects) (let [selected (mf/deref refs/selected-objects)
head (first selected) head (first selected)

View File

@ -8,6 +8,8 @@
(: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.data.macros :as dm]
[app.common.geom.rect :as grc]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.logic.shapes :as cls] [app.common.logic.shapes :as cls]
[app.common.types.shape :as cts] [app.common.types.shape :as cts]
@ -25,7 +27,6 @@
[app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [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.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :as ds-i] [app.main.ui.ds.foundations.assets.icon :as ds-i]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.options.menus.border-radius :refer [border-radius-menu*]] [app.main.ui.workspace.sidebar.options.menus.border-radius :refer [border-radius-menu*]]
[app.util.dom :as dom] [app.util.dom :as dom]
@ -61,7 +62,6 @@
:circle generic-options :circle generic-options
:frame frame-options :frame frame-options
:group generic-options :group generic-options
:image rect-options
:path generic-options :path generic-options
:rect rect-options :rect rect-options
:svg-raw generic-options :svg-raw generic-options
@ -87,92 +87,139 @@
shape)] shape)]
(select-keys shape measure-attrs))) (select-keys shape measure-attrs)))
(def ^:private xf:map-type (map :type))
(def ^:private xf:mapcat-type-to-options (mapcat type->options))
(mf/defc measures-menu* (mf/defc measures-menu*
{::mf/props :obj {::mf/memo true}
::mf/wrap [mf/memo]} [{:keys [ids ids-with-children values type shapes]}]
[{:keys [ids ids-with-children values type all-types shape]}] (let [all-types
(let [options (mf/with-memo [type shapes]
;; We only need this when multiple type is used
(when (= type :multiple)
(into #{} xf:map-type shapes)))
options
(mf/with-memo [type all-types] (mf/with-memo [type all-types]
(if (= type :multiple) (if (= type :multiple)
(into #{} (mapcat type->options) all-types) (into #{} xf:mapcat-type-to-options all-types)
(type->options type))) (type->options type)))
ids-with-children ids-with-children
(or ids-with-children ids) (d/nilv ids-with-children ids)
old-shapes
(if (= type :multiple)
(deref (refs/objects-by-id ids))
[shape])
frames frames
(map #(deref (refs/object-by-id (:frame-id %))) old-shapes) (mf/with-memo [shapes]
(let [objects (deref refs/workspace-page-objects)]
(into [] (comp (keep :frame-id)
(map (d/getf objects)))
shapes)))
ids (hooks/use-equal-memo ids) selection-parents-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
selection-parents-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) selection-parents
selection-parents (mf/deref selection-parents-ref) (mf/deref selection-parents-ref)
flex-child? (->> selection-parents (some ctl/flex-layout?)) shape
absolute? (ctl/item-absolute? shape) (first shapes)
flex-container? (ctl/flex-layout? shape)
flex-auto-width? (ctl/auto-width? shape)
flex-fill-width? (ctl/fill-width? shape)
flex-auto-height? (ctl/auto-height? shape)
flex-fill-height? (ctl/fill-height? shape)
disabled-position-x? (and flex-child? (not absolute?)) flex-child?
disabled-position-y? (and flex-child? (not absolute?)) (some ctl/flex-layout? selection-parents)
disabled-width-sizing? (and (or flex-child? flex-container?)
(or flex-auto-width? flex-fill-width?) absolute?
(not absolute?)) (ctl/item-absolute? shape)
disabled-height-sizing? (and (or flex-child? flex-container?)
(or flex-auto-height? flex-fill-height?) flex-container?
(not absolute?)) (ctl/flex-layout? shape)
flex-auto-width?
(ctl/auto-width? shape)
flex-fill-width?
(ctl/fill-width? shape)
flex-auto-height?
(ctl/auto-height? shape)
flex-fill-height?
(ctl/fill-height? shape)
disabled-position?
(and flex-child? (not absolute?))
disabled-width-sizing?
(and (or flex-child? flex-container?)
(or flex-auto-width? flex-fill-width?)
(not absolute?))
disabled-height-sizing?
(and (or flex-child? flex-container?)
(or flex-auto-height? flex-fill-height?)
(not absolute?))
;; To show interactively the measures while the user is manipulating ;; To show interactively the measures while the user is manipulating
;; the shape with the mouse, generate a copy of the shapes applying ;; the shape with the mouse, generate a copy of the shapes applying
;; the transient transformations. ;; the transient transformations.
shapes (as-> old-shapes $ shapes
(map gsh/translate-to-frame $ frames)) (mf/with-memo [shapes frames]
(map gsh/translate-to-frame shapes frames))
;; We repeatedly obtain the first shape after the
;; transformation.
shape
(first shapes)
;; For rotated or stretched shapes, the origin point we show in the menu ;; For rotated or stretched shapes, the origin point we show in the menu
;; is not the (:x :y) shape attribute, but the top left coordinate of the ;; is not the (:x :y) shape attribute, but the top left coordinate of the
;; wrapping rectangle. ;; wrapping rectangle.
values (let [{:keys [x y]} (gsh/shapes->rect [(first shapes)])] values
(cond-> values (let [rect (-> (get shape :points)
(not= (:x values) :multiple) (assoc :x x) (grc/points->rect))
(not= (:y values) :multiple) (assoc :y y) val-x (get values :x)
;; In case of multiple selection, the origin point has been already val-y (get values :y)]
;; calculated and given in the fake :ox and :oy attributes. See (cond-> values
;; common/src/app/common/attrs.cljc (not= val-x :multiple) (assoc :x (dm/get-prop rect :x))
(and (= (:x values) :multiple) (not= val-y :multiple) (assoc :y (dm/get-prop rect :y))
(some? (:ox values))) (assoc :x (:ox values)) ;; In case of multiple selection, the origin point has been already
(and (= (:y values) :multiple) ;; calculated and given in the fake :ox and :oy attributes. See
(some? (:oy values))) (assoc :y (:oy values)))) ;; common/src/app/common/attrs.cljc
(and (= val-x :multiple)
(some? (:ox values)))
(assoc :x (:ox values))
(and (= val-y :multiple)
(some? (:oy values)))
(assoc :y (:oy values))))
;; For :height and :width we take those in the :selrect attribute, because ;; For :height and :width we take those in the :selrect attribute, because
;; not all shapes have an own :width and :height (e. g. paths). Here the ;; not all shapes have an own :width and :height (e. g. paths). Here the
;; rotation is ignored (selrect always has the original size excluding ;; rotation is ignored (selrect always has the original size excluding
;; transforms). ;; transforms).
values (let [{:keys [width height]} (-> shapes first :selrect)] values
(cond-> values (let [selrect (get shape :selrect)
(not= (:width values) :multiple) (assoc :width width) rotation (get shape :rotation 0)]
(not= (:height values) :multiple) (assoc :height height))) (cond-> values
(not= (:width values) :multiple) (assoc :width (dm/get-prop selrect :width))
(not= (:height values) :multiple) (assoc :height (dm/get-prop selrect :height))
(not= (:rotation values) :multiple) (assoc :rotation rotation)))
;; The :rotation, however, does use the transforms. proportion-lock
values (let [{:keys [rotation] :or {rotation 0}} (-> shapes first)] (get values :proportion-lock)
(cond-> values
(not= (:rotation values) :multiple) (assoc :rotation rotation)))
proportion-lock (:proportion-lock values) clip-content-ref
(mf/use-ref nil)
clip-content-ref (mf/use-ref nil) show-in-viewer-ref
show-in-viewer-ref (mf/use-ref nil) (mf/use-ref nil)
;; PRESETS ;; PRESETS
preset-state* (mf/use-state false) preset-state*
show-presets-dropdown? (deref preset-state*) (mf/use-state false)
show-presets-dropdown?
(deref preset-state*)
open-presets open-presets
(mf/use-fn (mf/use-fn
@ -254,10 +301,17 @@
(st/emit! (udw/trigger-bounding-box-cloaking ids) (st/emit! (udw/trigger-bounding-box-cloaking ids)
(udw/increase-rotation ids value))))) (udw/increase-rotation ids value)))))
on-width-change #(on-size-change % :width) on-width-change
on-height-change #(on-size-change % :height) (mf/use-fn (mf/deps on-size-change) #(on-size-change % :width))
on-pos-x-change #(on-position-change % :x)
on-pos-y-change #(on-position-change % :y) on-height-change
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :height))
on-pos-x-change
(mf/use-fn (mf/deps on-position-change) #(on-position-change % :x))
on-pos-y-change
(mf/use-fn (mf/deps on-position-change) #(on-position-change % :y))
;; CLIP CONTENT AND SHOW IN VIEWER ;; CLIP CONTENT AND SHOW IN VIEWER
on-change-clip-content on-change-clip-content
@ -277,9 +331,9 @@
(dwsh/update-shapes ids (fn [shape] (cls/change-show-in-viewer shape (not value))))) (dwsh/update-shapes ids (fn [shape] (cls/change-show-in-viewer shape (not value)))))
(when-not value (when-not value
;; when a frame is no longer shown in view mode, cannot have ;; when a frame is no longer shown in view mode, cannot
;; interactions that navigate to it. ;; have interactions that navigate to it.
(apply st/emit! (map #(dwi/remove-all-interactions-nav-to %) ids))) (run! st/emit! (map #(dwi/remove-all-interactions-nav-to %) ids)))
(st/emit! (dwu/commit-undo-transaction undo-id))))) (st/emit! (dwu/commit-undo-transaction undo-id)))))
@ -373,27 +427,28 @@
(when (options :position) (when (options :position)
[:div {:class (stl/css :position)} [:div {:class (stl/css :position)}
[:div {:class (stl/css-case :x-position true [:div {:class (stl/css-case :x-position true
:disabled disabled-position-x?) :disabled disabled-position?)
:title (tr "workspace.options.x")} :title (tr "workspace.options.x")}
[:span {:class (stl/css :icon-text)} "X"] [:span {:class (stl/css :icon-text)} "X"]
[:> numeric-input* {:no-validate true [:> numeric-input* {:no-validate true
:placeholder (if (= :multiple (:x values)) (tr "settings.multiple") "--") :placeholder (if (= :multiple (:x values)) (tr "settings.multiple") "--")
:on-change on-pos-x-change :on-change on-pos-x-change
:disabled disabled-position-x? :disabled disabled-position?
:class (stl/css :numeric-input) :class (stl/css :numeric-input)
:value (:x values)}]] :value (:x values)}]]
[:div {:class (stl/css-case :y-position true [:div {:class (stl/css-case :y-position true
:disabled disabled-position-y?) :disabled disabled-position?)
:title (tr "workspace.options.y")} :title (tr "workspace.options.y")}
[:span {:class (stl/css :icon-text)} "Y"] [:span {:class (stl/css :icon-text)} "Y"]
[:> numeric-input* {:no-validate true [:> numeric-input* {:no-validate true
:placeholder (if (= :multiple (:y values)) (tr "settings.multiple") "--") :placeholder (if (= :multiple (:y values)) (tr "settings.multiple") "--")
:disabled disabled-position-y? :disabled disabled-position?
:on-change on-pos-y-change :on-change on-pos-y-change
:class (stl/css :numeric-input) :class (stl/css :numeric-input)
:value (:y values)}]]]) :value (:y values)}]]])
(when (or (options :rotation) (options :radius)) (when (or (options :rotation)
(options :radius))
[:div {:class (stl/css :rotation-radius)} [:div {:class (stl/css :rotation-radius)}
(when (options :rotation) (when (options :rotation)
[:div {:class (stl/css :rotation) [:div {:class (stl/css :rotation)
@ -409,7 +464,11 @@
:class (stl/css :numeric-input) :class (stl/css :numeric-input)
:value (:rotation values)}]]) :value (:rotation values)}]])
(when (options :radius) (when (options :radius)
[:> border-radius-menu* {:class (stl/css :border-radius) :ids ids :ids-with-children ids-with-children :values values :shape shape}])]) [:> border-radius-menu* {:class (stl/css :border-radius)
:ids ids
:ids-with-children ids-with-children
:values values
:shape shape}])])
(when (or (options :clip-content) (options :show-in-viewer)) (when (or (options :clip-content) (options :show-in-viewer))
[:div {:class (stl/css :clip-show)} [:div {:class (stl/css :clip-show)}
(when (options :clip-content) (when (options :clip-content)

View File

@ -6,9 +6,9 @@
(ns app.main.ui.workspace.sidebar.options.shapes.bool (ns app.main.ui.workspace.sidebar.options.shapes.bool
(:require (:require
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill] [app.main.ui.workspace.sidebar.options.menus.fill :as fill]
@ -21,31 +21,61 @@
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc options (mf/defc options*
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [ids [(:id shape)] (let [id (dm/get-prop shape :id)
type (:type shape) type (dm/get-prop shape :type)
measure-values (select-keys shape measure-attrs) ids (mf/with-memo [id] [id])
stroke-values (select-keys shape stroke-attrs) shapes (mf/with-memo [shape] [shape])
layer-values (select-keys shape layer-attrs)
constraint-values (select-keys shape constraint-attrs)
layout-item-values (select-keys shape layout-item-attrs)
layout-container-values (select-keys shape layout-container-flex-attrs)
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) measure-values
is-layout-child? (mf/deref is-layout-child-ref) (select-keys shape measure-attrs)
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids)) stroke-values
is-flex-parent? (mf/deref is-flex-parent-ref) (select-keys shape stroke-attrs)
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) layer-values
is-grid-parent? (mf/deref is-grid-parent-ref) (select-keys shape layer-attrs)
is-layout-child-absolute? (ctl/item-absolute? shape) constraint-values
(select-keys shape constraint-attrs)
ids (hooks/use-equal-memo ids) layout-item-values
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) (select-keys shape layout-item-attrs)
parents (mf/deref parents-by-ids-ref)]
layout-container-values
(select-keys shape layout-container-flex-attrs)
is-layout-child-ref
(mf/with-memo [ids]
(refs/is-layout-child? ids))
is-layout-child?
(mf/deref is-layout-child-ref)
is-flex-parent-ref
(mf/with-memo [ids]
(refs/flex-layout-child? ids))
is-flex-parent?
(mf/deref is-flex-parent-ref)
is-grid-parent-ref
(mf/with-memo [ids]
(refs/grid-layout-child? ids))
is-grid-parent?
(mf/deref is-grid-parent-ref)
is-layout-child-absolute?
(ctl/item-absolute? shape)
parents-by-ids-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
parents
(mf/deref parents-by-ids-ref)]
[:* [:*
[:& layer-menu {:ids ids [:& layer-menu {:ids ids
@ -55,7 +85,7 @@
[:> measures-menu* {:ids ids [:> measures-menu* {:ids ids
:type type :type type
:values measure-values :values measure-values
:shape shape}] :shapes shapes}]
[:& layout-container-menu [:& layout-container-menu
{:type type {:type type

View File

@ -6,9 +6,9 @@
(ns app.main.ui.workspace.sidebar.options.shapes.circle (ns app.main.ui.workspace.sidebar.options.shapes.circle
(:require (:require
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill] [app.main.ui.workspace.sidebar.options.menus.fill :as fill]
@ -22,32 +22,61 @@
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc options (mf/defc options*
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [ids [(:id shape)] (let [id (dm/get-prop shape :id)
type (:type shape) type (dm/get-prop shape :type)
ids (mf/with-memo [id] [id])
shapes (mf/with-memo [shape] [shape])
measure-values (select-keys shape measure-attrs) measure-values
stroke-values (select-keys shape stroke-attrs) (select-keys shape measure-attrs)
layer-values (select-keys shape layer-attrs)
constraint-values (select-keys shape constraint-attrs)
layout-item-values (select-keys shape layout-item-attrs)
layout-container-values (select-keys shape layout-container-flex-attrs)
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) stroke-values
is-layout-child? (mf/deref is-layout-child-ref) (select-keys shape stroke-attrs)
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids)) layer-values
is-flex-parent? (mf/deref is-flex-parent-ref) (select-keys shape layer-attrs)
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) constraint-values
is-grid-parent? (mf/deref is-grid-parent-ref) (select-keys shape constraint-attrs)
is-layout-child-absolute? (ctl/item-absolute? shape) layout-item-values
(select-keys shape layout-item-attrs)
ids (hooks/use-equal-memo ids) layout-container-values
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) (select-keys shape layout-container-flex-attrs)
parents (mf/deref parents-by-ids-ref)]
is-layout-child-ref
(mf/with-memo [ids]
(refs/is-layout-child? ids))
is-layout-child?
(mf/deref is-layout-child-ref)
is-flex-parent-ref
(mf/with-memo [ids]
(refs/flex-layout-child? ids))
is-flex-parent?
(mf/deref is-flex-parent-ref)
is-grid-parent-ref
(mf/with-memo [ids]
(refs/grid-layout-child? ids))
is-grid-parent?
(mf/deref is-grid-parent-ref)
is-layout-child-absolute?
(ctl/item-absolute? shape)
parents-by-ids-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
parents
(mf/deref parents-by-ids-ref)]
[:* [:*
[:& layer-menu {:ids ids [:& layer-menu {:ids ids
:type type :type type
@ -56,7 +85,7 @@
[:> measures-menu* {:ids ids [:> measures-menu* {:ids ids
:type type :type type
:values measure-values :values measure-values
:shape shape}] :shapes shapes}]
[:& layout-container-menu [:& layout-container-menu
{:type type {:type type

View File

@ -31,49 +31,77 @@
(let [shape-id (dm/get-prop shape :id) (let [shape-id (dm/get-prop shape :id)
shape-type (dm/get-prop shape :type) shape-type (dm/get-prop shape :type)
ids (mf/with-memo [shape-id] ids
[shape-id]) (mf/with-memo [shape-id]
[shape-id])
shapes (mf/with-memo [shape] shapes
[shape]) (mf/with-memo [shape]
[shape])
stroke-values (select-keys shape stroke-attrs) stroke-values
layer-values (select-keys shape layer-attrs) (select-keys shape stroke-attrs)
measure-values (select-measure-keys shape)
constraint-values (select-keys shape constraint-attrs) layer-values
layout-container-values (select-keys shape layout-container-flex-attrs) (select-keys shape layer-attrs)
layout-item-values (select-keys shape layout-item-attrs)
measure-values
(select-measure-keys shape)
constraint-values
(select-keys shape constraint-attrs)
layout-container-values
(select-keys shape layout-container-flex-attrs)
layout-item-values
(select-keys shape layout-item-attrs)
is-layout-child-ref is-layout-child-ref
(mf/with-memo [ids] (mf/with-memo [ids]
(refs/is-layout-child? ids)) (refs/is-layout-child? ids))
is-layout-child? is-layout-child?
(mf/deref is-layout-child-ref) (mf/deref is-layout-child-ref)
is-flex-parent-ref is-flex-parent-ref
(mf/with-memo [ids] (mf/with-memo [ids]
(refs/flex-layout-child? ids)) (refs/flex-layout-child? ids))
is-flex-parent? is-flex-parent?
(mf/deref is-flex-parent-ref) (mf/deref is-flex-parent-ref)
is-grid-parent-ref is-grid-parent-ref
(mf/with-memo [ids] (mf/with-memo [ids]
(refs/grid-layout-child? ids)) (refs/grid-layout-child? ids))
is-grid-parent? is-grid-parent?
(mf/deref is-grid-parent-ref) (mf/deref is-grid-parent-ref)
parents-by-ids-ref parents-by-ids-ref
(mf/with-memo [ids] (mf/with-memo [ids]
(refs/parents-by-ids ids)) (refs/parents-by-ids ids))
parents parents
(mf/deref parents-by-ids-ref) (mf/deref parents-by-ids-ref)
is-layout-container? (ctl/any-layout? shape) is-layout-container?
is-flex-layout? (ctl/flex-layout? shape) (ctl/any-layout? shape)
is-grid-layout? (ctl/grid-layout? shape)
is-layout-child-absolute? (ctl/item-absolute? shape) is-flex-layout?
variants? (features/use-feature "variants/v1") (ctl/flex-layout? shape)
is-variant? (when variants? (ctk/is-variant-container? shape))]
is-grid-layout?
(ctl/grid-layout? shape)
is-layout-child-absolute?
(ctl/item-absolute? shape)
variants?
(features/use-feature "variants/v1")
is-variant?
(when variants? (ctk/is-variant-container? shape))]
[:* [:*
[:& layer-menu {:ids ids [:& layer-menu {:ids ids
@ -82,7 +110,7 @@
[:> measures-menu* {:ids ids [:> measures-menu* {:ids ids
:values measure-values :values measure-values
:type shape-type :type shape-type
:shape shape}] :shapes shapes}]
[:& component-menu {:shapes shapes}] [:& component-menu {:shapes shapes}]

View File

@ -8,9 +8,9 @@
(: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.data.macros :as dm]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]] [app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraints-menu]]
@ -27,48 +27,89 @@
[app.main.ui.workspace.sidebar.options.shapes.multiple :refer [get-attrs]] [app.main.ui.workspace.sidebar.options.shapes.multiple :refer [get-attrs]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc options (mf/defc options*
{::mf/wrap [mf/memo] {::mf/wrap [mf/memo]}
::mf/wrap-props false} [{:keys [shape shapes-with-children libraries file-id] :as props}]
[props]
(let [shape (unchecked-get props "shape")
shape-with-children (unchecked-get props "shape-with-children")
libraries (unchecked-get props "libraries")
objects (->> shape-with-children (group-by :id) (d/mapm (fn [_ v] (first v))))
file-id (unchecked-get props "file-id")
layout-container-values (select-keys shape layout-container-flex-attrs)
ids [(:id shape)]
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids))
is-layout-child? (mf/deref is-layout-child-ref)
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids)) (let [id (dm/get-prop shape :id)
is-flex-parent? (mf/deref is-flex-parent-ref) type (dm/get-prop shape :type)
ids (mf/with-memo [id] [id])
shapes (mf/with-memo [shape] [shape])
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) objects
is-grid-parent? (mf/deref is-grid-parent-ref) (mf/with-memo [shapes-with-children]
(d/index-by :id shapes-with-children))
is-layout-child-absolute? (ctl/item-absolute? shape) layout-container-values
(select-keys shape layout-container-flex-attrs)
ids (hooks/use-equal-memo ids) svg-values
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) (select-keys shape [:svg-attrs])
parents (mf/deref parents-by-ids-ref)
type :group is-layout-child-ref
[measure-ids measure-values] (get-attrs [shape] objects :measure) (mf/with-memo [ids]
[layer-ids layer-values] (get-attrs [shape] objects :layer) (refs/is-layout-child? ids))
[constraint-ids constraint-values] (get-attrs [shape] objects :constraint)
[fill-ids fill-values] (get-attrs [shape] objects :fill)
[shadow-ids _] (get-attrs [shape] objects :shadow)
[blur-ids blur-values] (get-attrs [shape] objects :blur)
[stroke-ids stroke-values] (get-attrs [shape] objects :stroke)
[text-ids text-values] (get-attrs [shape] objects :text)
[svg-ids svg-values] [[(:id shape)] (select-keys shape [:svg-attrs])]
[layout-item-ids layout-item-values] (get-attrs [shape] objects :layout-item)]
is-layout-child?
(mf/deref is-layout-child-ref)
is-flex-parent-ref
(mf/with-memo [ids]
(refs/flex-layout-child? ids))
is-flex-parent?
(mf/deref is-flex-parent-ref)
is-grid-parent-ref
(mf/with-memo [ids]
(refs/grid-layout-child? ids))
is-grid-parent?
(mf/deref is-grid-parent-ref)
is-layout-child-absolute?
(ctl/item-absolute? shape)
parents-by-ids-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
parents
(mf/deref parents-by-ids-ref)
[measure-ids measure-values]
(get-attrs shapes objects :measure)
[layer-ids layer-values]
(get-attrs shapes objects :layer)
[constraint-ids constraint-values]
(get-attrs shapes objects :constraint)
[fill-ids fill-values]
(get-attrs shapes objects :fill)
[shadow-ids]
(get-attrs shapes objects :shadow)
[blur-ids blur-values]
(get-attrs shapes objects :blur)
[stroke-ids stroke-values]
(get-attrs shapes objects :stroke)
[text-ids text-values]
(get-attrs shapes objects :text)
[layout-item-ids layout-item-values]
(get-attrs shapes objects :layout-item)]
[:div {:class (stl/css :options)} [:div {:class (stl/css :options)}
[:& layer-menu {:type type :ids layer-ids :values layer-values}] [:& layer-menu {:type type :ids layer-ids :values layer-values}]
[:> measures-menu* {:type type :ids measure-ids :values measure-values :shape shape}] [:> measures-menu* {:type type
:ids measure-ids
:values measure-values
:shapes shapes}]
[:& layout-container-menu [:& layout-container-menu
{:type type {:type type
@ -116,7 +157,6 @@
[:& ot/text-menu {:type type :ids text-ids :values text-values}]) [:& ot/text-menu {:type type :ids text-ids :values text-values}])
(when-not (empty? svg-values) (when-not (empty? svg-values)
[:& svg-attrs-menu {:ids svg-ids [:& svg-attrs-menu {:ids ids :values svg-values}])]))
:values svg-values}])]))

View File

@ -1,97 +0,0 @@
;; 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.sidebar.options.shapes.image
(:require
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[rumext.v2 :as mf]))
(mf/defc options
[{:keys [shape] :as props}]
(let [ids [(:id shape)]
type (:type shape)
measure-values (select-keys shape measure-attrs)
layer-values (select-keys shape layer-attrs)
constraint-values (select-keys shape constraint-attrs)
stroke-values (select-keys shape stroke-attrs)
layout-item-values (select-keys shape layout-item-attrs)
layout-container-values (select-keys shape layout-container-flex-attrs)
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids))
is-layout-child? (mf/deref is-layout-child-ref)
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids))
is-flex-parent? (mf/deref is-flex-parent-ref)
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref)
is-layout-child-absolute? (ctl/item-absolute? shape)
ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
parents (mf/deref parents-by-ids-ref)]
[:*
[:& layer-menu {:ids ids
:type type
:values layer-values}]
[:> measures-menu* {:ids ids
:type type
:values measure-values
:shape shape}]
[:& layout-container-menu
{:type type
:ids [(:id shape)]
:values layout-container-values
:multiple false}]
(when (and (= (count ids) 1) is-layout-child? is-grid-parent?)
[:& grid-cell/options
{:shape (first parents)
:cell (ctl/get-cell-by-shape-id (first parents) (first ids))}])
(when is-layout-child?
[:& layout-item-menu
{:ids ids
:type type
:values layout-item-values
:is-layout-child? true
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
[:> fill/fill-menu*
{:ids ids
:type type
:values shape}]
[:& stroke-menu {:ids ids
:type type
:values stroke-values}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]]))

View File

@ -9,14 +9,16 @@
(:require (:require
[app.common.attrs :as attrs] [app.common.attrs :as attrs]
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.types.component :as ctk] [app.common.types.component :as ctk]
[app.common.types.path :as path] [app.common.types.path :as path]
[app.common.types.shape.attrs :refer [editable-attrs]] [app.common.types.shape.attrs :refer [editable-attrs]]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.common.types.text :as txt] [app.common.types.text :as txt]
[app.common.weak :as weak]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-attrs blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-attrs blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]] [app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
[app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu]] [app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu]]
@ -202,10 +204,6 @@
applies (some of them ignore some attributes)" applies (some of them ignore some attributes)"
[shapes objects attr-group] [shapes objects attr-group]
(let [attrs (group->attrs attr-group) (let [attrs (group->attrs attr-group)
default-text-attrs
(txt/get-default-text-attrs)
merge-attrs merge-attrs
(fn [v1 v2] (fn [v1 v2]
(cond (cond
@ -213,8 +211,21 @@
(= attr-group :blur) (attrs/get-attrs-multi [v1 v2] attrs blur-eq blur-sel) (= attr-group :blur) (attrs/get-attrs-multi [v1 v2] attrs blur-eq blur-sel)
:else (attrs/get-attrs-multi [v1 v2] attrs))) :else (attrs/get-attrs-multi [v1 v2] attrs)))
merge-token-values
(fn [acc keys attrs]
(reduce
(fn [accum key]
(let [new-val (get attrs key)
existing (get accum key ::not-found)]
(cond
(= existing ::not-found) (assoc accum key new-val)
(= existing new-val) accum
:else (assoc accum key :multiple))))
acc
keys))
extract-attrs extract-attrs
(fn [[ids values] {:keys [id type] :as shape}] (fn [[ids values token-acc] {:keys [id type applied-tokens] :as shape}]
(let [read-mode (get-in type->read-mode [type attr-group]) (let [read-mode (get-in type->read-mode [type attr-group])
editable-attrs (filter (get editable-attrs (:type shape)) attrs)] editable-attrs (filter (get editable-attrs (:type shape)) attrs)]
(case read-mode (case read-mode
@ -228,144 +239,192 @@
(into {} (map #(vector % nil)) editable-attrs) (into {} (map #(vector % nil)) editable-attrs)
(cond (cond
(= attr-group :measure) (select-measure-keys shape) (= attr-group :measure) (select-measure-keys shape)
:else (select-keys shape editable-attrs)))] :else (select-keys shape editable-attrs)))
new-token-acc (merge-token-values token-acc editable-attrs applied-tokens)]
[(conj ids id) [(conj ids id)
(merge-attrs values shape-values)]) (merge-attrs values shape-values)
new-token-acc])
:text :text
(let [shape-attrs (select-keys shape attrs) (let [shape-attrs (select-keys shape attrs)
content-attrs content-attrs
(attrs/get-text-attrs-multi shape default-text-attrs attrs) (attrs/get-text-attrs-multi shape txt/default-text-attrs attrs)
new-values new-values
(-> values (-> values
(merge-attrs shape-attrs) (merge-attrs shape-attrs)
(merge-attrs content-attrs))] (merge-attrs content-attrs))
new-token-acc (merge-token-values token-acc content-attrs applied-tokens)]
[(conj ids id) [(conj ids id)
new-values]) new-values
new-token-acc])
:children :children
(let [children (->> (:shapes shape []) (map #(get objects %))) (let [children (->> (:shapes shape []) (map #(get objects %)))
[new-ids new-values] (get-attrs* children objects attr-group)] [new-ids new-values] (get-attrs* children objects attr-group)]
[(d/concat-vec ids new-ids) (merge-attrs values new-values)]) [(d/concat-vec ids new-ids) (merge-attrs values new-values) {}])
[])))] [])))]
(reduce extract-attrs [[] []] shapes))) (reduce extract-attrs [[] {} {}] shapes)))
(def get-attrs (memoize get-attrs*)) (def get-attrs
(weak/memoize get-attrs*))
(defn basic-shape [_ shape]
(cond-> shape
:always
(dissoc :selrect :points :x :y :width :height :transform :transform-inverse :rotation :svg-transform :svg-viewbox :thumbnail)
(= (:type shape) :path)
(dissoc :content)))
(defn- is-bool-descendant? (defn- is-bool-descendant?
[[_ shape] objects selected-shape-ids] [objects selected-shape-ids shape]
(let [parent-id (:parent-id shape) (let [parent-id (:parent-id shape)
parent (get objects parent-id)] parent (get objects parent-id)]
(cond (cond
(nil? shape) false ;; failsafe (nil? shape) false ;; failsafe
(contains? selected-shape-ids (:id shape)) false ;; if it is one of the selected shapes, it is considerer not a bool descendant (contains? selected-shape-ids (:id shape)) false ;; if it is one of the selected shapes, it is considerer not a bool descendant
(= :bool (:type parent)) true ;; if its parent is of type bool, it is a bool descendant (= :bool (:type parent)) true ;; if its parent is of type bool, it is a bool descendant
:else (recur [parent-id parent] objects selected-shape-ids)))) ;; else, check its parent :else (recur [parent-id parent] objects selected-shape-ids)))) ;; else, check its parent
(mf/defc options (defn- check-options-props
{::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "shapes-with-children" "page-id" "file-id"]))] [new-props old-props]
::mf/wrap-props false} (and (= (unchecked-get new-props "shapes")
[props] (unchecked-get old-props "shapes"))
(let [shapes (unchecked-get props "shapes") (= (unchecked-get new-props "shapesWithChildren")
shapes-with-children (unchecked-get props "shapes-with-children") (unchecked-get old-props "shapesWithChildren"))
(= (unchecked-get new-props "pageId")
(unchecked-get old-props "pageId"))
(= (unchecked-get new-props "fileId")
(unchecked-get old-props "fileId"))))
;; remove children from bool shapes (mf/defc options*
shape-ids (into #{} (map :id) shapes) {::mf/wrap [#(mf/memo' % check-options-props)]}
[{:keys [shapes shapes-with-children page-id file-id libraries] :as props}]
(let [shape-ids
(mf/with-memo [shapes]
(into #{} d/xf:map-id shapes))
is-layout-child-ref
(mf/with-memo [shape-ids]
(refs/is-layout-child? shape-ids))
is-layout-child?
(mf/deref is-layout-child-ref)
is-flex-parent-ref
(mf/with-memo [shape-ids]
(refs/flex-layout-child? shape-ids))
is-flex-parent?
(mf/deref is-flex-parent-ref)
is-grid-parent-ref
(mf/with-memo [shape-ids]
(refs/grid-layout-child? shape-ids))
is-grid-parent?
(mf/deref is-grid-parent-ref)
has-flex-layout-container?
(some ctl/flex-layout? shapes)
all-layout-child-ref
(mf/with-memo [shape-ids]
(refs/all-layout-child? shape-ids))
all-layout-child?
(mf/deref all-layout-child-ref)
all-flex-layout-container?
(mf/with-memo [shapes]
(every? ctl/flex-layout? shapes))
show-caps?
(mf/with-memo [shapes]
(some #(and (cfh/path-shape? %)
(path/shape-with-open-path? %))
shapes))
has-text?
(mf/with-memo [shapes]
(some cfh/text-shape? shapes))
objects (->> shapes-with-children (group-by :id) (d/mapm (fn [_ v] (first v))))
objects objects
(into {} (mf/with-memo [shapes-with-children]
(filter #(not (is-bool-descendant? % objects shape-ids))) (let [objects (d/index-by :id shapes-with-children)]
objects) (reduce-kv (fn [objects id object]
(if (is-bool-descendant? objects shape-ids object)
(dissoc objects id)
objects))
objects
objects)))
workspace-modifiers (mf/deref refs/workspace-modifiers) [layer-ids layer-values]
shapes (map #(gsh/transform-shape % (get-in workspace-modifiers [(:id %) :modifiers])) shapes) (get-attrs shapes objects :layer)
page-id (unchecked-get props "page-id") [text-ids text-values]
file-id (unchecked-get props "file-id") (get-attrs shapes objects :text)
shared-libs (unchecked-get props "libraries")
show-caps (some #(and (= :path (:type %)) (path/shape-with-open-path? %)) shapes) [constraint-ids constraint-values]
(get-attrs shapes objects :constraint)
;; Selrect/points only used for measures and it's the one that changes the most. We separate it [fill-ids fill-values]
;; so we can memoize it (get-attrs shapes objects :fill)
objects-no-measures (->> objects (d/mapm basic-shape))
objects-no-measures (hooks/use-equal-memo objects-no-measures) [shadow-ids shadow-values]
(get-attrs shapes objects :shadow)
[blur-ids blur-values]
(get-attrs shapes objects :blur)
[stroke-ids stroke-values]
(get-attrs shapes objects :stroke)
[exports-ids exports-values]
(get-attrs shapes objects :exports)
[layout-container-ids layout-container-values]
(get-attrs shapes objects :layout-container)
[layout-item-ids layout-item-values {}]
(get-attrs shapes objects :layout-item)
components
(mf/with-memo [shapes]
(not-empty (filter ctk/instance-head? shapes)))
workspace-modifiers
(mf/deref refs/workspace-modifiers)
shapes
(mf/with-memo [workspace-modifiers shapes]
(into []
(map (fn [shape]
(let [shape-id (dm/get-prop shape :id)
modifiers (dm/get-in workspace-modifiers [shape-id :modifiers])]
(gsh/transform-shape shape modifiers))))
shapes))
type :multiple type :multiple
all-types (into #{} (map :type shapes))
ids (->> shapes (map :id)) ;; NOTE: we only need transformed shapes for the measure menu,
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) ;; the rest of menus can live with shapes not transformed; we
is-layout-child? (mf/deref is-layout-child-ref) ;; also don't use the memoized version of get-attrs because it
;; makes no sense because the shapes object are changed on
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids)) ;; each rerender.
is-flex-parent? (mf/deref is-flex-parent-ref) [measure-ids measure-values]
(get-attrs* shapes objects :measure)]
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref)
has-text? (contains? all-types :text)
has-flex-layout-container? (->> shapes (some ctl/flex-layout?))
all-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/all-layout-child? ids))
all-layout-child? (mf/deref all-layout-child-ref)
all-flex-layout-container? (->> shapes (every? ctl/flex-layout?))
[measure-ids measure-values] (get-attrs shapes objects :measure)
[layer-ids layer-values
text-ids text-values
constraint-ids constraint-values
fill-ids fill-values
shadow-ids shadow-values
blur-ids blur-values
stroke-ids stroke-values
exports-ids exports-values
layout-container-ids layout-container-values
layout-item-ids layout-item-values]
(mf/use-memo
(mf/deps shapes objects-no-measures)
(fn []
(into
[]
(mapcat identity)
[(get-attrs shapes objects-no-measures :layer)
(get-attrs shapes objects-no-measures :text)
(get-attrs shapes objects-no-measures :constraint)
(get-attrs shapes objects-no-measures :fill)
(get-attrs shapes objects-no-measures :shadow)
(get-attrs shapes objects-no-measures :blur)
(get-attrs shapes objects-no-measures :stroke)
(get-attrs shapes objects-no-measures :exports)
(get-attrs shapes objects-no-measures :layout-container)
(get-attrs shapes objects-no-measures :layout-item)])))
components (filter ctk/instance-head? shapes)]
[:div {:class (stl/css :options)} [:div {:class (stl/css :options)}
(when-not (empty? layer-ids) (when-not (empty? layer-ids)
[:& layer-menu {:type type :ids layer-ids :values layer-values}]) [:& layer-menu {:type type :ids layer-ids :values layer-values}])
(when-not (empty? measure-ids) (when-not (empty? measure-ids)
[:> measures-menu* {:type type :all-types all-types :ids measure-ids :values measure-values :shape shapes}]) [:> measures-menu*
{:type type
:ids measure-ids
:values measure-values
:shapes shapes}])
(when-not (empty? components) (when (some? components)
[:& component-menu {:shapes components}]) [:& component-menu {:shapes components}])
[:& layout-container-menu [:& layout-container-menu
@ -394,15 +453,18 @@
[:> fill/fill-menu* {:type type :ids fill-ids :values fill-values}]) [:> fill/fill-menu* {:type type :ids fill-ids :values fill-values}])
(when-not (empty? stroke-ids) (when-not (empty? stroke-ids)
[:& stroke-menu {:type type :ids stroke-ids :show-caps show-caps :values stroke-values [:& stroke-menu {:type type
:ids stroke-ids
:show-caps show-caps?
:values stroke-values
:disable-stroke-style has-text?}]) :disable-stroke-style has-text?}])
(when-not (empty? shapes) (when-not (empty? shapes)
[:> color-selection-menu* [:> color-selection-menu*
{:file-id file-id {:file-id file-id
:type type :type type
:shapes (vals objects-no-measures) :shapes shapes
:libraries shared-libs}]) :libraries libraries}])
(when-not (empty? shadow-ids) (when-not (empty? shadow-ids)
[:> shadow-menu* {:type type [:> shadow-menu* {:type type

View File

@ -6,9 +6,9 @@
(ns app.main.ui.workspace.sidebar.options.shapes.path (ns app.main.ui.workspace.sidebar.options.shapes.path
(:require (:require
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill] [app.main.ui.workspace.sidebar.options.menus.fill :as fill]
@ -22,32 +22,68 @@
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc options (mf/defc options*
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [ids [(:id shape)] (let [ids
type (:type shape) (mf/with-memo [shape]
[(dm/get-prop shape :id)])
measure-values (select-keys shape measure-attrs) shapes
stroke-values (select-keys shape stroke-attrs) (mf/with-memo [shape]
layer-values (select-keys shape layer-attrs) [shape])
constraint-values (select-keys shape constraint-attrs)
layout-item-values (select-keys shape layout-item-attrs)
layout-container-values (select-keys shape layout-container-flex-attrs)
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) type
is-layout-child? (mf/deref is-layout-child-ref) (dm/get-prop shape :type)
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids)) measure-values
is-flex-parent? (mf/deref is-flex-parent-ref) (select-keys shape measure-attrs)
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) stroke-values
is-grid-parent? (mf/deref is-grid-parent-ref) (select-keys shape stroke-attrs)
is-layout-child-absolute? (ctl/item-absolute? shape) layer-values
(select-keys shape layer-attrs)
constraint-values
(select-keys shape constraint-attrs)
layout-item-values
(select-keys shape layout-item-attrs)
layout-container-values
(select-keys shape layout-container-flex-attrs)
is-layout-child-ref
(mf/with-memo [ids]
(refs/is-layout-child? ids))
is-layout-child?
(mf/deref is-layout-child-ref)
is-flex-parent-ref
(mf/with-memo [ids]
(refs/flex-layout-child? ids))
is-flex-parent?
(mf/deref is-flex-parent-ref)
is-grid-parent-ref
(mf/with-memo [ids]
(refs/grid-layout-child? ids))
is-grid-parent?
(mf/deref is-grid-parent-ref)
is-layout-child-absolute?
(ctl/item-absolute? shape)
parents-by-ids-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
parents
(mf/deref parents-by-ids-ref)]
ids (hooks/use-equal-memo ids)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
parents (mf/deref parents-by-ids-ref)]
[:* [:*
[:& layer-menu {:ids ids [:& layer-menu {:ids ids
:type type :type type
@ -55,7 +91,7 @@
[:> measures-menu* {:ids ids [:> measures-menu* {:ids ids
:type type :type type
:values measure-values :values measure-values
:shape shape}] :shapes shapes}]
[:& layout-container-menu [:& layout-container-menu
{:type type {:type type

View File

@ -6,9 +6,9 @@
(ns app.main.ui.workspace.sidebar.options.shapes.rect (ns app.main.ui.workspace.sidebar.options.shapes.rect
(:require (:require
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill] [app.main.ui.workspace.sidebar.options.menus.fill :as fill]
@ -16,39 +16,67 @@
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]] [app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]] [app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]] [app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measures-menu*]] [app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]] [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc options (mf/defc options*
{::mf/wrap [mf/memo]
::mf/wrap-props false}
[{:keys [shape]}] [{:keys [shape]}]
(let [shape-id (:id shape) (let [id (dm/get-prop shape :id)
ids (hooks/use-equal-memo [shape-id]) type (dm/get-prop shape :type)
type (:type shape) ids (mf/with-memo [id] [id])
measure-values (select-measure-keys shape) shapes (mf/with-memo [shape] [shape])
layer-values (select-keys shape layer-attrs)
constraint-values (select-keys shape constraint-attrs)
stroke-values (select-keys shape stroke-attrs)
layout-item-values (select-keys shape layout-item-attrs)
layout-container-values (select-keys shape layout-container-flex-attrs)
is-layout-child* (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) measure-values
is-layout-child? (mf/deref is-layout-child*) (select-keys shape measure-attrs)
is-flex-parent* (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids)) stroke-values
is-flex-parent? (mf/deref is-flex-parent*) (select-keys shape stroke-attrs)
is-grid-parent* (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) layer-values
is-grid-parent? (mf/deref is-grid-parent*) (select-keys shape layer-attrs)
is-layout-child-absolute? (ctl/item-absolute? shape) constraint-values
(select-keys shape constraint-attrs)
parents-by-ids* (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) layout-item-values
parents (mf/deref parents-by-ids*)] (select-keys shape layout-item-attrs)
layout-container-values
(select-keys shape layout-container-flex-attrs)
is-layout-child-ref
(mf/with-memo [ids]
(refs/is-layout-child? ids))
is-layout-child?
(mf/deref is-layout-child-ref)
is-flex-parent-ref
(mf/with-memo [ids]
(refs/flex-layout-child? ids))
is-flex-parent?
(mf/deref is-flex-parent-ref)
is-grid-parent-ref
(mf/with-memo [ids]
(refs/grid-layout-child? ids))
is-grid-parent?
(mf/deref is-grid-parent-ref)
is-layout-child-absolute?
(ctl/item-absolute? shape)
parents-by-ids-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
parents
(mf/deref parents-by-ids-ref)]
[:* [:*
[:& layer-menu {:ids ids [:& layer-menu {:ids ids
@ -57,7 +85,7 @@
[:> measures-menu* {:ids ids [:> measures-menu* {:ids ids
:type type :type type
:values measure-values :values measure-values
:shape shape}] :shapes shapes}]
[:& layout-container-menu [:& layout-container-menu
{:type type {:type type

View File

@ -7,10 +7,10 @@
(ns app.main.ui.workspace.sidebar.options.shapes.svg-raw (ns app.main.ui.workspace.sidebar.options.shapes.svg-raw
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.types.color :as cc] [app.common.types.color :as cc]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill] [app.main.ui.workspace.sidebar.options.menus.fill :as fill]
@ -26,15 +26,10 @@
;; This is a list of svg tags that can be grouped in shape-container ;; This is a list of svg tags that can be grouped in shape-container
;; this allows them to have gradients, shadows and masks ;; this allows them to have gradients, shadows and masks
(def svg-elements #{:svg :g :circle :ellipse :image :line :path :polygon :polyline :rect :symbol :text :textPath}) (def ^:private svg-elements
#{:svg :g :circle :ellipse :image :line :path :polygon :polyline :rect :symbol :text :textPath})
(defn hex->number [_] 1) (defn- parse-color [color]
(defn shorthex->longhex [hex]
(let [[_ r g b] hex]
(str "#" r r g g b b)))
(defn parse-color [color]
(try (try
(cond (cond
(or (not color) (= color "none")) nil (or (not color) (= color "none")) nil
@ -51,8 +46,7 @@
(.error js/console "Error parsing color" e) (.error js/console "Error parsing color" e)
nil))) nil)))
(defn- get-fill-values [shape]
(defn get-fill-values [shape]
(let [fill-values (select-keys shape fill/fill-attrs) (let [fill-values (select-keys shape fill/fill-attrs)
color (-> (or (get-in shape [:content :attrs :fill]) color (-> (or (get-in shape [:content :attrs :fill])
(get-in shape [:content :attrs :style :fill])) (get-in shape [:content :attrs :style :fill]))
@ -64,7 +58,7 @@
fill-values)] fill-values)]
fill-values)) fill-values))
(defn get-stroke-values [shape] (defn- get-stroke-values [shape]
(let [stroke-values (select-keys shape stroke-attrs) (let [stroke-values (select-keys shape stroke-attrs)
color (-> (or (get-in shape [:content :attrs :stroke]) color (-> (or (get-in shape [:content :attrs :stroke])
(get-in shape [:content :attrs :style :stroke])) (get-in shape [:content :attrs :style :stroke]))
@ -92,42 +86,75 @@
stroke-values)] stroke-values)]
stroke-values)) stroke-values))
(mf/defc options (mf/defc options*
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [ids [(:id shape)] (let [id (dm/get-prop shape :id)
type (:type shape) type (dm/get-prop shape :type)
ids (mf/with-memo [id] [id])
shapes (mf/with-memo [shape] [shape])
{:keys [tag] :as content} (:content shape) {:keys [tag] :as content}
measure-values (select-keys shape measure-attrs) (get shape :content)
constraint-values (select-keys shape constraint-attrs)
fill-values (get-fill-values shape)
stroke-values (get-stroke-values shape)
layout-item-values (select-keys shape layout-item-attrs)
layout-container-values (select-keys shape layout-container-flex-attrs)
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) fill-values
is-layout-child? (mf/deref is-layout-child-ref) (mf/with-memo [shape]
(get-fill-values shape))
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids)) stroke-values
is-flex-parent? (mf/deref is-flex-parent-ref) (mf/with-memo [shape]
(get-stroke-values shape))
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) measure-values
is-grid-parent? (mf/deref is-grid-parent-ref) (select-keys shape measure-attrs)
is-layout-child-absolute? (ctl/item-absolute? shape) constraint-values
(select-keys shape constraint-attrs)
ids (hooks/use-equal-memo ids) layout-item-values
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) (select-keys shape layout-item-attrs)
parents (mf/deref parents-by-ids-ref)]
layout-container-values
(select-keys shape layout-container-flex-attrs)
is-layout-child-ref
(mf/with-memo [ids]
(refs/is-layout-child? ids))
is-layout-child?
(mf/deref is-layout-child-ref)
is-flex-parent-ref
(mf/with-memo [ids]
(refs/flex-layout-child? ids))
is-flex-parent?
(mf/deref is-flex-parent-ref)
is-grid-parent-ref
(mf/with-memo [ids]
(refs/grid-layout-child? ids))
is-grid-parent?
(mf/deref is-grid-parent-ref)
is-layout-child-absolute?
(ctl/item-absolute? shape)
parents-by-ids-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
parents
(mf/deref parents-by-ids-ref)]
(when (contains? svg-elements tag) (when (contains? svg-elements tag)
[:* [:*
[:> measures-menu* {:ids ids [:> measures-menu* {:ids ids
:type type :type type
:values measure-values :values measure-values
:shape shape}] :shapes shapes}]
[:& layout-container-menu [:& layout-container-menu
{:type type {:type type

View File

@ -6,14 +6,13 @@
(ns app.main.ui.workspace.sidebar.options.shapes.text (ns app.main.ui.workspace.sidebar.options.shapes.text
(:require (:require
[app.common.data :as d] [app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.common.types.text :as txt] [app.common.types.text :as txt]
[app.main.data.workspace.texts :as dwt] [app.main.data.workspace.texts :as dwt]
[app.main.features :as features] [app.main.features :as features]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]] [app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
@ -28,68 +27,102 @@
[app.main.ui.workspace.sidebar.options.menus.text :refer [text-menu]] [app.main.ui.workspace.sidebar.options.menus.text :refer [text-menu]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc options (mf/defc options*
[{:keys [shape file-id libraries] :as props}] [{:keys [shape file-id libraries] :as props}]
(let [ids [(:id shape)] (let [id (dm/get-prop shape :id)
type (:type shape) type (dm/get-prop shape :type)
ids (mf/with-memo [id] [id])
shapes (mf/with-memo [shape] [shape])
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids)) measure-values
is-layout-child? (mf/deref is-layout-child-ref) (select-keys shape measure-attrs)
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids)) stroke-values
is-flex-parent? (mf/deref is-flex-parent-ref) (select-keys shape stroke-attrs)
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids)) layer-values
is-grid-parent? (mf/deref is-grid-parent-ref) (select-keys shape layer-attrs)
layout-container-values (select-keys shape layout-container-flex-attrs) layout-item-values
is-layout-child-absolute? (ctl/item-absolute? shape) (select-keys shape layout-item-attrs)
ids (hooks/use-equal-memo ids) layout-container-values
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids)) (select-keys shape layout-container-flex-attrs)
parents (mf/deref parents-by-ids-ref)
state-map (if (features/active-feature? @st/state "text-editor/v2") is-layout-child-ref
(mf/deref refs/workspace-v2-editor-state) (mf/with-memo [ids]
(mf/deref refs/workspace-editor-state)) (refs/is-layout-child? ids))
editor-state (when (not (features/active-feature? @st/state "text-editor/v2")) is-layout-child?
(get state-map (:id shape))) (mf/deref is-layout-child-ref)
layer-values (select-keys shape layer-attrs) is-flex-parent-ref
editor-instance (when (features/active-feature? @st/state "text-editor/v2") (mf/with-memo [ids]
(mf/deref refs/workspace-editor)) (refs/flex-layout-child? ids))
fill-values (dwt/current-text-values is-flex-parent?
{:editor-state editor-state (mf/deref is-flex-parent-ref)
:editor-instance editor-instance
:shape shape
:attrs (conj txt/text-fill-attrs :fills)})
fill-values (if (not (contains? fill-values :fills)) is-grid-parent-ref
;; Old fill format (mf/with-memo [ids]
{:fills [fill-values]} (refs/grid-layout-child? ids))
fill-values)
stroke-values (select-keys shape stroke-attrs) is-grid-parent?
(mf/deref is-grid-parent-ref)
text-values (d/merge is-layout-child-absolute?
(select-keys shape [:grow-type]) (ctl/item-absolute? shape)
(select-keys shape fill/fill-attrs)
(dwt/current-root-values parents-by-ids-ref
{:shape shape (mf/with-memo [ids]
:attrs txt/root-attrs}) (refs/parents-by-ids ids))
(dwt/current-paragraph-values
{:editor-state editor-state parents
:editor-instance editor-instance (mf/deref parents-by-ids-ref)
:shape shape
:attrs txt/paragraph-attrs}) state-map
(dwt/current-text-values (if (features/active-feature? @st/state "text-editor/v2")
{:editor-state editor-state (mf/deref refs/workspace-v2-editor-state)
:editor-instance editor-instance (mf/deref refs/workspace-editor-state))
:shape shape
:attrs txt/text-node-attrs})) editor-state
layout-item-values (select-keys shape layout-item-attrs)] (when (not (features/active-feature? @st/state "text-editor/v2"))
(get state-map id))
editor-instance
(when (features/active-feature? @st/state "text-editor/v2")
(mf/deref refs/workspace-editor))
fill-values
(dwt/current-text-values
{:editor-state editor-state
:editor-instance editor-instance
:shape shape
:attrs (conj txt/text-fill-attrs :fills)})
fill-values
(if (not (contains? fill-values :fills))
;; Old fill format
{:fills [fill-values]}
fill-values)
text-values
(merge
(select-keys shape [:grow-type])
(select-keys shape fill/fill-attrs)
(dwt/current-root-values
{:shape shape
:attrs txt/root-attrs})
(dwt/current-paragraph-values
{:editor-state editor-state
:editor-instance editor-instance
:shape shape
:attrs txt/paragraph-attrs})
(dwt/current-text-values
{:editor-state editor-state
:editor-instance editor-instance
:shape shape
:attrs txt/text-node-attrs}))]
[:* [:*
[:& layer-menu {:ids ids [:& layer-menu {:ids ids
@ -98,12 +131,12 @@
[:> measures-menu* [:> measures-menu*
{:ids ids {:ids ids
:type type :type type
:values (select-keys shape measure-attrs) :values measure-values
:shape shape}] :shapes shapes}]
[:& layout-container-menu [:& layout-container-menu
{:type type {:type type
:ids [(:id shape)] :ids ids
:values layout-container-values :values layout-container-values
:multiple false}] :multiple false}]
@ -145,7 +178,7 @@
(when (= :multiple (:fills fill-values)) (when (= :multiple (:fills fill-values))
[:> color-selection-menu* [:> color-selection-menu*
{:type type {:type type
:shapes [shape] :shapes shapes
:file-id file-id :file-id file-id
:libraries libraries}]) :libraries libraries}])

View File

@ -53,7 +53,7 @@
(mf/defc tokens-section* (mf/defc tokens-section*
{::mf/private true} {::mf/private true}
[{:keys [tokens-lib]}] [{:keys [tokens-lib active-tokens resolved-active-tokens]}]
(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)
open-status (mf/deref ref:token-type-open-status) open-status (mf/deref ref:token-type-open-status)
@ -66,18 +66,9 @@
(mf/with-memo [selected-shapes objects] (mf/with-memo [selected-shapes objects]
(some #(ctsl/any-layout-immediate-child? objects %) selected-shapes)) (some #(ctsl/any-layout-immediate-child? objects %) selected-shapes))
active-theme-tokens
(mf/with-memo [tokens-lib]
(if tokens-lib
(ctob/get-tokens-in-active-sets tokens-lib)
{}))
;; Resolve tokens as second step
active-theme-tokens'
(sd/use-resolved-tokens* active-theme-tokens)
;; This only checks for the currently explicitly selected set ;; This only checks for the currently explicitly selected set
;; name, it is ephimeral and can be nil ;; name, it is ephimeral and can be nil
;; FIXME: this is a repeated deref for the same `:workspace-tokens` state
selected-token-set-name selected-token-set-name
(mf/deref refs/selected-token-set-name) (mf/deref refs/selected-token-set-name)
@ -92,8 +83,8 @@
(ctob/get-tokens-map selected-token-set)) (ctob/get-tokens-map selected-token-set))
tokens tokens
(mf/with-memo [active-theme-tokens selected-token-set-tokens] (mf/with-memo [active-tokens selected-token-set-tokens]
(merge active-theme-tokens selected-token-set-tokens)) (merge active-tokens selected-token-set-tokens))
tokens tokens
(sd/use-resolved-tokens* tokens) (sd/use-resolved-tokens* tokens)
@ -154,7 +145,7 @@
:type type :type type
:selected-shapes selected-shapes :selected-shapes selected-shapes
:is-selected-inside-layout is-selected-inside-layout :is-selected-inside-layout is-selected-inside-layout
:active-theme-tokens active-theme-tokens' :active-theme-tokens resolved-active-tokens
:tokens tokens}])) :tokens tokens}]))
(for [type empty-group] (for [type empty-group]
@ -162,5 +153,5 @@
:type type :type type
:selected-shapes selected-shapes :selected-shapes selected-shapes
:is-selected-inside-layout :is-selected-inside-layout :is-selected-inside-layout :is-selected-inside-layout
:active-theme-tokens active-theme-tokens' :active-theme-tokens resolved-active-tokens
:tokens []}])])) :tokens []}])]))

View File

@ -144,16 +144,12 @@
:on-click open-settings-modal}])])) :on-click open-settings-modal}])]))
(mf/defc tokens-sidebar-tab* (mf/defc tokens-sidebar-tab*
{::mf/wrap [mf/memo]} [{:keys [tokens-lib] :as props}]
[]
(let [{on-pointer-down-pages :on-pointer-down (let [{on-pointer-down-pages :on-pointer-down
on-lost-pointer-capture-pages :on-lost-pointer-capture on-lost-pointer-capture-pages :on-lost-pointer-capture
on-pointer-move-pages :on-pointer-move on-pointer-move-pages :on-pointer-move
size-pages-opened :size} size-pages-opened :size}
(use-resize-hook :tokens 200 38 "0.6" :y false nil) (use-resize-hook :tokens 200 38 "0.6" :y false nil)]
tokens-lib
(mf/deref refs/tokens-lib)]
[:div {:class (stl/css :sidebar-wrapper)} [:div {:class (stl/css :sidebar-wrapper)}
[:> token-management-section* [:> token-management-section*
@ -166,5 +162,5 @@
:on-lost-pointer-capture on-lost-pointer-capture-pages :on-lost-pointer-capture on-lost-pointer-capture-pages
:on-pointer-move on-pointer-move-pages} :on-pointer-move on-pointer-move-pages}
[:div {:class (stl/css :resize-handle-horiz)}]] [:div {:class (stl/css :resize-handle-horiz)}]]
[:> tokens-section* {:tokens-lib tokens-lib}]] [:> tokens-section* props]]
[:> import-export-button*]])) [:> import-export-button*]]))