Flip horizontally and flip vertically, for whatever element is selected.
On the base element rather than on images, so a shape, a path, a text frame and a picture all get it from one place — the same reason the canvas put the pair on PageElement and applied it in the one transform every draw and hit test already goes through (TYP-716).
Two independent toggles, not a radio pair: an element can be mirrored in both axes, which is a different thing from either alone and the same thing as half a turn.
⚠️ set_undo() and set_redo() must bracket the change. set_undo() alone leaves the step open, and the next edit overwrites its before-state — the flip becomes un-undoable and takes whatever followed it down with it (TYP-653).
Hyphenation: the button is the on/off switch, and turning it ON opens the params below.
It used to be a plain palette whose popup carried an on/off switch as its first row, so turning hyphenation on took two clicks and the button's own state said nothing. Same shape as spell-check (a direct toggle) and as underline/strikethrough (turning it on reveals its parameters) — the popup now holds only the parameters.
One list toggle — bulleted or numbered — for the paragraph the caret is in.
The icon SWAPS between its off and active variants rather than being painted over with a background, which is the idiom the four artworks in control_defaults were drawn for: the active pair carry their own plate behind the frame. The stroke-alignment row paints its own selection instead, and copying that here would put a highlight behind an icon that already has one.
Two independent toggles rather than a radio row, so clicking the active one turns the list off. They are still mutually exclusive in effect — setListType writes one value — and each repaints both, since turning bullets on has to turn numbers off on screen as well.
Greyed inside a table cell: v1 does not draw markers there, so an enabled button would write a setting that never shows.
Icon-only palette trigger with an off/on push-button icon: shows icon_off normally and
icon_on while its popup (opened below the button) is open. Pass one icon to keep a
single visual. TYP-422 toolbar UX.
Optionalicon_on: stringSuper/subscript control: a two-cell push-button (superscript | subscript). The whole icon swaps to reflect the active position (off / superscript-on / subscript-on). Clicking a cell toggles that position on the selection (click again clears to 'normal'); turning a position on opens the size % / position % params popup below (TYP-422 toolbar UX).
The letter case in force where the caret is, or across a selection.
Not read off the resolved font the way underline and strikethrough are: capitalization is deliberately not a font property — the font object the resolver returns is what gets serialized as the element's default_font — so the editor exposes it separately, through the caps_resolver that layout itself uses. Asking the same resolver keeps the button and the page answering the same question (TYP-663).
The colour to paint in the decoration's swatch well.
resolved_hex is the decoration's colour as story_style_to_font worked it out — run
override, then character style, then PARAGRAPH STYLE, then the text fill — already a hex.
It comes first because this used to read the run's own override ALONE, so a colour stated
by a paragraph style was invisible: H3 in the Project Proposal brochure states
underline_color: Color/Paper, the canvas drew the bar white all along, and the well
showed the text colour instead (TYP-705).
The swatch-uuid path below is kept for the case where the resolved font carries no colour
of its own, and fill_hex remains the last word.
Optionalresolved_hex: stringResolves the font used to seed the decoration controls. get_font_at_cursor() reads at cursorLocation, which during a drag-selection sits on the anchor boundary; get_char_run_at_offset() resolves a boundary offset to the PRECEDING run, so a left-to-right drag that starts exactly on a decorated run's left edge reads the undecorated run before it (underline/strikethrough appear off). When a selection exists, read from the first character run that actually overlaps it — mirroring get_selection_point_size — so the state is correct regardless of drag direction or start position. Falls back to the cursor font when there is no selection.
Wraps one palette control in a data-pb-component row inside the current
popup panel, runs fill with this._group pointed at the row so existing
add* methods append into it.
Two or more palette controls on ONE line. _palette_row stacks its rows, so a control
that belongs beside its neighbour rather than under it needs a row to share. The nested
rows keep their own data-pb-component, so EditorUI can still hide either control on its
own; their padding is dropped afterwards, since it would otherwise widen the gap that
gap is there to set.
The stroke the flyout is describing: the SELECTED TEXT's while the editor has focus, and the frame's own otherwise.
Every stroke setter in textcommands.ts is selection-first, frame-second — a selection writes the runs it covers, a bare caret writes the frame's default. The controls have to be read the same way round or they describe something the buttons will not change: a 4 pt run in a frame whose default is 0 showed 0 pt, and setting it to 2 pt left the popup saying 0 pt for ever after, because the frame's default never moved.
Returns null outside text mode, or when there is no editor to ask. A property that DIFFERS across the selection comes back as null from canvas, and each caller shows that as blank rather than as one of the values (TYP-645).
Adds an icon-only toolbar trigger that opens a ToolbarPopup palette.
The trigger lives in its own toolbar group (key toolbar.<component>), so
the whole palette is hide/disable-able via the normal _apply_toolbar path.
build populates the flyout panel; it runs with this._group pointed at the
panel so the existing add methods and _palette_row append into it. Inner rows
use data-pb-component so EditorUI keys resolve as toolbar.<component>.<row>.
Left, right and first-line indent for the paragraph the caret is in, in millimetres.
Reads the RESOLVED values, so a paragraph that inherits an indent from its style shows what the text actually does rather than an empty field. Each input writes only its own key, so changing one does not clear the other two.
First line is offered as InDesign offers it — an offset from the left indent, negative for a hang. It is not clamped to zero here: a hanging indent IS the negative case, and it is the whole reason this control exists.
Params popup for super/subscript: size % and position % for the selection's active position. Writes superscript_size/position or subscript_size/position accordingly; greyed out when the selection is 'normal' or mixed.
The join the control should show, on the same selection-first rule as the alignment row.
setLineJoin() writes three different places depending on where the caret is — the runs a selection covers, else the frame's text_stroke_join, else the border's line_join — while this control read the BORDER's join in every case, which is the one of the three a focused editor never writes.
Unlike the width and the dash, a mixed selection cannot show blank: the control draws a corner rather than printing a word, and has no empty state. It falls back to the frame's own text join, which is what an un-joined run is drawn with anyway.
When toolbar.font_face.default_font is hidden and font_name equals the default font, returns the first non-default active font family name instead (or '' if none). Pass null (mixed selection) to get '' directly.
Optionalcursor_font_size: numberRe-resolve the displayed font-face and font-style titles immediately. Called by EditorUI.apply() so that hiding/showing default_font takes effect without requiring a full toolbar rebuild.
All caps: a plain on/off toggle, the same idiom as underline beside it — the icon swaps between its off and active artwork rather than being painted over.
No params popup, because there is nothing to configure. Underline has a weight, an offset and a colour; a case transform has none of those, so a button that opened an empty panel would be worse than one that just toggles.
Small caps is not offered. The schema carries the value and a conversion records it, but nothing renders it yet, and a control that writes a setting the page ignores is a promise the product does not keep (TYP-663).