* Fix rotation recalculation corrupting compound transforms
Two bugs in the rotation center recalculation triggered by attribute
changes on rotated elements:
1. The recalculation fires for ALL attribute changes (stroke-width,
fill, opacity, etc.) even though only geometric attributes (x, y,
width, height, d, points, etc.) can change the bbox center. This
causes unnecessary and incorrect rotation center updates.
2. In undo.js, the center is computed through ALL remaining transforms
via transformListToTransform(tlist).matrix, but for compound
transform lists like [translate(tx,ty), rotate(angle)], the
pre-rotation translate leaks into the center calculation, producing
rotate(angle, bcx+tx, bcy+ty) instead of the correct
rotate(angle, bcx, bcy).
3. In history.js (undo/redo), the code replaces the ENTIRE transform
attribute with just rotate(...), completely destroying any other
transforms (translate, scale, etc.) in the list.
Fixes:
- Guard recalculation with a BBOX_AFFECTING_ATTRS set so non-geometric
attribute changes skip the rotation block entirely.
- In undo.js, use transformListToTransform(tlist, n, max) to compute
the center through only post-rotation transforms.
- In history.js, replace string-based transform replacement with
transform list API that finds and updates only the rotation entry,
preserving all other transforms. Extract shared logic into
relocateRotationCenter() helper.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add tests for rotation recalculation with compound transforms
Tests demonstrate and verify fixes for three bugs:
1. Non-geometric attributes (stroke-width, fill, opacity) no longer
trigger rotation center recalculation — the transform list is
left untouched.
2. Geometric attribute changes on elements with compound transforms
(e.g. translate + rotate) compute the rotation center using only
post-rotation transforms, preventing the translate from leaking
into the center calculation.
3. ChangeElementCommand.apply/unapply preserve compound transform
structure instead of replacing the entire transform attribute
with just rotate(...).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add visual demo and screenshot for rotation recalculation bug
Includes an HTML demo showing both bugs side-by-side:
- Bug 1: Non-geometric attribute changes (stroke-width) on compound
transforms corrupt character positions (e.g., word art on curves)
- Bug 2: Rotation center computed through ALL transforms instead of
only post-rotation transforms, causing translate to leak into center
Each panel shows Original / Buggy / Fixed comparisons with the actual
SVG transform math applied. A Playwright script generates screenshots.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add sample SVG demonstrating compound transform corruption bug
A pinwheel of 6 colored rectangles using translate(200,200) rotate(N).
Loading this into SVG-Edit and changing stroke-width on the group
triggers the rotation recalculation bug on unfixed builds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix standard linting: object properties on separate lines
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Centralize BBOX_AFFECTING_ATTRS and fix bbox-before-remove safety
Address two code review comments:
1. Export BBOX_AFFECTING_ATTRS from history.js and import it in undo.js
so the attribute list is defined in one place.
2. Compute getBBox() before calling tlist.removeItem() so that a falsy
bbox causes an early return/break without having already destroyed
the rotation transform.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When editing text inside a group element, the text cursor was appearing
in the wrong position because only the text element's own transform was
being considered, ignoring transforms from parent groups.
This change:
- Adds a new #getAccumulatedMatrix() method that traverses up the DOM tree
from the text element to the SVG content element, collecting and multiplying
all transform matrices along the way
- Updates the init() method to use this accumulated matrix instead of just
the text element's transform
- Updates test mock to include getSvgContent() method
Fixes the issue where editing text inside a transformed group would show
the cursor at the wrong position.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Update svgWhiteList in sanitize.js to include 'font-stretch' for relevant SVG elements
* Refactor svgWhiteList in sanitize.js to utilize FONT_ATTRIBUTES for better maintainability and consistency across SVG elements
Upgraded several dependencies and devDependencies in package.json and package-lock.json, including Babel, core-js, browser-fs-access, i18next, jspdf, cypress, and rollup. Test coverage improved in multiple files as reflected in coverage-summary.json.
* Update history.js
- Change `BatchCommand.unapply` to use `[...this.commands].reverse()` so the original array is never mutated.
- This preserves the order of commands and ensures history integrity.
* Added alt tags to img elements.
* fixed lint issues
* Changed the SESpinInput to have a closed shadow DOM to fix the duplicate label id issue reported in browser.
* Fixed code in EditorStartup that fails if the editor is in a Web Component. $qq will not find the .svg_editor, but this.$container will.
* fix linter issue
* update packages
* remove closed as this causes the test to fail.
---------
Co-authored-by: JFH <20402845+jfhenon@users.noreply.github.com>