The horizontal ruby, Zhuyin and emphasis painters and the text content
code shape glyphs through helpers that lived under text_vertical. Move
shaping.rs, font_tables.rs and orientation.rs to a new
shapes/text_shaping module, which both engines import.
The position-data direction values were split between the vertical
positions module and the Zhuyin module. They now sit next to
PositionData in shapes/text.rs, with their values unchanged.
AI-assisted-by: claude-opus-5-5
Several CJK passes had a copy per writing direction. Merge them without
changing their results:
- allocate_bounded_expansion and bounded_expansion divide justify and
distribute slack for both axes. Each axis still collects its own gaps;
the horizontal one checks no-break controls over the source range and
the vertical one at cell edges, as before.
- PolicyBoundaries holds the break and emergency rules at each grapheme
of a paragraph. The horizontal overlong-word and atomic-overflow passes
and the vertical pairwise column planner read it. relax_overlong_words
moves next to retain_atomic_overflow and shares annotation_ranges.
- TextLayoutPolicy::pair_spacing_em gives the compression and script gap
that both axes apply with their own caps.
- cjk_chars keeps the Han, kana, hangul and punctuation ranges. Ranges
that differ on purpose stay separate there, with a note on why.
- OverhangClaims tracks the ruby overhang an earlier reading takes.
- horizontal_zhuyin_glyphs places Zhuyin for position data and painting.
- paint_horizontal_annotations paints warichu, emphasis and ruby; the
emoji overlay keeps its place between the marks and the ruby.
AI-assisted-by: claude-opus-5-5
TextLayoutPolicy had nine flat variants that mixed language, Chinese
region and Korean wrap. It is now Plain, Japanese, Chinese(ChineseRegion)
or Korean(KoreanWrap), and the layout code asks it named questions
(uses_jlreq, plans_breaks, keeps_overlong_units, reopens_overlong_words,
bounded_justify, needs_joiner, normalizes_western_spaces,
uses_clreq_positions, ...) instead of comparing variants.
Paragraph parses its language once, when the language or the Korean wrap
changes, and copies the policy to its spans. Span code no longer builds a
policy from the tag with a dummy Korean wrap, and the emphasis and
underline positions take the policy instead of a Chinese flag.
A LanguageTag parser now serves both the layout policy and the CJK font
choice. It also accepts '_' as a separator, as the font choice did, so
a tag such as "ja_JP" now selects the Japanese policy.
The korean-wrap byte decodes through a new exported RawKoreanWrap enum
(Syllable=0, SpacesOnly=1, KeepWords=2) with the same byte values.
AI-assisted-by: claude-opus-5-5
The CJK layout code kept names from when it only handled Japanese.
Chinese regional presets, Pinyin, Zhuyin and Korean now share it, so
rename the modules and helpers to say what they do:
- kinsoku.rs becomes line_breaks.rs: the layout-text rewrite with
OffsetMap and the inserted break markers. The kinsoku predicates move
to jlreq.rs (was japanese.rs); JapaneseClass becomes JlreqClass.
- is_japanese_text_char becomes is_cjk_text_char.
- text_japanese.rs splits into text_attrs.rs (span attribute enums),
text_ruby.rs (ruby pieces and overhang), text_warichu.rs and
text_allocation.rs (capped_equal_allocations, shared by both axes).
- wasm/text/japanese_layout.rs becomes layout_attrs.rs.
- RubySide becomes AnnotationSide; RawTextSpan.ruby_side becomes
ruby_flags, since the byte packs the side and the Zhuyin bit.
- horizontal_aki_sheds becomes the horizontal_pair_spacing dispatcher
with a jlreq_aki_sheds branch; the plan field sheds is pair_spacing.
- The policy_* helpers become pairwise_* and the Japanese ones jlreq_*.
- The oikomi policy parameter is adjustment and minimum_oikomi_extent is
min_squeezed_extent.
Exported functions, Raw* enums and byte layouts stay unchanged.
AI-assisted-by: claude-opus-5-5
The CJK text options were behind per-language "Enable layout" toggles in
the file menu and the settings, each with its own sidebar section. A text
now has one language, picked in a single Language panel, and the options
of that language show below it.
- Rename the `vertical-text-layout` flag and feature to `cjk-support`.
- Remove the per-file and per-profile layout toggles, the file options
that stored them and the `:set-text-layout` change.
- Add the Language panel: a grouped dropdown of Japanese, Korean and the
regional Chinese variants, a row to change the language and a button to
remove it, "Mixed" when the selected texts differ. Picking a language
writes it to every paragraph of the texts.
- Render the CJK attrs only under the language that uses them, so a text
without language is horizontal and plain. The stored content keeps
every attr.
- Remember the last picked language for the next new texts.
- Add File > Language: the language of the texts without one of their
own, applied at render time and laid out again when it changes.
- Add the profile text language in Settings > Options: new files start
with it as their file language.
- Extract the grouped dropdown of the board size presets into a shared
component used by the presets and the Language panel.
- Name the Japanese readings furigana, drop the redundant prefixes of
the furigana and pinyin options, move Distribute below the writing
mode row and show only the position sides of the writing mode.
AI-assisted-by: claude-opus-5-5
Finding the line-end squeeze laid out the whole paragraph again for every
line, so the cost grew with the square of the length and typing in a
long Japanese text lagged.
Lines break greedily, so a line depends only on the text from its start.
Lay out a window from the line start that holds the line and the next
one, doubling it when needed, keep it while no squeeze changes the sheds,
and lay out the full paragraph once at the end. A test checks the sheds
match a full relayout.
AI-assisted-by: claude-opus-5-5
Readings paint above the line box, outside the glyph metrics. The text
bounds joined the emphasis marks only, so an auto-width text with ruby
or Zhuyin and no emphasis exported with the top of its reading cut off.
Measure the ink of the readings with the code that paints them and join
it to the content and auto-width bounds.
AI-assisted-by: claude-opus-5-5
The narrow-box overflow plan, which lets an indivisible unit overflow a
box narrower than one character, ran for Chinese and Korean only. In a
Japanese box of one character width Skia broke anywhere: a line started
with "、" and a ruby base split over two lines.
Run the plan for Japanese too, and refuse emergency breaks before a
character that may not start a line or after one that may not end it.
AI-assisted-by: claude-opus-5-5
The language profile and Japanese layout selects labelled mixed values
with "labels.mixed-values", a key that no longer exists, so they showed
the raw key. Use "settings.multiple", as the other text options do.
The "No language profile" choice had a blank id, which the select shows
as "--". Give it the "plain" id and map it back to no language.
AI-assisted-by: claude-opus-5-5
Edit > Undo and Redo emit the same events as the shortcuts, but the menu
takes the focus. The blurred WASM editor then ignored the restore, so the
menu did nothing while the text edition stayed open.
Focus the editor again before restoring its history.
AI-assisted-by: claude-opus-5-5
An `all` composite gave up below half width, so "2027" in a font with
proportional digits (about 0.45) stayed sideways, while `digits` combined
the same run down to 1 / length.
A Western run no longer than a `digits` composite now squeezes as far as
one. Upright CJK and longer runs keep the half-width limit, since a
deeper squeeze makes full-width glyphs illegible.
AI-assisted-by: claude-opus-5-5
When an item overflowed a column, column_break moved the characters that
may not start a column into the next one, and only checked that they fit
there with the overflowing item. The characters after it may not start a
column either, so a run longer than a column was pushed out again at
every column: "ださい。ー、ャュョッ。" in a five-character box left
"ださ", "い", "。" and "ー" alone in four columns.
Measure the whole unit that moves, up to the next allowed break, and keep
the natural break when that unit is longer than a column.
AI-assisted-by: claude-opus-5-5
Font fetches are shared per URL, so a text that asks for a face already
being fetched gets no fetch callback. process-pending only relaid out
text after its own callbacks, so such a text kept its fallback-font
layout. Auto-grow text recovered through the reflow resize, but fixed
text stayed wrong until another change.
Wait for the text's pending faces to be stored or to fail before the
relayout, whoever started their fetch.
AI-assisted-by: claude-opus-5-5
Zhuyin, Pinyin and emphasis marks over horizontal text were placed
against an em box bottom-aligned to Skia's tight glyph rect, which spans
the hhea ascent and descent. In CJK faces the descent reaches past the
em box, so Zhuyin columns sat about 0.17 em below their base, and over
annotations relied on a hand-tuned clearance.
Place them against the ideographic em box (OS/2 typo metrics) of the
font that shaped each base, centred on the line baseline, the same
metrics vertical text uses for upright glyphs.
AI-assisted-by: claude-opus-5-5
Skia keys a line's style runs by UTF-8 byte offset, while line indices
are UTF-16. Decoration segments searched those runs with UTF-16 offsets,
so with CJK text every underline or strike on a line took the paint of
the first run, and a decorated span wrapped onto a new line lost its bar.
Look up each segment's run by the span's UTF-8 style anchor, falling
back to the line's first run for a span continued from an earlier line.
AI-assisted-by: claude-opus-5-5
Each ruby reading attached its lowest ink to the base, which suits kana
but not Latin letters: the descender of "y" lifted "yǒu" above "liáo"
over 友聊, and under ruby moved with ascenders and tone marks.
Western letters in a reading now take the font's descent (over) or cap
height (under) instead of their ink, so Pinyin and romaji readings share
one baseline and descenders stay clear of the base. Upright glyphs keep
the ink edge.
AI-assisted-by: claude-opus-5-5
The fifth alignment button made the first row of the text options 36px
wider than the sidebar grid: the options button fell outside it and the
panel scrolled sideways.
Distributed alignment is an East Asian convention (均等割り付け, 分散对齐,
배분 정렬), so it moves out of the alignment group into a switch of the
Japanese, Chinese and Korean layout sections, shown when the text's
language matches. Turning it off aligns the text to the start. The label
shortens to fit beside the switch.
AI-assisted-by: claude-opus-5-5
SkParagraph moves each line right by half the letter-spacing of its first
character. That centres span tracking, but the spacing added to single
characters (distribution and justification gaps, squeezing, compression
and ruby room) must only open the gap after them. A distributed label of
two characters started half a gap in and overflowed the box by as much:
"国家" in a 200px box drew 国 92px from the left edge.
Builders of horizontal text record how far each adjusted character's
letter-spacing departs from its span tracking, and `LayoutParagraph` takes
back half of that on each line, next to its baseline shifts: painting,
glyph and placeholder rects, line metrics, hit testing and text paths.
Span tracking keeps its half spacing before the line.
AI-assisted-by: claude-opus-5-5
The paragraph language selects the CJK typesetting rules (line breaking,
punctuation spacing, the default emphasis position and localized glyphs),
but plugins could not read or set it. `lang` holds it as a BCP 47 tag, as
the HTML `lang` attribute does; `null` or `''` removes it.
On a text shape it applies to every paragraph and reports 'mixed' when
they differ. On a text range it applies to the whole paragraphs the range
touches: `update-text-range-attrs` now writes paragraph attrs such as the
language there instead of copying them into spans. The tag pattern moves
to `schema:text-language`, shared by the content schema and the plugin
validator.
AI-assisted-by: claude-opus-5-5
Four fixes to how `digits` tate-chu-yoko composites lay out in vertical
text:
- A lone digit combines too, as CSS `digits <n>` combines runs of n or
fewer, so it stands upright instead of turning sideways. The renderer
(`split_digit_runs`) and the export path (`digit-combine-segments`)
share the rule.
- Composites centre on the OS/2 typographic metrics, like upright glyphs.
The hhea ascent of CJK faces exceeds the em, which set digits about
0.07em below the kanji beside them.
- Letter-spacing stays outside the composite, as in CSS. Counting the
trailing spacing in its width moved the digits left by half of it.
- The regional Chinese profiles no longer add the Han/Western gap around
a composite: it sets in one ideograph's cell, as JLREQ already does.
AI-assisted-by: claude-opus-5-5
Styling a range splits spans at its ends, and nothing joined them back, so
a text kept invisible boundaries between spans with equal styles. Two CJK
features depend on those boundaries: tate-chu-yoko `all` combines per
span, so "2" + "027" rendered as two upright blocks, and a ruby reading or
warichu note over a range that crossed a hidden boundary was rejected.
`merge-equal-spans` joins neighbouring spans of a paragraph whose styles
match, counting a missing attr as its default value. Spans with a reading
or a warichu note are never joined: each one is its own group. Both places
that split spans use it: `update-text-range-attrs` (plugin API) and
`apply-attrs-to-paragraph` (WASM editor styling).
AI-assisted-by: claude-opus-5-5
Add distributed alignment to text styles, sidebar controls, CSS export,
and the Plugin API. Spread characters across horizontal and vertical
lines, including the final line, while preserving graphemes and annotations.
Keep fractional line heights consistent across painting, hit testing,
selection, and text paths to prevent baseline drift between lines.
Add tests for distribution, nonbreaking text, and fractional line geometry.
AI-assisted-by: gpt-6
Restore the pre-composition content and UTF-16 selection when an IME ends
with an empty replacement. Keep styles, selection direction and redo intact
without recording cancellation as an edit. Share snapshot restoration with
editor undo and redo.
Add a regression for styled selections and cancellation after undo. Verify
commit, cancellation, deletion and history in four saved showcase examples,
including emoji and decomposed Korean Jamo in both writing directions.
AI-assisted-by: GPT-6
Exercise the Hangul-to-Hanja composition sequence through the public editor
bindings. Keep previews out of saved content and history, then restore the
styled source selection with one undo and the converted content with redo.
Cover both writing directions and Korean wrapping modes.
Verify native Fcitx Hangul conversion in all four showcase examples and
confirm the saved examples survive reopening.
AI-assisted-by: GPT-6
Keep bounded content and selection history within each editing session.
Group committed compositions and styled insertions, omit IME previews,
and reset history when external content changes the editing baseline.
Route keyboard, workspace menu and browser history input to the editor.
Restore UTF-16 selections through a new WASM binding, preserving styles,
readings and paragraph settings without reaching earlier canvas edits.
Verify 1,587 frontend tests, 671 renderer tests and both WASM builds.
Add four editable showcase examples and verify them after reopening.
AI-assisted-by: GPT-6
Remember when a key-down belongs to native composition. Consume its
Escape release after composition ends, preserving the active text editor.
Keep ordinary Escape behavior for leaving editing and closing menus.
Add regression coverage for native key ordering and composition markers.
Verify 1,583 frontend tests, lint and changed-file formatting. Check native
Pinyin, Zhuyin and Korean input with eight editable showcase examples.
AI-assisted-by: GPT-6
Recover merged annotation styles on the base character's own line, using
separate UTF-16 line anchors and UTF-8 style keys. Include emphasis marks
in horizontal text bounds so standalone exports keep each mark whole.
Add regression coverage for adjacent readings, wrapped text, emoji line
anchors, raster output and export bounds across all text grow modes.
Verify 670 renderer tests, formatting and both WASM builds. Add four
editable showcase examples and check their layout and exports.
AI-assisted-by: GPT-6
Retain legal line starts at the original wrap width before allowing an
indivisible punctuation or annotation unit to overflow together. Share the
layout plan and alignment offset across painting, editing and exports.
Cover mixed styles, nonbreaking controls, graphemes, annotations, alignment,
strokes and resize. All 666 renderer tests and both WASM builds pass.
AI-assisted-by: GPT-6
Add typed one-character Zhuyin readings with upright right-side symbols
and separate neutral and non-neutral tones in both writing modes.
Persist the mode through the editor, WASM bridge and Plugin API. Preserve
annotation clearance and canvas, PNG, PDF and SVG geometry.
Validate syntax and selection boundaries, and cover schema, bridge,
rendering, UI and API behavior. Native IME and reader review remain open.
AI-assisted-by: gpt-6
Carry optional span positions through the schema, WASM header, editor,
Plugin API and CSS output. Expose Chinese controls with language defaults
and independent overrides for horizontal and vertical text.
Reserve automatic clearance per side and stack underlines, ruby and
emphasis. Preserve reading groups during decoration edits and retain
canonical position values in DOM editor style data.
Add protocol, geometry, editing and API tests, including the prior Japanese
mixed-font gutter behavior. Verify both WASM targets and live exports.
AI-assisted-by: GPT-6
Support typed character and group readings through the shared ruby model.
Expose Chinese labels, presentation controls and selection guards without
changing Japanese controls or generating pronunciation.
Preserve complete source ranges for glyphs sharing a combining cluster.
Add pinned horizontal and vertical tone-mark fixtures and editor tests.
AI-assisted-by: GPT-6
Cover Chinese regional profiles and Korean wrap modes across fitting
widths, style boundaries, punctuation, numeric units and decomposed Jamo.
Check stable offsets and finite geometry in narrower horizontal boxes,
and keep indivisible punctuation units together in short vertical boxes.
AI-assisted-by: GPT-6
Add named Chinese punctuation presets and a Korean keep-words mode for
horizontal and vertical layout. Preserve the saved spaces-only mode and
keep source offsets stable through safe emergency wrapping.
Apply bounded CJK spacing and justification, expose the new choices in the
sidebar, and document preset bounds and remaining release checks.
Verify renderer, frontend, common and exporter tests, both WASM builds,
and sample save/reload plus PNG, PDF and SVG exports. Existing CI failures
remain documented in the layout notes.
AI-assisted-by: GPT-6
Add independent Japanese, Chinese and Korean file switches and all-files
preferences under the shared vertical-text-layout feature flag. Keep
control availability separate from saved paragraph profiles and rendering.
Expose explicit language profiles in separate sidebar sections. Preserve
mixed values, report the active paragraph profile at the caret, and keep
shared writing-mode controls consistent without radio group collisions.
Validation: common JVM/JS and frontend suites, backend profile tests,
exporter tests and lint pass. Existing runner formatting and Spanish
translation QA issues remain unchanged.
AI-assisted-by: GPT-6
Choose paragraph layout rules from an optional language tag. Pass language
to horizontal and vertical shaping, add basic Chinese punctuation rules,
and add experimental Korean spaces-only wrapping.
Keep text boundaries grapheme-safe and preserve paragraph profiles across
editor splits and merges. Add reproducible font fixtures for localized
glyphs and regression tests for the shared WASM protocol and layout paths.
Validation: renderer, common JVM/JS, frontend and exporter tests pass.
Both WASM targets build. Full CI still reports baseline lint and format
errors and one backend multipart-upload test failure.
AI-assisted-by: GPT-6
Expose Japanese layout properties on Text and TextRange with validated
values and whole-shape writing mode behavior. Keep ruby readings tied
to their spans when applying styles through ranges.
Update public TypeScript declarations, the API changelog and runtime
and plugin test coverage, including active-page checks.
Enable Japanese layout per file through undoable changes, or for all
files through a saved profile preference. Show the controls when the
WASM renderer and either setting are active.
Add writing mode, orientation, ruby, emphasis, warichu and line fitting
controls with icons and English and Japanese translations. Cover the
file change, profile preference and control behavior.
Apply Japanese attributes to text selections and whole shapes without
splitting ruby or warichu spans. Respect vertical writing when resizing
text and placing selection handles and pointer cursors.
Anchor native IME input to the WASM caret, keep composition previews
out of the store until commit, and add an optional geometry overlay.
Cover editor styles, serialization, fallback fonts and cursor behavior.
Render Japanese annotations in HTML and SVG and expose their styles
in CSS code generation. Preserve vertical position data from WASM,
while keeping the legacy SVG renderer on its horizontal layout path.
Cover generated markup, styles and copied SVG output.
Lay out horizontal and vertical Japanese text with kinsoku, ruby,
emphasis, warichu, tate-chu-yoko and proportional font features.
Carry the layout through glyph paths, SVG export and text selection.
Update the Rust and ClojureScript binary formats together, including
the editor bridge and headless exporter. Resolve CJK fallback fonts
and add renderer tests and font fixtures.
Add schemas, defaults and helpers for vertical writing, ruby, emphasis
and warichu. Keep readings and notes tied to their own characters when
copying styles, and preserve base text when pasting HTML ruby.
Cover the model, property copying, clipboard and library file builder.
* ✨ Render email templates inside the mail job
The web process rendered each email to full subject and HTML body
before submitting it, so every queued job carried a huge params
payload. The queue now stores only the template id plus the raw
template data, and the new :send-templated-mail job renders and
sends the email inside the worker.
The old :sendmail job stays in place to drain jobs submitted in the
previous format; the quota notice and the REPL test mail keep using
it. All templated callers (auth, profile, feedback, invitations,
comments, Nitrate) submit recipes through eml/send-template.
Closes#12445
AI-assisted-by: muse-spark-1.3-contributor
* ♻️ Unify templated mail on template id strings
The ::eml/template value was a namespaced keyword whose name had to
match the registry key, with one live mismatch (user-feedback vs
feedback). Callers now pass the registry id string itself, so keys
stay ::eml/-namespaced and values stay plain data, and the single
templates set rejects unsendable mail both at submit and in the
worker.
Closes#12445
AI-assisted-by: muse-spark-1.3-contributor
* 🐛 Encode templated mail data with the template schema
The job params column is plain JSON, so the URIs of an organization
(:logo, :avatar-bg-url) were stored as record maps and the template
check rejected them in the worker. Invites for organization teams,
organization invites and renewal notices failed without a retry.
Each registry entry now carries the JSON encoder and decoder of its
template schema: send-template encodes the data before submit and the
worker decodes it before rendering. The job schema keeps only the mail
envelope, as the template schemas own the typed data.
Closes#12445
AI-assisted-by: claude-opus-5-5
---------
* ♻️ Move the dashboard header styles to the DS
The page header of the dashboard and settings pages took its styles from
common/refactor/common-dashboard.scss. Move the rules still in use to
dashboard/common/header.scss, written with DS tokens:
- The page titles become heading* (title-large) with a class instead of
a bare h1; the team section links get a class, and the active class
moves from the li to the link.
- Drop the rules that matched nothing: .element-name, .context-menu,
.icon and .btn-secondary inside the header, and the global .btn-primary
and .btn-secondary (only the fonts page uses them; it keeps the old
import until its open change lands).
- The sidebar and subscription styles imported the file without using
it; drop the import.
The header looks the same (0 px in the new visual test). The title line
height goes from 1.15 to 1.4, which does not move the text.
AI-assisted-by: claude-opus-5-5
* ♻️ Move the dashboard libraries and search styles to the DS
Replace the deprecated spacing, size and border variables with DS
tokens and logical properties, and drop the refactor/ import.
- The search placeholder icon gets a class for its color instead of a
.icon svg rule; its xl size already gives the 32px box.
- Delete the selectors no markup uses: .dashboard-projects in both
files and .dashboard-shared in search.
No visual change (0 px in the new libraries and search visual test).
AI-assisted-by: claude-opus-5-5
* 🔥 Move the fonts page header to the DS and delete common-dashboard
The fonts page was the last user of common/refactor/common-dashboard.scss:
its header now uses the shared DS header styles and a DS heading, like
the other dashboard pages. Nothing else imports common-dashboard, so it
is deleted.
No visual change.
AI-assisted-by: claude-opus-5-5
* 📎 Remove a double blank line in the dashboard sidebar styles
Prettier rejects the two blank lines left after the imports, which made
the frontend lint fail in CI.
AI-assisted-by: claude-opus-5-5
* 📎 Remove a blank line between the subscription style imports
Stylelint (at-rule-empty-line-before) rejects the blank line left between
the @use rules after the common-dashboard import was dropped.
AI-assisted-by: claude-opus-5-5
* ♻️ Use DS icon buttons in the path editing bar
The path editing bar now uses DS icon buttons (ghost, tooltip below) and
DS icons, like the top toolbar. The toggles (draw/move mode, handler
types, snap) use aria-pressed, and the handler type trigger uses the DS
flyout indicator, with no tooltip because its menu opens on hover.
This also shows the handler and snap icons again: since #12659 their
SVGs draw with currentColor, and the legacy %button-icon set color to
transparent, so they were invisible.
Add a visual test of the bar, its hover and the handler menu.
AI-assisted-by: claude-opus-5-5
* ♻️ Move the path editing bar styles to the DS
Drop the deprecated styles import, resolve --panel-border-color to
--color-background-quaternary and use logical properties, except top and
height of the bar, which its transition names.
Delete the selectors the DS buttons left unused: .handler-trigger and
.flyout-indicator (the DS icon button draws its own indicator).
No visual change.
AI-assisted-by: claude-opus-5-5
* 📎 Add the blank line stylelint expects in the path bar styles
Stylelint (scss/double-slash-comment-empty-line-before) rejects the
comment right after a declaration, which made the frontend lint fail in
CI.
AI-assisted-by: claude-opus-5-5
* ⚡ Keep only the shape data the worker reads
The worker kept a full copy of the current page for its selection and
snap indexes. It now keeps only the attributes the indexes and the
change replay read, and re-indexes only the shapes that changed.
On a 52k-shape page the worker heap goes from 698 MB to 286 MB.
Closes#12740
AI-assisted-by: claude-opus-5-5
* ♻️ Share the worker re-trim with its replay test
The worker and its replay test now share `retrim-objects`.
AI-assisted-by: claude-opus-5-5
Migrate the remaining legacy components in the inspect module to the
modern rumext syntax: typography-block, text-block, svg-attr, svg-block,
selection-rect, selection-feedback, layer-item and left-sidebar.
Rename the ?-suffixed props of layer-item (component-child? to
is-component-child, hide-toggle? to hide-toggle) and drop the unused
sortable? and filtered? props passed from left-sidebar.
Relates to #9260
AI-assisted-by: claude-opus-5-5
Signed-off-by: Nimesh Kulkarni <167794819+GitNimay@users.noreply.github.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>