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
25 changed files with 987 additions and 665 deletions

View File

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

View File

@@ -30,7 +30,20 @@
(def workspace-read-only? (mf/create-context nil))
(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 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
[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
[tokens name]
(->> tokens
vals
(apply concat)
(some #(when (= (:name %) name) %))))
(let [tokens (if (delay? tokens) @tokens tokens)
xform (filter #(= (:name %) name))]
(reduce-kv (fn [result _ tokens]
(into result xform tokens))
[]
tokens)))
(defn- clean-token-name
[s]
@@ -114,14 +117,14 @@
(subs s (inc start))))
(defn- filter-token-groups-by-name
[tokens-by-type filter-text]
[tokens filter-text]
(let [lc-filter (str/lower filter-text)]
(into {}
(keep (fn [[group tokens]]
(let [filtered (filter #(str/includes? (str/lower (:name %)) lc-filter) tokens)]
(when (seq filtered)
[group filtered]))))
tokens-by-type)))
tokens)))
(defn- focusable-option?
[option]
@@ -183,7 +186,9 @@
is-selected-on-focus nillable
tokens applied-token empty-to-end
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
;; options provide as clojure data structures or javascript
;; plain objects and lists.
@@ -253,12 +258,14 @@
dropdown-options
(mf/with-memo [tokens filter-id]
(let [partial (extract-partial-brace-text filter-id)
options (if (seq partial)
(filter-token-groups-by-name tokens partial)
tokens)
no-sets? (nil? tokens)]
(generate-dropdown-options options no-sets?)))
(delay
(let [tokens (if (delay? tokens) @tokens tokens)
partial (extract-partial-brace-text filter-id)
options (if (seq partial)
(filter-token-groups-by-name tokens partial)
tokens)
no-sets? (nil? tokens)]
(generate-dropdown-options options no-sets?))))
selected-id*
(mf/use-state (fn []
@@ -351,23 +358,27 @@
on-option-click
(mf/use-fn
(mf/deps dropdown-options on-token-apply)
(mf/deps on-token-apply)
(fn [event]
(let [node (dom/get-current-target event)
id (dom/get-data node "id")
option (get-option dropdown-options id)
value (get option :resolved-value)
name (get option :name)]
(let [node (dom/get-current-target event)
id (dom/get-data node "id")
options (mf/ref-val options-ref)
options (if (delay? options) @options options)
option (get-option options id)
value (get option :resolved-value)
name (get option :name)]
(on-token-apply id value name)
(reset! filter-id* ""))))
on-option-enter
(mf/use-fn
(mf/deps dropdown-options focused-id on-token-apply)
(mf/deps focused-id on-token-apply)
(fn [_]
(let [option (get-option dropdown-options focused-id)
value (get option :resolved-value)
name (get option :name)]
(let [options (mf/ref-val options-ref)
options (if (delay? options) @options options)
option (get-option options focused-id)
value (get option :resolved-value)
name (get option :name)]
(on-token-apply focused-id value name)
(reset! filter-id* ""))))
@@ -386,9 +397,9 @@
(when (fn? on-blur)
(on-blur event)))))
handle-key-down
on-key-down
(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]
(mf/set-ref-val! dirty-ref true)
(let [up? (kbd/up-arrow? event)
@@ -398,7 +409,8 @@
node (mf/ref-val ref)
open-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
(and (some? options) open-tokens)
@@ -418,8 +430,8 @@
(dom/prevent-default event)
(if focused-id
(on-option-enter event)
(let [option-id (first-focusable-id dropdown-options)
option (get-option dropdown-options option-id)
(let [option-id (first-focusable-id options)
option (get-option options option-id)
value (get option :resolved-value)
name (get option :name)]
(on-token-apply option-id value name)
@@ -461,7 +473,7 @@
(update-input (fmt/format-number new-val))
(apply-value (dm/str new-val))))))))
handle-focus
on-focus
(mf/use-fn
(mf/deps on-focus select-on-focus)
(fn [event]
@@ -473,7 +485,7 @@
;; 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})))))
handle-mouse-wheel
on-mouse-wheel
(mf/use-fn
(mf/deps apply-value parse-value min max nillable ref default step min max)
(fn [event]
@@ -580,8 +592,8 @@
placeholder)
:default-value (or (mf/ref-val last-value*) (fmt/format-number value))
:on-blur on-blur
:on-key-down handle-key-down
:on-focus handle-focus
:on-key-down on-key-down
:on-focus on-focus
:on-change store-raw-value
:disabled disabled
:slot-start (when icon
@@ -603,11 +615,12 @@
token-props
(when (and token-applied (not= :multiple token-applied))
(let [token (get-option-by-name dropdown-options token-applied)
id (get token :id)
label (get token :name)
(let [token (get-option-by-name dropdown-options token-applied)
id (get token :id)
label (get token :name)
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
{:id id
:label label
@@ -649,9 +662,9 @@
(when-let [node (mf/ref-val ref)]
(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)]
(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))))
(mf/with-effect [dropdown-options]
@@ -666,11 +679,12 @@
[:> input-field* input-props])
(when ^boolean is-open
[:> options-dropdown* {:on-click on-option-click
:id listbox-id
:options dropdown-options
:selected selected-id
:focused focused-id
:align align
:empty-to-end empty-to-end
:ref set-option-ref}])]))
(let [options (if (delay? dropdown-options) @dropdown-options dropdown-options)]
[:> options-dropdown* {:on-click on-option-click
:id listbox-id
:options options
:selected selected-id
:focused focused-id
:align align
:empty-to-end empty-to-end
:ref set-option-ref}]))]))

