Adopts the rumext * suffix convention for the following components,
invoking them with the [:> JS-style syntax to match the rest of the
codebase (see e.g. rea*, single-selection* in viewport/selection):
- measurements: size-display, distance-display-pill, selection-rect,
distance-display, selection-guides, measurement
- shapes/svg-defs: svg-node, svg-defs (also drop the now-redundant
{::mf/wrap-props false} annotations)
Updates all call sites in inspect/selection_feedback, shapes/shape,
workspace/viewport, and workspace/viewport_wasm. Pure rename — no
behavioral change.
Signed-off-by: bitcompass <devwiz.sh@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Add read-only preview mode for saved versions (#7622)
* 🔧 Address review feedback on version preview (#7622)
* 🐛 Fix version preview for WASM renderer (#7622)
* 🐛 Fix stylelint color-named and color-function-notation in preview banner (#7622)
* 🐛 Fix invalid-arity call to initialize-workspace in exit-preview (#7622)
* 🐛 Fix unclosed defn paren in exit-preview (#7622)
* ♻️ Refactor version preview/restore flow
Separate enter-preview and enter-restore flows with dedicated dialogs
instead of a persistent banner. Removes preview-banner component in favor
of inline actions dialog. Uses backup/restore pattern for exit-preview
instead of full workspace reinitialization. Adds analytics events for
preview/restore actions.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ⚡ Extract on-name-input-focus as namespace-level private function
The callback had no dependencies on component-local state or props,
making it a pure function that can be hoisted to a defn-. This avoids
recreating the same callback identity on every render of version-entry*.
* ⚡ Extract extract-id-from-event helper to deduplicate snapshot callbacks
Three callbacks in snapshot-entry* shared the same DOM extraction logic
(get current target, read data-id, parse UUID). Extracted into a private
defn- to remove the duplication and simplify each callback.
* ⚡ Extract pure state-update callbacks from versions-toolbox* to namespace level
Eight callbacks that only emit fixed Potok events with no meaningful
deps were hoisted out of the component as defn- functions:
- on-create-version
- on-edit-version
- on-cancel-version-edition
- on-rename-version
- on-delete-version
- on-pin-version
- on-lock-version
- on-unlock-version
These no longer need mf/use-fn wrappers since namespace-level functions
have stable identity across renders, avoiding unnecessary callback
recreation on each render cycle.
* ✨ Rename filter parameter to filter-value in on-change-filter to avoid core shadowing
The parameter name 'filter' shadowed clojure.core/filter within the
function scope. Renamed to 'filter-value' for clarity and to prevent
potential bugs if core/filter were needed in future changes.
* 🔧 Fix linter warnings and errors across version-related namespaces
frontend/src/app/main/ui/workspace.cljs:
- Remove unused requires: app.common.data, app.main.data.notifications,
app.main.data.workspace.versions
frontend/src/app/main/data/workspace/versions.cljs:
- Remove unused require: app.common.uuid
- Fix duplicate reify type: enter-restore used ::restore-version
(same as the private restore-version fn), renamed to ::enter-restore
- Remove unused bindings: state in enter-restore, team-id in
exit-preview and restore-version-from-plugin
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Signed-off-by: wdeveloper16 <wdeveloer16@protonmail.com>
Co-authored-by: wdeveloper16 <wdeveloer16@protonmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
- Add session ID tracking to RPC layer (backend and frontend)
- Send session ID header with RPC requests for request correlation
- Rename file-restore to file-restored for consistency
- Extract initialize-file function from initialize-workspace flow
- Improve file restoration initialization with wait-for-persistence
- Extract initialize-version event handler for version restoration
- Fix viewport key generation with file version numbers for proper re-renders
- Update layout item schema and constraints to use internal sizing state
- Add v-sizing state retrieval in layout-size-constraints component
- Refactor file-change notifications stream handling with rx/map
- Fix team-id lookup in restore-version-from-plugins
Improves request traceability across frontend/backend sessions and streamlines
the workspace initialization flow for file restoration scenarios.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
- Add session ID tracking to RPC layer (backend and frontend)
- Send session ID header with RPC requests for request correlation
- Rename file-restore to file-restored for consistency
- Extract initialize-file function from initialize-workspace flow
- Improve file restoration initialization with wait-for-persistence
- Extract initialize-version event handler for version restoration
- Fix viewport key generation with file version numbers for proper re-renders
- Update layout item schema and constraints to use internal sizing state
- Add v-sizing state retrieval in layout-size-constraints component
- Refactor file-change notifications stream handling with rx/map
- Fix team-id lookup in restore-version-from-plugins
Improves request traceability across frontend/backend sessions and streamlines
the workspace initialization flow for file restoration scenarios.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Convert viewport-scrollbars to viewport-scrollbars* using {:keys [...]}
destructuring and update call sites in viewport.cljs and viewport_wasm.cljs
to use [:> ...].
* ♻️ 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.
* 🐛 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>
* ⬆️ Update opencode and copilot deps
* 🐛 Decouple workspace-content from workspace-local to reduce scroll re-renders
Move workspace-local subscription from workspace-content* (parent) into
viewport* and viewport-classic* (children). workspace-content* now only
subscribes to the new workspace-vport derived atom, which changes only on
window resize — not on every scroll event. This prevents the sidebar,
palette and other workspace-content children from re-rendering on scroll.
* 🐛 Throttle wheel events to one state update per animation frame
Accumulate wheel event deltas in a mutable ref and flush them via
requestAnimationFrame, so that multiple wheel events between frames
produce a single state mutation instead of one per event. This prevents
the cascade of synchronous React re-renders (via useSyncExternalStore)
that can exceed the maximum update depth on rapid scrolling.
Both panning (scroll) and zoom (ctrl/mod+wheel) are throttled. Scroll
deltas are summed additively; zoom scales are compounded multiplicatively
with the latest cursor point used as the zoom center.
* ♻️ Extract schedule-zoom! and schedule-scroll! from on-mouse-wheel
* ♻️ Avoid zoom dep on on-mouse-wheel by using a ref
* ⬆️ Update opencode and copilot deps
* 🐛 Decouple workspace-content from workspace-local to reduce scroll re-renders
Move workspace-local subscription from workspace-content* (parent) into
viewport* and viewport-classic* (children). workspace-content* now only
subscribes to the new workspace-vport derived atom, which changes only on
window resize — not on every scroll event. This prevents the sidebar,
palette and other workspace-content children from re-rendering on scroll.
* 🐛 Throttle wheel events to one state update per animation frame
Accumulate wheel event deltas in a mutable ref and flush them via
requestAnimationFrame, so that multiple wheel events between frames
produce a single state mutation instead of one per event. This prevents
the cascade of synchronous React re-renders (via useSyncExternalStore)
that can exceed the maximum update depth on rapid scrolling.
Both panning (scroll) and zoom (ctrl/mod+wheel) are throttled. Scroll
deltas are summed additively; zoom scales are compounded multiplicatively
with the latest cursor point used as the zoom center.
* ♻️ Extract schedule-zoom! and schedule-scroll! from on-mouse-wheel
* ♻️ Avoid zoom dep on on-mouse-wheel by using a ref