slider-selector (slider_selector.cljs):
- Rename to slider-selector*
- Rename prop vertical? to is-vertical
- Remove prop reverse? entirely: it was never passed by any callsite,
so the related reversal logic in calculate-pos and handler positioning
is also removed as dead code
value-saturation-selector (ramp.cljs):
- Rename to value-saturation-selector*
- Update internal call site to [:> value-saturation-selector* ...]
- Update slider-selector call sites to [:> slider-selector* ...]
harmony-selector (harmony.cljs):
- Rename to harmony-selector*
- Update slider-selector call sites to [:> slider-selector* ...] with
renamed is-vertical prop
- Remove stale duplicate :vertical true prop
- Fix spurious extra wrapping vector around the opacity slider in the
when branch
hsva-selector (hsva.cljs):
- Rename to hsva-selector*
- Update all four slider-selector call sites to [:> slider-selector* ...]
- Remove no-op :reverse? false prop from the value slider
color-inputs (color_inputs.cljs):
- Rename to color-inputs*
colorpicker.cljs:
- Update :refer imports for color-inputs*, harmony-selector*,
hsva-selector* and libraries*
- Update all corresponding call sites from [:& ...] to [:> ...]
Convert typography-item, palette and text-palette to typography-item*,
palette* and text-palette* using {:keys [...]} destructuring. Rename
prop name-only? to is-name-only in typography-item*. Update internal
call sites to [:> ...] and update the :refer import in palette.cljs.
Convert active-sessions to active-sessions* (zero-prop component).
Update call site in right_header.cljs to use [:> ...] and update the
:refer import accordingly.
Convert coordinates to coordinates* using {:keys [...]} destructuring
and rename prop colorpalette? to is-colorpalette. Update call site in
workspace.cljs to use [:> ...] with new prop name.
Convert viewport-scrollbars to viewport-scrollbars* using {:keys [...]}
destructuring and update call sites in viewport.cljs and viewport_wasm.cljs
to use [:> ...].
Convert shape-distance-segment to shape-distance-segment* using {:keys [...]}
destructuring and update its internal call site in shape-distance to use [:> ...].
* 🔧 Validate only after propagation in tests
* 💄 Enhance some component sync traces
* 🔧 Add fake uuid generator for debugging
* 🐛 Remove old feature of advancing references when reset changes
Since long time ago, we only allow to reset changes in the top copy
shape. In this case the near and the remote shapes are the same, so
the advance-ref has no effect.
* 🐛 Fix some bugs and add validations, repair and migrations
Also added several utilities to debug and to create scripts that
processes files
* 🐛 Fix misplaced parenthesis passing propagate-fn to wrong function
The :propagate-fn keyword argument was incorrectly placed inside the
ths/get-shape call instead of being passed to tho/reset-overrides.
This caused reset-overrides to never propagate component changes,
making the test not validate what it intended.
* 🐛 Accept and forward :include-deleted? in find-near-match
Callers were passing :include-deleted? true but the parameter was not
in the destructuring, so it was silently ignored and the function
always hardcoded true. This made the API misleading and would cause
incorrect behavior if called with :include-deleted? false.
* 💄 Use set/union alias instead of fully-qualified clojure.set/union
The namespace already requires [clojure.set :as set], so use the alias
for consistency.
* 🐛 Add tests for reset-overrides with and without propagate-fn
Add two focused tests to comp_reset_test to cover the propagate-fn
path in reset-overrides:
- test-reset-with-propagation-updates-copies: verifies that resetting
an override on a nested copy inside a main and supplying propagate-fn
causes the canonical color to appear in all downstream copies.
- test-reset-without-propagation-does-not-update-copies: regression
guard for the misplaced-parenthesis bug; confirms that omitting
propagate-fn leaves copies with the overridden value because the
component sync never runs.
---------
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Add delete and duplicate buttons to typography dialog
Add delete and duplicate action buttons to the expanded typography
editing panel, allowing users to quickly manage typographies without
needing to close the panel and use the context menu.
Fixes#5270
* ♻️ Use DS icon-button for typography dialog actions
Address review feedback: replace raw `:button`/`:div` elements and
deprecated-icon usage with the design system `icon-button*` and
non-deprecated icons (`i/add`, `i/delete`, `i/tick`).
* ♻️ Only show typography delete/duplicate buttons in assets sidebar
`typography-entry` is reused from the right sidebar text options
panel, where the delete and duplicate actions don't make sense.
Add an `is-asset?` opt-in prop and gate the `on-delete`/`on-duplicate`
handlers behind it, so the buttons only appear when the entry is
rendered from the assets sidebar.
* ♻️ Move typography delete/duplicate handlers next to their use site
Refine the previous opt-in: instead of plumbing on-delete/on-duplicate
function props through typography-entry, build them directly inside
typography-advanced-options where they're actually rendered. The
component now takes :file-id and :is-asset? and gates the action
buttons on a single `show-actions?` flag.
---------
Signed-off-by: eureka0928 <meobius123@gmail.com>
When several library colors share the same RGB value but differ only
in opacity, append the alpha percentage (e.g. "#ff0000 50%") next to
the displayed default name and in the color bullet tooltip so users
can tell them apart at a glance.
Closes#6328
Signed-off-by: rockchris99 <chrisleo0721@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* ♻️ Convert snap-points components to modern rumext format
Migrate snap-point, snap-line, snap-feedback, and snap-points from
legacy mf/defc format to modern * suffix format. This enables
optimized props handling by the rumext macro, eliminating implicit
JS object wrapping overhead on each render. All internal and
external call sites updated to use [:> component* props] syntax.
* ♻️ Convert frame-title to modern rumext format
Migrate frame-title from legacy mf/defc format to modern * suffix
format. The component was using legacy implicit props wrapping without
::mf/wrap-props false or ::mf/props :obj, causing unnecessary JS
object conversion overhead on each render. The parent frame-titles*
call site updated to use [:> frame-title* props] syntax.
* ♻️ Convert interactions components to modern rumext format
Migrate interaction-marker, interaction-path, interaction-handle,
overlay-marker, and interactions from legacy mf/defc format to modern
* suffix format. These five components had zero props optimization
applied, causing implicit JS object wrapping on every render. All
internal and external call sites updated to use [:> component* props]
syntax.
* ♻️ Convert rulers components to modern rumext format
Migrate rulers-text, viewport-frame, and selection-area from legacy
mf/defc format to modern * suffix format. These three components in
the always-visible rulers layer had zero props optimization applied.
Internal call sites in the parent rulers component updated to use
[:> component* props] syntax.
* ♻️ Convert frame-grid components to modern rumext format
Migrate square-grid, layout-grid, grid-display-frame, and frame-grid
from legacy mf/defc format to modern * suffix format. These four
components render grid patterns per-frame with zero props optimization.
All internal and external call sites updated to use [:> component* props]
syntax.
* ♻️ Convert gradient handler components to modern rumext format
Migrate shadow, gradient-color-handler, and gradient-handler-transformed
from legacy mf/defc format to modern * suffix format. These components
are rendered during gradient editing with zero props optimization applied.
Internal call sites in gradient-handler-transformed and
gradient-handlers-impl updated to use [:> component* props] syntax.
* ♻️ Rename ?-ending props in modernized workspace viewport components
Apply prop naming rules to all * components migrated in the previous batch:
- remove-snap? -> remove-snap in snap-feedback* (and get-snap helper)
- selected? -> is-selected in interaction-path*
- hover-disabled? -> is-hover-disabled in overlay-marker* and interactions*
- show-rulers? -> show-rulers in viewport-frame*
Update all internal and external call sites consistently.
* 🐛 Fix get-snap call in snap-feedback* using JS props object
Modern rumext *-suffix components receive props as JS objects, not
Clojure maps. snap-feedback* was pushing the raw props object into the
rx/subject and get-snap was destructuring it as a Clojure map, causing
all keys to resolve to nil.
Fix by:
- Changing get-snap to take positional arguments (coord, shapes,
page-id, remove-snap, zoom) instead of a map-destructured opts arg
- Building an explicit Clojure map from the bound locals before pushing
to the subject
- Destructuring that map inside the rx/switch-map callback and calling
get-snap with positional args
Also mark get-snap and add-point-to-snaps as private (defn-), consistent
with the other helpers in the namespace — none are referenced externally.
The 'Move to' menu in the dashboard file context menu only filtered
out the first selected file's project from the available target list.
When multiple files from different projects were selected, the other
files' projects still appeared as valid targets, causing a 400
'cant-move-to-same-project' backend error.
Now all selected files' project IDs are collected and excluded from
the available target projects.
lambdaisland/uri's query-string->map uses :multikeys :duplicates by
default: a key that appears once yields a plain string, but the same
key repeated yields a vector. cljs.core/parse-long only accepts
strings and therefore threw "Expected string, got: object" whenever
a URL contained a duplicate 'index' parameter.
Add rt/get-query-param to app.main.router. The helper returns the
scalar value of a query param key, taking the last element when the
value is a sequential (i.e. the key was repeated). Use it at every
call site that feeds a query-param value into parse-long, in both
app.main.ui (page*) and app.main.data.viewer.
* 🐛 Allow viewers to select locked elements in canvas
* ✨ Add ability to lock guides to prevent accidental movement
---------
Signed-off-by: Dexterity104 <hatanokanjiro@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
When users switch between the Layers and Assets sidebar tabs, the
`assets-toolbox*` component unmounts and its local `use-state` is
discarded, so the search query and section filter are lost.
Lift the search term and section filter into a per-file, in-memory
session atom that survives tab switches but doesn't leak across files
or persist across reloads. Ordering and list-style continue to use
localStorage as before.
Closes#2913
Signed-off-by: eureka0928 <meobius123@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
Subgroups in asset libraries were rendered in hash-map order because
update-in descends into plain maps instead of sorted ones. Add a
recursive post-process that rebuilds every level as a sorted-map so
subfolders are alphabetical at every nesting depth.
Closes#2572
Signed-off-by: eureka928 <meobius123@gmail.com>
Refactor use-portal-container to allocate one persistent <div> per
logical category (:modal, :popup, :tooltip, :default) instead of
creating a new div for every component instance. This keeps the DOM
clean with at most four fixed portal containers and eliminates the
arbitrary growth of empty <div> elements on document.body while
preserving the removeChild race condition fix.
* ✨ Add visibility toggle for strokes
* ♻️ Use single emit! call for stroke visibility toggle
* 💄 Disable stroke controls when hidden, matching shadow/blur pattern
When a stroke is hidden, the alignment/style selects, cap selects, and
cap switch button are now disabled. A .hidden CSS class dims the
options area with reduced opacity. This matches the existing behavior
in shadow_row and blur menu where controls are disabled when the
effect is hidden.
* 💄 Move stroke hide button before remove button
---------
Signed-off-by: eureka928 <meobius123@gmail.com>
Add z-index to the sticky .nav element in the dashboard so that
section titles (Recent, Deleted) stay above scrolling content
instead of being obscured by project cards and file thumbnails.
Fixes#8577
Signed-off-by: rockchris99 <chrisleo0721@gmail.com>