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>
Step toward issue #9260 (incremental migration of legacy UI
components to the modern `*`-suffixed syntax, removing the per-render
JS-to-Clojure props conversion overhead).
Two unrelated namespaces, both clean Case-A migrations grouped in a
single PR for review efficiency.
frontend/src/app/main/ui/shapes/text/fontfaces.cljs
---------------------------------------------------
Three components, all previously using `::mf/wrap-props false` with a
custom memoizer (`#(mf/memo' % (mf/check-props ["fonts"]))`) and
reading `fonts` via `(obj/get props "fonts")`. The custom memoizer
existed because the legacy components received raw JS-object props,
where the default `mf/memo` Clojure-equality comparison would always
fail.
- `fontfaces-style-html` → `fontfaces-style-html*`
- `fontfaces-style-render` → `fontfaces-style-render*`
- `fontfaces-style` → `fontfaces-style*`
Migration:
- Standard destructuring `[{:keys [fonts]}]` replaces the
`[props]` + `(obj/get props "fonts")` pattern.
- `::mf/wrap-props false` removed.
- Custom memoizer collapses to `::mf/wrap [mf/memo]`. With modern
destructuring the props are Clojure data, so default `=`-based memo
is structurally correct (and a stronger guarantee than the previous
shallow JS-prop check).
- `app.util.object` require dropped from the namespace — it was only
used for the `obj/get props "fonts"` reads that are now gone.
- Internal call site of `fontfaces-style-render*` (within
`fontfaces-style*`) keeps its `[:>` form, just with the new name.
External call sites updated:
- `frontend/src/app/main/render.cljs` — three sites
(`[:& ff/fontfaces-style {:fonts fonts}]` × 3) →
`[:> ff/fontfaces-style* {:fonts fonts}]`.
- `frontend/src/app/main/ui/workspace/shapes.cljs` — one site,
call signature unchanged. (Note: this caller passes `:shapes`
rather than `:fonts`; the legacy component already ignored
`:shapes` because it only read `(obj/get props "fonts")`, so the
modern destructuring `{:keys [fonts]}` preserves the same
behavior. Pre-existing bug, intentionally left out of scope.)
frontend/src/app/main/ui/viewer/thumbnails.cljs
-----------------------------------------------
Four components, all using standard destructuring already (no
`::mf/wrap-props false`, no `unchecked-get`). Migration is the
straight `*` rename plus `?`-prop renames per the prompt's mapping:
- `thumbnails-content` → `thumbnails-content*` (`expanded?` →
`is-expanded`)
- `thumbnails-summary` → `thumbnails-summary*` (no `?`-props)
- `thumbnail-item` → `thumbnail-item*` (`selected?` →
`is-selected`; `::mf/wrap [mf/memo #(mf/deferred …)]` preserved)
- `thumbnails-panel` → `thumbnails-panel*` (`show?` →
`show` — no `is-` prefix needed, reads naturally as a verb)
Internal callsites of all three sub-components in `thumbnails-panel*`
updated to `[:> …*` with renamed kwargs (`:expanded?` →
`:is-expanded`, `:selected?` → `:is-selected`).
The `expanded?` symbol still appears in `thumbnails-panel*`'s body —
it's a local `let`-binding deref'd from the `expanded-state` atom,
not a component param, so the `?` suffix is preserved per the
prompt's "local bindings stay" rule.
External call sites updated:
- `frontend/src/app/main/ui/viewer.cljs` — one site, plus the
`:refer [thumbnails-panel]` → `:refer [thumbnails-panel*]` require
update.
Github #9260
Signed-off-by: FairyPigDev <luislee3108@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* 🐛 Fix incorrect invitation token handling on register process
- Reject prepare-register-profile when an active profile already
exists for the requested email.
- Stop embedding an existing profile's :profile-id into the
prepared-register JWE. Profile resolution in register-profile is
now done exclusively by email lookup, never by a JWE claim.
- Add created? guard to the invitation-success branch in
register-profile, so existing profiles (active or not) cannot
reach session creation via anonymous registration.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ♻️ Restructure invitation handling inside register-profile
Move the invitation-success branch into the created? sub-cond so it
sits alongside the other post-creation branches, making the control
flow consistent.
- Active new profile + matching invitation: mint session and return
:invitation-token (frontend redirects to :auth-verify-token).
- Not-yet-active new profile + matching invitation: embed the
invitation token inside the verify-email JWE and send the
verification email. When the user clicks the link, they get
logged in and the frontend completes the team-invitation flow.
- Extend send-email-verification! with an optional invitation-token
parameter propagated into the verify-email JWE claims.
- Update the frontend verify-email handler to navigate to
:auth-verify-token when the response carries :invitation-token.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* 🐛 Handle email-already-exists error on registration form
Add a specific handler for the [:validation :email-already-exists] error
code in the registration form's on-error callback. The backend raises
this error when an active profile already exists for the requested email,
but the frontend was falling through to the generic error message.
Now it shows the existing "Email already used" i18n message instead of
the generic "Something wrong has happened" toast.
* 🐛 Reset submitted state on registration form error
The on-error handler in the registration form was not resetting the
submitted? state, causing the submit button to remain disabled after
any error. The completion callback in rx/subs! only fires on success,
not on error.
Add (reset! submitted? false) at the beginning of the on-error handler
so the form becomes submittable again after any error, allowing the user
to fix their input and retry.
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* 🐛 Fix incorrect invitation token handling on register process
- Reject prepare-register-profile when an active profile already
exists for the requested email.
- Stop embedding an existing profile's :profile-id into the
prepared-register JWE. Profile resolution in register-profile is
now done exclusively by email lookup, never by a JWE claim.
- Add created? guard to the invitation-success branch in
register-profile, so existing profiles (active or not) cannot
reach session creation via anonymous registration.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ♻️ Restructure invitation handling inside register-profile
Move the invitation-success branch into the created? sub-cond so it
sits alongside the other post-creation branches, making the control
flow consistent.
- Active new profile + matching invitation: mint session and return
:invitation-token (frontend redirects to :auth-verify-token).
- Not-yet-active new profile + matching invitation: embed the
invitation token inside the verify-email JWE and send the
verification email. When the user clicks the link, they get
logged in and the frontend completes the team-invitation flow.
- Extend send-email-verification! with an optional invitation-token
parameter propagated into the verify-email JWE claims.
- Update the frontend verify-email handler to navigate to
:auth-verify-token when the response carries :invitation-token.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* 🐛 Handle email-already-exists error on registration form
Add a specific handler for the [:validation :email-already-exists] error
code in the registration form's on-error callback. The backend raises
this error when an active profile already exists for the requested email,
but the frontend was falling through to the generic error message.
Now it shows the existing "Email already used" i18n message instead of
the generic "Something wrong has happened" toast.
* 🐛 Reset submitted state on registration form error
The on-error handler in the registration form was not resetting the
submitted? state, causing the submit button to remain disabled after
any error. The completion callback in rx/subs! only fires on success,
not on error.
Add (reset! submitted? false) at the beginning of the on-error handler
so the form becomes submittable again after any error, allowing the user
to fix their input and retry.
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Change isVariant() return type from boolean to 'this is LibraryVariantComponent',
enabling TypeScript users to directly access variants, variantProps, and
variantError after a type-narrowing check. Update MCP instructions with
improved variant navigation guidance.
Closes#9185
Co-authored-by: Claude (Anthropic) <noreply@anthropic.com>
Remove the :canary flag from the flags definition and make all
features gated behind it always available:
- Enable "download font" option in dashboard fonts context menu
- Enable Tab/Shift+Tab keyboard navigation for renaming shapes
in layer items
- Enable "duplicate color" option in asset panel when applicable
- Enable "duplicate typography" option in asset panel when applicable
- Enable "copy as image" context menu option for frame shapes
Also remove unused [app.config :as cf] requires from files that
no longer reference it after the materialization.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>