* M7: Minimize collapses the navigation bar and both sidebars, the right one back while something is selected (#1835)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M7: a narrow window ignores Minimize, and a rename started while minimized waits without repaints
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M2: a child resized to the full available space of its auto layout frame becomes Fill container
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Auto layout: a child becomes Fill for the full space only across the flow or alone along it
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Auto layout: the full available space is what layout leaves (padding and an included inside stroke), judged after a new path's size
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M2: a rotated child resized to the frame's room stays Fixed (review)
CodeRabbit on #1859: a rotated layer's local size isn't the room layout
gives it, so Fill would squash its geometry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M2: a double-click on an auto layout edge sets Hug contents, with Alt Fill container (#1838)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Auto layout edges: a text child fills with Alt too, and still enters on a plain double-click
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M4: superscript and subscript are synthesised where the font has no glyphs for them (#1828)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Text: a zero OS/2 script offset counts as unset, and the native-glyph check sees the case-mapped characters
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M4: max lines on auto-width text keep it auto width, hugging that many lines
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M4: an auto-width text with max lines hugs the ellipsis on its last line, and the editing test expects auto width
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M4: Backspace or Delete at a list item's start keeps its indentation level
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Lists: the level is kept by Backspace and Delete alone, and the tests read the text's own glyph
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M2: fill container children share the free space by their content area, border-box fashion (#1824)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Layout: rustfmt's line for the frozen-share closure
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M2: one doc comment on distribute (review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M4: bulleted lists keep the same bullet at every level of indentation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* list_markers: the comment says bullets are the same at every level
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M4: typing 1) and a space starts a numbered list, as 1. does
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Parity: the Text area row names the list creation characters
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Parity: the list creation characters without spaces inside the code spans
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Shortcuts: Cmd/Ctrl+Shift+Alt+= / - / 0 make the interface larger, smaller and default-sized
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Interface size keys: live while editing text too, and the new size draws on the next frame
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* A preference set during a frame repaints this window too, so the interface size applies on the next frame
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Control channel: a preference changed by a hidden window's command repaints every window
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Shortcuts: Cmd/Ctrl+Alt+arrows rotate a degree at a time, 15 with Shift
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* The rotate gesture's label in the English catalog
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Rotate keys: about the selection's rotation origin, not while editing points, Dev Mode refusal on the control path too
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M3: Delete on a layer inside an instance hides it instead of being refused
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* The components structure test: Delete inside an instance hides
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* M4: a link on text is underlined by default, and Underline takes it off
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* text.link: only a new link takes the default underline; Underline reads the texts inside a target
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* Shortcuts: the Layers panel opens with Ctrl+1 as well as Alt+1 on Windows and Linux
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Parity note: in the browser Ctrl+1 is the browser's tab key
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* M8: .fig import: a routed connector takes its line style from the generated record (#1807)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M8: .fig import: a routed connector keeps its own empty paints and dash pattern
CodeRabbit review on #1813: an explicit empty strokePaints (no stroke) or
dashPattern (solid) on the connector no longer takes the generated record's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M3: library analytics list how each style and variable is used
A file reports how many of its layers use each of a team library's styles and
variables, and Show usage lists them by a Type choice with their layers and
files. Layers in instances count for their component. Also ignores plugins/target.
* M3: the style analytics test waits for the instance report too
A widget description can have a line, 100 long and black and 1 thick unless told
otherwise, and an SVG that comes in as locked layers, scaled to fit a size and
within the widget's 256 layers. The Counter example uses both.
Both reports were checked by running them and are already fixed on main. Pins a rounded rectangle or frame stroking only the side asked for in every alignment, and SVG font families and ids leaving out characters XML forbids.
The desktop shell swallows a plain Cmd/Ctrl+V, press and release, and sends an
image paste event; FigCraft ignored it and waited for a release that no longer
comes. The browser's paste event gives eframe only text, so the page now reads
the image from it, under the same limits.
Bound variables with an iOS or Android code syntax are named in generated SwiftUI and Compose in place of their value: paints, stroke weight, sizes, corner radius, gaps, padding, opacity and text. A variable with none for the platform keeps the value.
Choosing Image shows a checkered placeholder and Upload from computer instead of a dialog at once; an image paint shows its asset preview. A file dropped on the open picker replaces the image, keeping the fill mode, crop, position and adjustments (image.replace, one undo step; paths capped as image.place's). The browser's file picker reaches the tab too. Also fixes a race in library_detach_tests.
Gap 10: a file counts the library instances it places, creates, pastes or duplicates and reports them like its detaches. The server counts what a file's totals grow past their highest in the current week and keeps a year of weeks (actions.json). library.usage {days} and Show usage give insertions and detachments over the past 30 days, 90 days or year. New variants are appended; an older server refuses them and Show usage says so.
A request line can carry timeoutMs beside id and method, capped at 600,000 ms; without it the wait stays 60 s and older apps ignore the field. figcraft-cli mcp --attach PORT --timeout SECONDS sends it with every request and reads the answers that much longer. A timeout's message says how long the request waited.
* M11: a widget opens its plugin's panel (plugin API 5)
Gap 6: a widget callback's ui_show opens the plugin's panel and keeps the module loaded; the panel's callbacks get the widget's id and state and redraw it in the same undo step. Older plugins' ui_show from a widget still opens nothing. The Counter example sets its count from a panel.
* M11: open_panel takes its opener as one value
Gap 14: variable.extendCollection and Extend collection on a collection's row in the Variables editor. Extensions follow edits of the collection they extend at once (normalising keeps them in step whenever variables change), extensions extend again, and a loop of extensions from a hostile file comes apart into plain collections.
* M4: the eyedropper with Cmd/Ctrl+Shift makes a colour style or variable of what it picks
* M4: the Create from color window's collection picker is its own function