Add a Layer submenu to the canvas element menu (BL-15992) - #8372
JohnThomson wants to merge 1 commit into
Conversation
|
[Claude Fable 5.1] Consulted Devin on 2026-09-17 up to commit 1ca995d (three review rounds: 47de296, b40d243, 1ca995d). Devin raised three bugs and three flags on the first commit, and one more bug on the second. All seven are mirrored as review threads below, each closed with its outcome:
The review of the final commit re-listed the same six earlier items, all of which the reviewed code already fixes or which were assessed above; it found nothing new. No Informational items. CI (pr-automation) passed on every commit; no other review bot posted. |
|
[Claude Sonnet 5] Checked the feature in a running Bloom from this branch (menu placement, icons, greyed-out states at the top and bottom of the stack, background image without a Layer item, keyboard shortcuts, and a parent/child bubble family moving as one unit all behave as described). One dependency came out of that check: moving an element on a page that has a child bubble shows a "A JavaScript error occurred" toast. The move itself completes correctly; the error is a latent ComicalJS bug that the level renumbering exposes. Every time Bloom turns bubble editing back on for a canvas, Comical leaks the previous generation of bubble objects with their mutation observers still attached, and a stale family bubble that wakes up after its level changed finds no relatives and dereferences The fix is in ComicalJS: BloomBooks/comical-js#121. Once that is merged (the publish workflow releases the next patch version automatically), this PR needs |
|
[Claude Fable 5.1] Consulted Devin on 2026-09-17 up to commit 813e959 (fourth round, for the comicaljs 0.4.2 bump). It re-listed only the six items already closed on their threads above and found nothing new. CI (pr-automation) passed; Reviewable's status stays pending until its mirrored discussions are marked resolved there. Also verified in a running Bloom with 0.4.2 actually served: Layer moves on a page with a child bubble no longer raise the JavaScript error toast. |
JohnThomson
left a comment
There was a problem hiding this comment.
@JohnThomson reviewed 19 files and all commit messages, and made 1 comment.
Reviewable status: 0 of 19 files reviewed, 7 unresolved discussions.
https://issues.bloomlibrary.org/youtrack/issue/BL-15992 Overlapping canvas elements were always stacked in the order they were added, with no way to change it. This adds a Layer submenu to the canvas element menu (the "..." button and the right-click menu), in its own group just before Duplicate and Delete, with Bring Forward (Ctrl+]), Bring to Front (Ctrl+Alt+]), Send Backwards (Ctrl+[) and Send to Back (Ctrl+Alt+[). The submenu uses the MUI LayersOutlined icon and the four item icons attached to the card, drawn as SvgIcon components (LayerIcons.tsx). Stacking order is the DOM order of the elements in the bloom-canvas, while ComicalJS draws and hit-tests bubbles by the `level` in each element's data-bubble spec. The new CanvasElementZOrder module moves the element in the DOM and then renumbers every level to match (background image first, at level 1) before calling Comical.update(). A bubble family (parent plus child bubbles, which share a level) moves as one unit; a family that had become scattered in the DOM is gathered next to its parent first, so every move is exactly one step. On game pages elements only move among their own kind (draggable or fixed), matching the rule that draggables stay on top; a family with any draggable member counts as draggable. The game code that pushes draggables to the top shares the level-renumbering helper. The submenu is hidden for the background image, which must stay behind everything, and disabled when there is only one movable element; the forward items are disabled at the top of the stack and the backward items at the bottom. LocalizableNestedMenuItem now passes `disabled` through so the submenu row itself can be disabled. The keyboard shortcuts accept either the physical US bracket keys or the bracket characters (an AltGr-typed bracket counts as the one-step shortcut), and are left alone when no canvas element is selected or text is being edited. comicaljs is updated to 0.4.2 (BloomBooks/comical-js#121): Comical leaked the previous generation of Bubble objects each time editing was turned back on, and after a level renumbering a stale family bubble threw in uniteShapes, which showed as a "JavaScript error" toast on any Layer move on a page with a child bubble. Five new strings in Bloom.xlf (EditTab.Toolbox.CanvasTool.Layer.*). Also fixes stale identifiers in the canvas toolbox README and logs a papercut about build/agent-vite.ps1 reporting exit code 1 on a successful build. Tests: CanvasElementZOrder.test.ts (moves, families, level renumbering, draggable bands), layerMenuItem.test.ts (menu placement, per-type inclusion, disabled states) and CanvasElementKeyboardProvider.test.ts (shortcuts, layouts). Full front-end suite green; typecheck and eslint clean; isolated Vite production build succeeds; verified by hand in a running Bloom. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
813e959 to
ce797d7
Compare
JohnThomson
left a comment
There was a problem hiding this comment.
@JohnThomson+AGNT resolved 7 discussions.
Reviewable status: 0 of 19 files reviewed, all discussions resolved.
Problem
When canvas elements (pictures, speech bubbles, text boxes, videos, buttons) overlap on a page, whichever one was added last is drawn on top, and there has been no way to change that. A user who wants a caption to sit in front of a picture they added later, or a bubble to tuck behind another, has had to delete and re-create elements in the right order. Requested on the community forum and tracked as BL-15992.
What the PR does
levelstored on each element. A newCanvasElementZOrdermodule moves the element in the DOM and then renumbers every level to match, background first, before asking Comical to redraw. A parent bubble and its child bubbles (which share a level) move together as one unit; a family that had become scattered in the DOM is gathered next to its parent first, so every move is exactly one step. On game pages, draggable pieces and fixed pieces only reorder among their own kind, matching the existing rule that draggables stay on top; a family with any draggable member counts as draggable. The game code that pushes draggables to the top now uses the same level-renumbering helper.disabled), five new localizable strings are added, and unit tests cover the moves, the menu, and the shortcuts.comicaljsto 0.4.2 (Stop stale Bubble objects from reacting after Comical replaces them comical-js#121). Comical used to leak the previous generation of bubble objects each time Bloom turned editing back on for a canvas; after a level renumbering a stale family bubble threw inside Comical, which showed as a "JavaScript error" toast on any Layer move on a page with a child bubble.Ref: https://issues.bloomlibrary.org/youtrack/issue/BL-15992
Devin review
This change is