View File

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

View File

@@ -13,8 +13,8 @@ const Padded = ({ children }) => (
<div style={{ padding: "10px" }}>{children}</div>
);
const TabSwitcherWrapper = ({tabs, ...props}) => {
const navTabs = tabs.map(({content, ...item}) => {
const TabSwitcherWrapper = ({ tabs, ...props }) => {
const navTabs = tabs.map(({ content, ...item }) => {
return item;
});
@@ -28,7 +28,12 @@ const TabSwitcherWrapper = ({tabs, ...props}) => {
}, {});
return (
<TabSwitcher tabs={navTabs} selected={selected} onChange={setSelected} {...props}>
<TabSwitcher
tabs={navTabs}
selected={selected}
onChange={setSelected}
{...props}
>
{content[selected]}
</TabSwitcher>
);
@@ -77,12 +82,7 @@ export default {
},
parameters: {
controls: {
exclude: [
"tabs",
"actionButton",
"default",
"actionButtonPosition",
],
exclude: ["tabs", "actionButton", "default", "actionButtonPosition"],
},
},
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)))
window-size (dom/get-window-size)]
(when-let [[placement placement-rect] (find-matching-placement placement tooltip-brect origin-brect window-size offset)]
(let [height (if (or (= placement "right") (= placement "left"))
(- (:height placement-rect) arrow-height)
(:height placement-rect))]
(dom/set-data! tooltip "height" (:height tooltip-brect))
(dom/set-data! tooltip "width" (:width tooltip-brect))
(let [height (:height placement-rect)]
(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-inline-start" (dm/str (:left placement-rect) "px")))
@@ -253,7 +249,7 @@
:on-focus on-show
:on-blur on-hide
:on-key-down handle-key-down
:class (stl/css :tooltip-trigger)
:class [class (stl/css :tooltip-trigger)]
:aria-describedby id})
content
(if (fn? content)
@@ -262,7 +258,7 @@
[:> :div props
children
[:div {:class [class (stl/css :tooltip)]
[:div {:class (stl/css :tooltip)
:id id
:popover "auto"
:role "tooltip"}

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,7 +22,8 @@
(def ^:private 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)
head (first selected)

View File

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

View File

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

View File

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

View File

@@ -31,49 +31,77 @@
(let [shape-id (dm/get-prop shape :id)
shape-type (dm/get-prop shape :type)
ids (mf/with-memo [shape-id]
[shape-id])
ids
(mf/with-memo [shape-id]
[shape-id])
shapes (mf/with-memo [shape]
[shape])
shapes
(mf/with-memo [shape]
[shape])
stroke-values (select-keys shape stroke-attrs)
layer-values (select-keys shape layer-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)
stroke-values
(select-keys shape stroke-attrs)
layer-values
(select-keys shape layer-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
(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)
parents-by-ids-ref
(mf/with-memo [ids]
(refs/parents-by-ids ids))
parents
(mf/deref parents-by-ids-ref)
is-layout-container? (ctl/any-layout? shape)
is-flex-layout? (ctl/flex-layout? 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))]
is-layout-container?
(ctl/any-layout? shape)
is-flex-layout?
(ctl/flex-layout? 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
@@ -82,7 +110,7 @@
[:> measures-menu* {:ids ids
:values measure-values
:type shape-type
:shape shape}]
:shapes shapes}]
[:& component-menu {:shapes shapes}]

View File

@@ -8,9 +8,9 @@
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[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.color-selection :refer [color-selection-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]]
[rumext.v2 :as mf]))
(mf/defc options
{::mf/wrap [mf/memo]
::mf/wrap-props false}
[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)
(mf/defc options*
{::mf/wrap [mf/memo]}
[{:keys [shape shapes-with-children libraries file-id] :as props}]
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids))
is-flex-parent? (mf/deref is-flex-parent-ref)
(let [id (dm/get-prop shape :id)
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))
is-grid-parent? (mf/deref is-grid-parent-ref)
objects
(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)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
parents (mf/deref parents-by-ids-ref)
svg-values
(select-keys shape [:svg-attrs])
type :group
[measure-ids measure-values] (get-attrs [shape] objects :measure)
[layer-ids layer-values] (get-attrs [shape] objects :layer)
[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-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)
[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)}
[:& 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
{:type type
@@ -116,7 +157,6 @@
[:& ot/text-menu {:type type :ids text-ids :values text-values}])
(when-not (empty? svg-values)
[:& svg-attrs-menu {:ids svg-ids
:values svg-values}])]))
[:& svg-attrs-menu {:ids ids :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
[app.common.attrs :as attrs]
[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.types.component :as ctk]
[app.common.types.path :as path]
[app.common.types.shape.attrs :refer [editable-attrs]]
[app.common.types.shape.layout :as ctl]
[app.common.types.text :as txt]
[app.common.weak :as weak]
[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.color-selection :refer [color-selection-menu*]]
[app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu]]
@@ -202,10 +204,6 @@
applies (some of them ignore some attributes)"
[shapes objects attr-group]
(let [attrs (group->attrs attr-group)
default-text-attrs
(txt/get-default-text-attrs)
merge-attrs
(fn [v1 v2]
(cond
@@ -213,8 +211,21 @@
(= attr-group :blur) (attrs/get-attrs-multi [v1 v2] attrs blur-eq blur-sel)
: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
(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])
editable-attrs (filter (get editable-attrs (:type shape)) attrs)]
(case read-mode
@@ -228,144 +239,192 @@
(into {} (map #(vector % nil)) editable-attrs)
(cond
(= 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)
(merge-attrs values shape-values)])
(merge-attrs values shape-values)
new-token-acc])
:text
(let [shape-attrs (select-keys shape 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
(-> values
(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)
new-values])
new-values
new-token-acc])
:children
(let [children (->> (:shapes shape []) (map #(get objects %)))
[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*))
(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)))
(def get-attrs
(weak/memoize get-attrs*))
(defn- is-bool-descendant?
[[_ shape] objects selected-shape-ids]
[objects selected-shape-ids shape]
(let [parent-id (:parent-id shape)
parent (get objects parent-id)]
(cond
(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
(= :bool (:type parent)) true ;; if its parent is of type bool, it is a bool descendant
(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
(= :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
(mf/defc options
{::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "shapes-with-children" "page-id" "file-id"]))]
::mf/wrap-props false}
[props]
(let [shapes (unchecked-get props "shapes")
shapes-with-children (unchecked-get props "shapes-with-children")
(defn- check-options-props
[new-props old-props]
(and (= (unchecked-get new-props "shapes")
(unchecked-get old-props "shapes"))
(= (unchecked-get new-props "shapesWithChildren")
(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
shape-ids (into #{} (map :id) shapes)
(mf/defc options*
{::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
(into {}
(filter #(not (is-bool-descendant? % objects shape-ids)))
objects)
(mf/with-memo [shapes-with-children]
(let [objects (d/index-by :id shapes-with-children)]
(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)
shapes (map #(gsh/transform-shape % (get-in workspace-modifiers [(:id %) :modifiers])) shapes)
[layer-ids layer-values]
(get-attrs shapes objects :layer)
page-id (unchecked-get props "page-id")
file-id (unchecked-get props "file-id")
shared-libs (unchecked-get props "libraries")
[text-ids text-values]
(get-attrs shapes objects :text)
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
;; so we can memoize it
objects-no-measures (->> objects (d/mapm basic-shape))
objects-no-measures (hooks/use-equal-memo objects-no-measures)
[fill-ids fill-values]
(get-attrs shapes objects :fill)
[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
all-types (into #{} (map :type shapes))
ids (->> shapes (map :id))
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)
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)]
;; NOTE: we only need transformed shapes for the measure menu,
;; the rest of menus can live with shapes not transformed; we
;; also don't use the memoized version of get-attrs because it
;; makes no sense because the shapes object are changed on
;; each rerender.
[measure-ids measure-values]
(get-attrs* shapes objects :measure)]
[:div {:class (stl/css :options)}
(when-not (empty? layer-ids)
[:& layer-menu {:type type :ids layer-ids :values layer-values}])
(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}])
[:& layout-container-menu
@@ -394,15 +453,18 @@
[:> fill/fill-menu* {:type type :ids fill-ids :values fill-values}])
(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?}])
(when-not (empty? shapes)
[:> color-selection-menu*
{:file-id file-id
:type type
:shapes (vals objects-no-measures)
:libraries shared-libs}])
:shapes shapes
:libraries libraries}])
(when-not (empty? shadow-ids)
[:> shadow-menu* {:type type

View File

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

View File

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

View File

@@ -7,10 +7,10 @@
(ns app.main.ui.workspace.sidebar.options.shapes.svg-raw
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.types.color :as cc]
[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]
@@ -26,15 +26,10 @@
;; This is a list of svg tags that can be grouped in shape-container
;; 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 shorthex->longhex [hex]
(let [[_ r g b] hex]
(str "#" r r g g b b)))
(defn parse-color [color]
(defn- parse-color [color]
(try
(cond
(or (not color) (= color "none")) nil
@@ -51,8 +46,7 @@
(.error js/console "Error parsing color" e)
nil)))
(defn get-fill-values [shape]
(defn- get-fill-values [shape]
(let [fill-values (select-keys shape fill/fill-attrs)
color (-> (or (get-in shape [:content :attrs :fill])
(get-in shape [:content :attrs :style :fill]))
@@ -64,7 +58,7 @@
fill-values)]
fill-values))
(defn get-stroke-values [shape]
(defn- get-stroke-values [shape]
(let [stroke-values (select-keys shape stroke-attrs)
color (-> (or (get-in shape [:content :attrs :stroke])
(get-in shape [:content :attrs :style :stroke]))
@@ -92,42 +86,75 @@
stroke-values)]
stroke-values))
(mf/defc options
(mf/defc options*
{::mf/wrap [mf/memo]}
[{:keys [shape] :as props}]
(let [ids [(:id shape)]
type (:type shape)
(let [id (dm/get-prop shape :id)
type (dm/get-prop shape :type)
ids (mf/with-memo [id] [id])
shapes (mf/with-memo [shape] [shape])
{:keys [tag] :as content} (:content shape)
measure-values (select-keys shape measure-attrs)
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)
{:keys [tag] :as content}
(get shape :content)
is-layout-child-ref (mf/use-memo (mf/deps ids) #(refs/is-layout-child? ids))
is-layout-child? (mf/deref is-layout-child-ref)
fill-values
(mf/with-memo [shape]
(get-fill-values shape))
is-flex-parent-ref (mf/use-memo (mf/deps ids) #(refs/flex-layout-child? ids))
is-flex-parent? (mf/deref is-flex-parent-ref)
stroke-values
(mf/with-memo [shape]
(get-stroke-values shape))
is-grid-parent-ref (mf/use-memo (mf/deps ids) #(refs/grid-layout-child? ids))
is-grid-parent? (mf/deref is-grid-parent-ref)
measure-values
(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)
parents-by-ids-ref (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
parents (mf/deref parents-by-ids-ref)]
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)]
(when (contains? svg-elements tag)
[:*
[:> measures-menu* {:ids ids
:type type
:values measure-values
:shape shape}]
:shapes shapes}]
[:& layout-container-menu
{:type type

View File

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

View File

@@ -53,7 +53,7 @@
(mf/defc tokens-section*
{::mf/private true}
[{:keys [tokens-lib]}]
[{:keys [tokens-lib active-tokens resolved-active-tokens]}]
(let [objects (mf/deref refs/workspace-page-objects)
selected (mf/deref refs/selected-shapes)
open-status (mf/deref ref:token-type-open-status)
@@ -66,18 +66,9 @@
(mf/with-memo [selected-shapes objects]
(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
;; name, it is ephimeral and can be nil
;; FIXME: this is a repeated deref for the same `:workspace-tokens` state
selected-token-set-name
(mf/deref refs/selected-token-set-name)
@@ -92,8 +83,8 @@
(ctob/get-tokens-map selected-token-set))
tokens
(mf/with-memo [active-theme-tokens selected-token-set-tokens]
(merge active-theme-tokens selected-token-set-tokens))
(mf/with-memo [active-tokens selected-token-set-tokens]
(merge active-tokens selected-token-set-tokens))
tokens
(sd/use-resolved-tokens* tokens)
@@ -154,7 +145,7 @@
:type type
:selected-shapes selected-shapes
:is-selected-inside-layout is-selected-inside-layout
:active-theme-tokens active-theme-tokens'
:active-theme-tokens resolved-active-tokens
:tokens tokens}]))
(for [type empty-group]
@@ -162,5 +153,5 @@
:type type
:selected-shapes selected-shapes
:is-selected-inside-layout :is-selected-inside-layout
:active-theme-tokens active-theme-tokens'
:active-theme-tokens resolved-active-tokens
:tokens []}])]))

View File

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