Combined fixes from PR #10656 (numeric-input redesign) and PR #10696
(global finite? guard) for issue #10638.
- Add (number? v) guard to cljs mth/finite? so strings are rejected
- Redesign numeric-input last-value* to store number, not formatted string
- Invalid-input fallback restores display without emitting on-change
- Esc now fully discards typed text (resets raw-value* + dirty flag)
- Token dedup by name instead of resolved value
- Defense-in-depth: d/parse-double at 4 padding/gap handlers
- Math tests (common), unit tests, Storybook play tests, Playwright E2E
AI-assisted-by: deepseek-v4-flash
Co-authored-by: Akshit Nassa <nassaakshit@gmail.com>
Co-authored-by: Ulises Millán <ulises.millanguerrero@gmail.com>
Repair text shapes with empty/broken content at all three levels
(root, paragraph-set, paragraph) in migration 0025 to prevent
workspace update failures. Handle all corner cases: nil/empty/non-
vector children, non-map items, wrong types. Remove geometry-only
validation skip in changes.cljc so all shapes are validated.
AI-assisted-by: qwen3.7-plus
Guard remaining text pipeline locations that accessed :selrect directly
against nil/zero-dimension selrects by using safe-size-rect, which
provides a 4-level fallback chain (selrect -> points -> shape fields ->
empty 0.01x0.01 rect).
Fixes:
- fix-position in viewport_texts_html.cljs: replaced dm/get-prop
:selrect with ctm/safe-size-rect for both old and new shape
- assoc-position-data in modifiers.cljs: replaced (:selrect ...)
with ctm/safe-size-rect for delta computation
- change-orientation-modifiers in modifiers.cljc: replaced raw
:selrect access with safe-size-rect for scale and origin computation
Closes#10617
AI-assisted-by: mimo-v2.5-pro
Guard the content-to-PathData coercion on whether
stp/convert-to-path actually produced a new value, so
SVG-raw shapes (whose :content is a hiccup map) pass through
unchanged instead of crashing.
Closes#10612
AI-assisted-by: deepseek-v4-pro
Preserve real size overrides during variant switches without copying stale absolute composite geometry from the source variant.
Signed-off-by: Codex <codex@openai.com>
* Revert "🐛 Detect duplicated token names in the whole library (#9034)"
This reverts commit 61cd7573553b1c5e9fc2d7300cf9b2c36b4dcbb6.
* 🔧 Preserve some enhancements and fixes that are still valid
* 🔧 Fix broken integration tests
* 🐛 Fix DTCG token import discriminator and group-level $type inheritance
Closes#8342.
The DTCG Community Group Final Report (W3C, 2025-10-28) specifies:
"The presence of a $value property definitively identifies an object
as a token."
"A token's type can be specified by the optional $type property [...]
Furthermore, the $type property on a group applies to all tokens
nested within that group."
Two bugs in `common/src/app/common/types/tokens_lib.cljc` violate the
spec and silently break import of any third-party DTCG file that uses
group-level type inheritance:
1. `flatten-nested-tokens-json` used `(not (contains? v "$type"))` as
the group-vs-token discriminator. A group node carrying only a
`$type` (to set a default for child tokens) was misidentified as a
token, then immediately discarded because it had no `$value`.
2. `schema:dtcg-node` declared both `$type` and `$value` as required,
so even after the discriminator was fixed any leaf token that
relied on group-level type inheritance failed `dtcg-node?`
validation and never reached the parser.
The combined effect: importing a spec-compliant DTCG file that
expressed types at the group level produced a TokensLib with no
tokens at all, because every leaf was discarded as "unknown type".
Penpot-exported files were unaffected because Penpot always emits
both `$type` and `$value` on every token and never attaches `$type`
to a group, so the existing tests covered only the inline-type
shape.
- `schema:dtcg-node`: mark `$type` optional.
- `flatten-nested-tokens-json`: use `$value` as the discriminator
(anything without `$value` is a group), accept an optional
`inherited-type` accumulator that carries the nearest enclosing
group `$type` down through recursion, and resolve a token's type
from its own `$type` first, falling back to the inherited type.
A token's own `$type` always wins over the inherited one (per
spec).
Added `parse-dtcg-group-type-inheritance` covering both cases:
- group `$type` is inherited by tokens that don't declare their own
(`colors.red`, `colors.blue`, `space.small`)
- token `$type` overrides the inherited group `$type`
(`colors.danger`, `space.large`)
Existing DTCG round-trip tests continue to pass because they all
declare `$type` at the token level, which the new code still honours.
CHANGES.md entry added under the 2.17.0 Bugs-fixed section.
* 📚 Do not update CHANGES.md
We are changing the procedures to not update the changelog on each PR. Instead, we use github tracking to check what issues come in a release, and update the changelog automatically in a batch.
Signed-off-by: Andrés Moya <hirunatan@hammo.org>
---------
Signed-off-by: Andrés Moya <hirunatan@hammo.org>
Co-authored-by: MilosM348 <milos.milic001@outlook.com>
* ⚡ Improve performance and fix orphan detection in validate-file
- Add `*ref-shape-cache*` dynamic var to memoize `find-ref-shape`
lookups per page, avoiding repeated O(depth) ancestor walks.
- Add `*children-sets*` pre-computed maps for O(1) parent-child
containment checks, replacing linear `some` scans.
- Short-circuit `inside-component-main?` when the shape context
already implies a main component.
- Use single-pass reduce with early exit for duplicate detection
(children, swap slots) instead of count/distinct or frequencies.
- Guard `check-missing-slot` to skip expensive `find-near-match`
when the shape already has a swap slot.
- Refactor variant-set validation to use `run!` with direct `get`.
- Refactor `check-ref-cycles` to use a single `reduce-kv` pass.
- Fix `get-orphan-shapes`: the original `map` pipeline produced
nils so orphan shapes were never validated; rewrite with
`reduce-kv` for correct results.
- Add `validate-file-affected!` for change-scoped validation,
replacing full file validation in `process-changes-and-validate`
to only validate pages and components touched by the changes.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Improved validation
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: alonso.torres <alonso.torres@kaleidos.net>
Do not show the library sync popup when the only differences are global x/y changes on library components. We now generate the actual sync changes and only notify if there are real redo-changes to apply.
Run cll/generate-sync-file-changes for candidate libraries and filter out those with empty :redo-changes. The expensive check is deferred via rx/timer 0 so it runs asynchronously and does not block the UI.
Why: Position-only changes are normalized during sync (via reposition-shape) and never propagate to copies; showing the popup in that case was a false positive.
Performance: The check is deferred to the next tick to avoid UI stutter on large files with many libraries.
Add focused common JavaScript test execution with log-level control and a quiet test wrapper matching the frontend workflow.
Update developer docs and testing memories to reflect the common/frontend test split, and document why runner helper extraction is deferred.
Signed-off-by: Codex <codex@openai.com>
Add a shared `schema:font-family` whitelist validator in
app.common.types.font that only allows letters, digits, spaces,
hyphens, underscores, and dots in font family names. Apply the schema
to create-font-variant and update-font RPC endpoints on the
backend, and add client-side validation in the dashboard fonts UI.
Include unit tests for the schema and integration tests for the RPC
handlers.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>