Commit Graph
3733 Commits
Author SHA1 Message Date
BFlat f9c8a623dd Merge pull request #2248 from TrevorBrown-dev/feat/typed-number-starts-list
M4: a typed number and full stop start a numbered list at that number, as measured in Figma
2026-11-12 09:27:46 +07:00
BFlat 37af80ed89 Merge pull request #2160 from Ragulsundaram/tamil-ui
i18n: Tamil (ta) interface catalog
2026-11-12 09:26:49 +07:00
BFlat fe5e0eb35f Merge pull request #2112 from Silvertree2010/fix/h10143-file-export-exports-the-whole-pa
Reject invalid layer ids in file.export and file.exportLayers
2026-11-12 09:25:28 +07:00
BFlat 0839958f54 Merge pull request #2142 from TrevorBrown-dev/feat/al-drag-reorder-edge
Auto layout: a dragged child passes a sibling when its leading edge reaches the sibling's middle
2026-11-12 09:23:43 +07:00
BFlat 5de88b69f8 Merge pull request #2154 from ljkx/fix/crop-from-fill-strip-2150
M1: Crop chosen in the colour picker enters crop mode (#2150)
2026-11-12 09:22:07 +07:00
BFlat f2c593ff6e Merge pull request #2117 from Silvertree2010/fix/h11295-node-reparent-silently-turns-a-n
Reject negative or fractional index in node.reparent
2026-11-12 09:20:42 +07:00
BFlat 0fd45a2eb2 Merge pull request #2107 from TrevorBrown-dev/fix/escape-deselects-measured
Selection: Escape clears the selection instead of stepping out to the parent, as in Figma
2026-11-12 09:18:27 +07:00
BFlat d3138da22f Merge pull request #2120 from Silvertree2010/fix/h11642-exportsize-parse-accepts-a-sign
Reject signs and exponents in ExportSize::parse
2026-11-12 09:17:41 +07:00
BFlat 736a1efe1a Merge pull request #2148 from TrevorBrown-dev/feat/scale-tool-focus-2146
Scale tool: K focuses the Scale field, so K, 2, Enter scales by two (#2146)
2026-11-12 09:15:53 +07:00
Dylan M. Taylor e2b6b4cd87 chore: bump to 0.18.1 for the Flatpak updater patch release (#2279) 2026-11-11 19:01:50 -05:00
Trevor BrownandClaude Opus 5.5 20f02bb7c1 M12: Boards: mind maps in the document and engine (#2226, step 1) (#2228)
* M9: Boards: mind maps in the document and engine (#2226)

Part of #2226, step 1 of 4. A mind map node is a board object of its own (BoardItem::MindNode: a frame hugging its text, no box) and a branch is a connector marked `branch`; the tree is read from the branches alone. `board.mindMap` places a first node with three children and `board.mindMapAdd` adds a child or a sibling, each one undo step. The normalize pass (`board::settle_mind_maps`, `figcraft_doc::mind_layout`) lays a touched map out again from its first node: 88 between columns, 48 between siblings, each stack centred on its parent; a branch that no longer joins two layers of its page is removed. Branches are curved, stroke 4, #757575, round caps. Numbers are from a FigJam map saved and decoded. No toolbar entry, shortcuts or import yet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 designed; Sonnet 5.5 wrote at medium

* M12: Mind maps: a map around its own container stays put; a moved branch re-flows its old map (#2226)

A map holding a layer and something inside it is skipped by the settle pass (it never settled). Every touched branch now stirs its old ends, so re-attaching a branch's start re-flows the map it left. Boards without branches return early, a map over MIND_MAX_NODES is left whole, shift skips non-finite moves, and the doc tests share one six-node helper.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 reviewed; Sonnet 5.5 wrote at medium

* M12: Mind maps: FigCraft's own starter texts (#2226)

A new map's starter children read "Idea 1", "Idea 2" and "Idea 3", as the design specified,
instead of the incumbent's wording, which the first commit had copied from the measurement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote

* M12: Docs: the mind-map revision rows go in the revision history (#2226)

The 2026-11-10 rows sat in ROADMAP.md's Headline numbers table and docs/roadmap.md's Alpha gate
table; each now opens its file's revision history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 00:47:05 +01:00
Trevor BrownandClaude Opus 5.5 0da027292e Merge upstream/main into fix/escape-deselects-measured
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 17:55:27 -05:00
Trevor BrownandClaude Opus 5.5 3a4b6f0e1f Merge upstream/main into feat/scale-tool-focus-2146
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 17:49:15 -05:00
FredAppsandFredApps e8b53e3393 Release: FigCraft v0.18.0 on main (#2275)
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-11 23:27:43 +01:00
FredApps 8f36c3f16b CI: nightly release dry run (#2274)
release.yml also runs nightly on main with craft-common-actions' dry-run: every release build
except macOS, with nothing signed, pushed or drafted. Breakage that only the release build hits
(riscv64, Flatpak, FreeBSD, packaging) then shows up the next morning instead of on release
day, as it did on 11 Nov 2026.
2026-11-11 23:04:08 +01:00
Trevor BrownandClaude Sonnet 5.5 7c3f9ce7e3 M4: the list start reset runs once per edit and leaves plain paragraphs' levels alone
insert_model cleared the copied start with one set_para_lists call per newline, each scanning the whole text, and set_para_lists also zeroed the level of plain paragraphs. Add TextData::clear_list_starts (one pass, touches only start_offset, no-op when no paragraph has a start) and call it once over the created paragraphs, only when the text has a newline.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-11 16:03:31 -05:00
Dylan M. Taylor 3b9bf8c9a2 batch: bound how much referenced data one step's params copy (#2257)
* batch: bound how much referenced data one step's params copy

* batch: check a list's size before queuing its elements
2026-11-11 15:55:11 -05:00
24cf70329b M5: Locked layers follow Figma's rules: no nudge, a locked parent's children stay locked (#1560) (#2219)
* M5: Locked layers follow Figma's rules: no nudge, a locked parent's children stay locked (#1560)

Pins Figma's locked-layer behaviour (measured in Figma's web app, 2026-11-10; help center "Lock and unlock layers") in a new lock_behaviour_tests suite. Fixes the divergences: transform.nudge and transform.nudgeSize skip locked layers, object.toggleLock without a value counts a child of a locked parent as locked (so it never locks the child on its own), and the Layers panel padlock on such a child is inert.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Fable 5.1 briefed; Sonnet 5.5 wrote at medium

* Layers panel: a padlock sweep skips the children of a locked layer (#1560)

A padlock drag sweep no longer collects rows with `locked_above`, so
dragging across a locked frame's children leaves their own flags alone
and draws no swept value on them. An eye sweep is unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium

* M5: Lock/Unlock leaves a locked layer's child alone in a mixed selection (#1560)

With a locked frame's child and an unlocked layer selected, Lock/Unlock set both own flags, so
the child stayed locked once the frame was unlocked. With no explicit `locked` value, the command
now skips a layer whose parent is locked, as its padlock does; an explicit value (scripts) still
sets it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-11 21:06:56 +01:00
Dylan M. Taylor 898bfc2e60 Fix Flatpak updates and bump to 0.17.1 (#2267)
* fix(flatpak): allow release checks and self-update helpers

* test: keep Flatpak permission parsing within strict Clippy rules

* chore: bump version to 0.17.1 for the Flatpak update fix
2026-11-11 15:01:36 -05:00
Dylan M. Taylor 554ad0ea77 pathops: budget the closed faces input, share the dash allowance, index point incidence (#2249)
* pathops: check closed inputs before faces normalises, share the dash allowance across subpaths, index point incidence once

* pathops: leave out move-only subpaths when closing, budget dashes by the fitted pattern, index only join points
2026-11-11 14:49:49 -05:00
Dylan M. Taylor 81371f4a53 render: seed and mix the node-id cache hash, skip the cell allocation past the pattern limit (#2254)
* render: seed and mix the node-id cache hash, skip the cell allocation past the pattern limit

* render: use hash_one in the bucket test
2026-11-11 14:49:35 -05:00
Dylan M. Taylor 9032dc3e67 svg export: embed each image's bytes once per file (#2250) 2026-11-11 14:49:20 -05:00
Dylan M. Taylor 64e91207f1 svg import: bound the layer stack a filter chain builds (#2252) 2026-11-11 14:49:06 -05:00
Dylan M. Taylor 6e9582c0a0 codeConnect.import: index components by name and describe each once (#2265) 2026-11-11 14:48:52 -05:00
Dylan M. Taylor 6bc8bbaef1 inspect: work out a grid's cells once per inspection (#2260) 2026-11-11 14:48:38 -05:00
Trevor BrownandClaude Sonnet 5.5 b190e675b9 M4: a list item made by Enter has no start of its own, so a split list restarts at 1, as measured
Enter copied the item's start (a typed "5. " gives 4) onto the new item, so once a middle item was unlisted the next one restarted at its copied start. Every paragraph an insertion creates now has start_offset 0; the first item keeps its start. Measured in Figma: unlisting "b" in 5. 6. 7. leaves "c" at 1., and the same for a list started with 1.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-11 14:34:56 -05:00
Oleksii SukholitaandOleksii Sukholita 74698fa89f M7: links open in the browser in the desktop app, What's new on the update prompt among them (#2216)
The desktop app built eframe without its `links` feature, so egui-winit dropped every
`ctx.open_url` with only a log warning: the update prompt's What's new link and Download
button, the About and Credits links, Terms in Live and the link in the Dev Mode panel did
nothing on click. The feature adds no crate: `webbrowser` is already a dependency of the app.
DeckCraft's desktop app builds eframe with it too.

`links_in_the_interface_open_in_the_browser` fails without the feature.

Co-authored-by: Oleksii Sukholita <oleksii.sukholita@gmail.com>
2026-11-11 20:23:45 +01:00
Dylan M. Taylor 41c1ad3458 Merge pull request #2263 from storytold/chore/craft-update-6e03f65
Updates: take craft-update from craft-libs main at 6e03f65bf
2026-11-11 12:44:22 -05:00
Dylan M. Taylor 2446e8718b Updates: take craft-update from craft-libs main at 6e03f65bf 2026-11-11 12:44:16 -05:00
Dylan M. Taylor 8415de0bad ci: run Harden-Runner on every job (#2258)
Adds step-security/harden-runner (audit, pinned to v2.22.4 like
craft-common-actions) as the first step of each job that did not have it,
so every workflow in the org's public repos reports its egress to
StepSecurity. Audit, not block: block-mode allow lists come from each
job's observed traffic.
2026-11-11 12:11:16 -05:00
Trevor BrownandClaude Opus 5.5 cf17c66a13 Merge upstream/main into feat/scale-tool-focus-2146
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 11:39:49 -05:00
Trevor BrownandClaude Opus 5.5 e829590fdf Merge upstream/main into fix/escape-deselects-measured
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 11:39:38 -05:00
Trevor BrownandClaude Sonnet 5.5 b8f05d1948 M4: a typed number and full stop start a numbered list at that number, as measured in Figma
Typing `5. ` at the start of a plain paragraph starts a numbered list whose first item reads 5 (Figma has no start-number field); the next item goes on with 6. Digits only, 1 to 9999; `0. `, `12a. ` and `2)` stay text (not measured), `1)` works as before. The measured restart rows (plain paragraph, bullet item) are no longer marked silent.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-11 09:58:57 -05:00
rumangerst 7bf098d75d fix(ui): paste uses the event's clipboard text instead of re-reading it (#2021) (#2243)
The paste handler read the system clipboard synchronously (2 s timeout) even
though the paste event already carries that text, and discarded the read's
result. On the desktop, the clipboard bridge delivers `event_text` that it read
while the window thread was free; re-reading from the paste handler blocks that
same window thread - and when the app itself owns the clipboard (a self-paste),
its own data source can only be served by that very thread, so every self-paste
froze the window for the full 2 s read timeout on Linux/Wayland.

Prefer the event's text and only fall back to the synchronous read when the
platform handed over none (chords, image-only clipboard, context-menu paste).
A regression test pins that a paste event carrying text never triggers the
synchronous read.
2026-11-11 15:37:20 +01:00
Trevor BrownandClaude Sonnet 5.5 2dd1b5a53a Menus: the main menu and its submenus stay inside the window and scroll when taller (#2217) (#2220)
Submenus of the main menu were not constrained to the window (constrain: false, so they sit
beside their row), so the Object submenu ran past the bottom edge with its lowest commands out of
reach. Menus and submenus are now held within the window's height (moved up, never above the top,
8 pt margins, still beside their row so menu-aim is unchanged), and a panel taller than that
scrolls with the wheel; the keyboard's focus scrolls into view.


Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-11 15:32:21 +01:00
Pavel Ivanov 9e815546ba M8: switching back to a tab shows its page at once (#2075)
* **No blank canvas** when switching back to a document tab or to a page in a file: the image it had when last shown is drawn from the first frame while it renders again
* Images of up to four recently shown files and pages are kept; closing a tab frees its image right away

Refs: #2074
2026-11-11 15:05:04 +01:00
Trevor BrownandClaude Sonnet 5.5 401f449729 M8: zoom previews: scan system fonts before the zoom-preview tests render (#2230)
pans_and_edits_get_no_preview_and_build_on_the_kept_image failed in full lib runs with "a pan after a previewed zoom renders strips only: Full". The render kept from the zoom is stale once the global font generation changes (retained.rs prepare: last.fonts == layout_generation()), and the once-per-process system font scan that many other tests start bumps it (fontdb.rs scan_system_fonts -> clear_layout_cache). When that scan landed between the test's zoom and its pan, the pan redrew in full instead of patching. Unrelated to the clock or the threshold. document() now runs scan_system_fonts() first (a concurrent caller waits for the scan), so the generation is settled before any render. Test-only change; the shipped staleness check is intended behaviour.

Stress, full lib binary with 16 test threads: 3 of 6 runs failed before, 0 of 25 after.


Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-11 15:02:45 +01:00
Dylan M. Taylor 0f08269067 fix(collab-net): never send the server key over plain ws:// to another machine (#1923)
* fix(collab-net): never send the server key over plain ws:// to another machine

Publishing a plugin, uploading or sharing with the server's key accepted a
ws:// address for a remote host, so the reusable administrative key went
out in clear text. The key now goes only over wss://, or over ws:// to
this machine (loopback or localhost); browsing without a key is unchanged.

* address review: connect only to loopback addresses for a plain ws://localhost endpoint
2026-11-11 08:36:29 -05:00
FredApps be991533b0 Merge pull request #2207 from storytold/sonar/format-mandated-sha1
sonar: SHA-1 image names in .fig export are the format's, not a choice
2026-11-10 18:45:47 +01:00
FredApps e92d5cbd56 Merge branch 'main' into sonar/format-mandated-sha1 2026-11-10 18:23:29 +01:00
amorSoftLabsandbflatastic 2af535c132 fix(ui): access preferences from home screen via shortcut and sidebar (#956) (#962)
* fix(ui): access preferences from home screen via shortcut and sidebar (#956)

* fix(ui): handle preferences shortcut before popup guard

* docs: add docstrings for modified functions to satisfy coverage check

---------

Co-authored-by: bflatastic <bombayapirat@gmail.com>
2026-11-10 17:58:20 +01:00
FredApps 73e3720083 sonar: SHA-1 image names in .fig export are the format's, not a choice 2026-11-10 11:22:16 +01:00
Trevor BrownandClaude Sonnet 5.5 e415a3a0fb M2: pin the leading-edge drag reorder at its boundaries, zero delta and several layers (#2142 review)
Tests for the -129 leftward boundary, the vertical boundaries both ways, a drag with no move along the flow, and several moving layers using their combined box. Doc comments say whose edge is "leading" and what the caller passes; the parity row names the unchanged cases and the web-app measurement source.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 triaged and briefed; Sonnet 5.5 verified and wrote at medium
2026-11-09 15:16:36 -05:00
Trevor BrownandClaude Sonnet 5.5 7a8d422dec M8: the Scale field only takes the keyboard when the tool is chosen or the panel returns, and Ctrl/Alt+Enter keep the tool (#2148 review)
A stale "field had the keyboard" flag no longer ends the tool on the first frame back from another tab. A selection appearing after K with nothing selected no longer moves the keyboard from the canvas to the Scale field. Ctrl+Enter and Alt+Enter are not the tool's exit. Tests pin the full text selection, the 2x and 1.5 factors, the field letting go after Enter and Escape, idle frames after Tab, and a leftover edit dropped on return.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 triaged and briefed; Sonnet 5.5 verified and wrote at medium
2026-11-09 14:47:06 -05:00
ljkx a54eafc0fc M1: test that picker Crop only sets the mode where Crop image doesn't apply (#2150)
Choosing Crop in the colour picker starts crop mode only for one layer's
own image fill. The new test chooses Crop for a stroke, for two layers'
fills at once, and for a region's fill in vector edit mode (the layer's
own fill an image too). In each case it checks that the paint takes the
Crop mode, crop mode does not start, and the picker stays open. It also
checks that crop_on_canvas gives nothing for a solid fill, an index with
no fill, the page background and a style.
2026-11-09 20:08:46 +01:00
Ragulsundaram 6108efd4d2 i18n(ta): shorten Min W to match the other size labels 2026-11-10 00:11:02 +05:30
skylar taylor-barrick a2e87433d8 Naming: Developer Mode follow-ups (#2165)
* Naming: record Developer Mode in the feature-names doc and the stage paragraph

docs/feature-names.md gains the entry for the rename: the old label, the new one, Figma's
US registration for DEV MODE (7574348) as the reason with its TSDR record, the identifiers
that keep their names, and the translations that moved from a generic "dev mode" to the
developer mode. The stage paragraph in ROADMAP.md listed the mode as Dev Mode.

* Actions palette: put each search doc comment back on its function

search_text had grown a second doc line under matches's, so the sentence about the query sat
above a function that takes none. search_text now says what it reads and matches keeps its own.
2026-11-09 15:44:02 +01:00
Ragulsundaram 50a76d0914 i18n: Tamil (ta) interface catalog (#2159)
Adds ta.toml with every UI string, command label and menu wording, marked draft.
Desktop draws Tamil with an installed face (#2018); the web picker leaves Tamil out
until craft-fonts has Noto Sans Tamil, like Georgian and Arabic, with a test.
docs/translating.md gains Tamil's entry, typography notes and a Tamil draft section.
2026-11-09 18:45:27 +05:30
Dylan M. Taylor 79c363466a fix(web): allow up to Cloudflare 25 MiB cap in package.sh (#2155) 2026-11-09 06:59:31 -05:00
ljkx 91a76c72c4 M1: the picker-Crop test drags the picture's corner outside the layer too (#2150) 2026-11-09 12:53:10 +01:00