Commit Graph
196 Commits
Author SHA1 Message Date
Ivan Shishkanov 98e47487f4 M3: merge current main into PR #575
Preserve feature and upstream progress/catalog updates. Use native Command modifiers in macOS paste tests; Command+Control is an unbound chord.
2026-10-17 14:41:08 +03:00
bflatastic 99d097636e Merge fix/all-f5 into batch 12 2026-10-17 16:59:57 +07:00
bflatastic b96e007a2c Merge fix/675 2026-10-17 16:37:32 +07:00
bflatastic a2e9b5ade2 Merge fix/673 2026-10-17 16:37:28 +07:00
bflatastic 6f8c2a657e Merge fix/680 2026-10-17 16:37:27 +07:00
bflatastic e2d9e7b493 Merge fix/625 2026-10-17 16:37:25 +07:00
bflatastic 313386c1ac Merge main into batch 11
# Conflicts:
#	apps/figcraft/src/services.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/menus.rs
2026-10-17 16:15:12 +07:00
bflatastic 7bf814f6b4 Merge main into #675 2026-10-17 16:03:45 +07:00
bflatastic b3a2891c2e Merge main into #673 2026-10-17 15:58:31 +07:00
bflatastic 5ea5590673 #680: move the page clipboard test to its own module, check the error id 2026-10-17 15:58:24 +07:00
bflatastic 7de7dbc991 Merge main into #625 2026-10-17 15:53:28 +07:00
bflatastic cd8a88733f Merge main into #655 2026-10-17 15:48:00 +07:00
bflatastic 546c09b3ba Merge fix/all-f2 into batch 10 2026-10-17 15:26:45 +07:00
bflatastic 2fe28bf0a0 Merge fix/707 2026-10-17 15:20:40 +07:00
bflatastic 62308e247e Merge fix/666 2026-10-17 15:20:30 +07:00
bflatastic 946004f0d6 Merge main into #707 2026-10-17 15:08:01 +07:00
bflatastic 6020d94d55 Merge fix/647 2026-10-17 14:41:03 +07:00
bflatastic 9f01b21a54 Merge fix/619 2026-10-17 14:40:49 +07:00
bflatastic b5cba7c885 Merge fix/711 2026-10-17 14:35:20 +07:00
bflatastic 4c1f2b978b Merge fix/697 2026-10-17 14:35:17 +07:00
bflatastic 3353d2d5d3 #647: edit.pasteDesignLayers, named neutrally; design data capped at 256 MB before decoding, data accepts wrapped or unpadded base64 2026-10-17 14:34:57 +07:00
bflatastic 9b4e45aa0b #711: move the vector.offset tests into their own module 2026-10-17 13:40:55 +07:00
Ahmed5Emad dc97118c6f Actions palette rework: Figma-shaped panel over the toolbar
Tabs (All, Assets, Plugins & widgets), Recents kept in the preferences
(newest first, capped at 5), commands grouped by top-level menu, this
file's components (placed at the view centre) and styles (applied to
the selection), installed plugins and widgets with letter tiles. Rows
carry right-side shortcut/kind hints; Enter runs the first visible row.

The panel floats 8 px above the toolbar pill with its exact width and
centre (toolbar::main_width, canvas-centred), at a fixed size so tab
switches never resize it. Tabs keep their frames when idle so the
active pill never moves its neighbours.

Engine: Prefs.recent_actions (persisted, skipped when empty). UI:
invoke/menu/plugin picks record recents; gone entries drop out.
Locales: new keys in en + es, retired the old search hint everywhere.
Docs: ui-parity row describes the new surface (palette_tests).
2026-10-16 22:58:36 +03:00
NetterSilverandClaude Haiku 5.5 9aeb9fb752 Cap stroke width in the outliner so huge weights don't panic
Found while testing crates/engine/src/cmd/props.rs:361 (strokeWeight is only clamped with .max(0.0)); the panic is raised when the renderer draws the stroke (render crate / tiny-skia stroker)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 19:58:00 +02:00
phonedu 9daf39e24c M1: a param that names a layer says so when it isn't one
`node.create` read its `parent` as `id(p, "parent").unwrap_or(page)`, so a `parent` that isn't a
layer id — a `{"$step": n}` nothing had resolved, a name, a negative number — quietly meant "no
parent" and the layer landed on the page, with the call reporting success. The same shape sat on
`image.place` and `instance.create`, on `index` (a string index appended where it was asked to
insert), and on the `ids` of every command that targets layers (an entry that wasn't an id was
dropped and the rest ran). A number that names nothing was reported; anything that isn't a number at
all was not.

`params::opt_id` and `params::opt_index` now say what the commands mean: missing and `null` are
"none", and anything else has to be a layer id (or a whole, non-negative number) and is named when it
isn't. `req_targets` refuses an `ids` entry that isn't an id, before falling back to the selection. A
number that names no layer still reports `no such node`, and a boolean is still a number to `f64_of`,
as it is for `x`, `width` and the rest.

This turns a silently wrong result into an error on purpose, so a caller that passed something that
isn't an id and relied on the fallback now hears about it.
2026-10-16 19:53:43 +08:00
Ahmed5Emad 1aa499c84f Merge remote-tracking branch 'origin/main' into feat/font-hover-preview
# Conflicts:
#	crates/ui-egui/src/style_picker.rs
#	crates/ui-egui/src/typography.rs
2026-10-16 14:34:02 +03:00
phonedu 0f4c79b629 M0.9: a script runs as one undo step and resolves $step, like command.batch
`figcraft-cli run` ran each step of a script on its own, so a script's `{"$step": n}` reached
`parent` unresolved and the layer landed on the page while every step reported success — the same
commands through `command.batch` (the MCP `batch` tool, the control channel, plugins) put it inside
the frame. One `edit.undo` took back one step of a script rather than the script, and a failing step
left the earlier ones applied.

`Session::batch_step` is now the one path both take — one step of a batch, its `$step` references
resolved against the results before it — and `run_script` wraps its steps in `Session::grouped`: the
whole script is one undo step, and a step that fails takes the script back. The result lines come out
once the script is through, so none of them reports work a later failure took back; a failure prints
one line with `rolledBack: true` and exits 1. `docs/cli.md` documents the reference and the output.
2026-10-16 19:33:59 +08:00
Ahmed5Emad 2cac36a4e2 Live font preview on hover in font picker (#653)
Hovering a family in the Typography font dropdown previews it on the
canvas via text.preview; closing without picking restores the original,
clicking applies it as one undo step.
2026-10-16 12:31:50 +03:00
NetterSilverandClaude Haiku 5.5 a911ab9614 Reject negative or fractional index in fill.set and stroke.set
Found while testing crates/engine/src/cmd/edit.rs:1180

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 08:29:55 +00:00
JimKnoxxandClaude Opus 5.5 ab10e37d43 M1: paste layers copied in Figma
Figma puts copied layers in the clipboard's HTML as a base64 .fig canvas
between (figma) markers. edit.pasteFromFigma reads it with the .fig import,
turns the layers into the session clipboard and pastes them as edit.paste
does (selected frame, in place or view centre), with the import's warnings.
The desktop app reads the clipboard's HTML (arboard) and Paste prefers a
Figma copy; the browser's paste event carries plain text only.

Tested on copies written by our own .fig export; not yet on real copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:20:49 +02:00
Ivan Shishkanov 1ac0e475c1 M3: adapt Selection colors to current main 2026-10-16 07:58:58 +03:00
NetterSilverandClaude Haiku 5.5 8538dd740f Refuse edits that leave a layer with non-finite geometry
Found while testing crates/engine/src/cmd/arrange.rs:132

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 03:38:36 +02:00
Skyfuller1303 4b29d8c34d M1: apply instance overrides by key and order, settle bound paints, keep stroke outline styles
Override rows of an instance can name a layer of its main by the key the layer
had before the main was edited. The key now resolves to the layer's current id
when it is unambiguous and the current id does not exist already. Rows of an
enclosing instance win over those of the instances nested in it, whatever order
the wire lists them in, and an explicit "no style" on an override detaches the
style instead of falling back to the older field.

Paints bound to variables take the colours of the active modes when a document
loads, before the first edit, without touching other pending changes.

A stroke-only vector that imports as the outline of its stroke now moves the
stroke's shared style and colour variables to the fill it becomes, and vectors
whose single segments carry their own stroke style say so in a warning.
2026-10-16 03:32:38 +02:00
Skyfuller1303 d4394e87cc M1: save a copy as .fig
Save as now offers .figcraft and .fig as separate file types. A .fig
destination, chosen in the dialog or passed to file.saveAs and file.save,
writes the existing experimental .fig export of the document that is shown
and reports how much was left out. The file's own path, unsaved changes,
versions, branches and undo history are not touched, and a shown earlier
version stays shown while the copy is written or a Save as choice is
pending.

Plain Save no longer writes over a file whose saved path ends in .fig;
earlier builds could write native data under that name. It asks for a
destination instead.
2026-10-16 02:03:46 +02:00
Skyfuller1303 0404448f74 M1: keep imported file bytes out of the command journal
Pasting or dropping a file runs file.import with the whole file as Base64
data, and every successful command was journaled with its parameters, so
each imported file stayed in memory a second time for the session. Byte
imports, including ones wrapped in command.batch, are no longer journaled.
Imports by path and all other commands are unchanged.
2026-10-16 01:34:29 +02:00
Ivan Shishkanov 692d52c514 M3: merge current main and resolve PR #575 conflicts
Preserve the upstream behaviour and regression tests alongside this feature. Align the control-server connection-limit test with main closing invalid JSON connections: assert EOF instead of shutting down an already closed socket on macOS.
2026-10-15 23:08:41 +03:00
bflatastic 891f0acb3c Merge branch 'rb-560' into batch/t6 2026-10-16 02:36:56 +07:00
bflatastic d60a27b675 Merge main into #554: one id map for the copy, and #562's flows, prototype and guides follow it
page.duplicate copies every layer with duplicate_all_into (navigation between
copied frames points at the copies) and builds the old-to-new list for flows
from that copy, instead of copying each layer separately.
2026-10-16 02:34:54 +07:00
bflatastic db8bf6ba33 Merge main into #560; normalise the replacement where findReplace reads it
Main's case-insensitive replace loop (from an earlier PR) took the place of the
loop this change edited, so the replacement text is normalised once, where
the parameter is read.
2026-10-16 02:31:34 +07:00
bflatastic 887e374c58 Merge branch 'pr-545' into batch/t5 2026-10-16 01:36:00 +07:00
bflatastic 34dcf852d5 Merge branch 'pr-542' into batch/t5 2026-10-16 01:35:59 +07:00
bflatastic 16e26b69ff Merge branch 'pr-516' into batch/t5 2026-10-16 01:35:44 +07:00
Ivan Shishkanov 7a5885cde9 M3: add Selection colors for mixed selections (#403) 2026-10-15 19:05:24 +03:00
MarekSpodBiedry 843b00b22f text: scripted text stores CRLF, CR, U+2028 and U+2029 as LF like the editor (#427) 2026-10-15 17:20:58 +02:00
NetterSilverandClaude Haiku 5.5 a4f4869443 Point duplicated page navigation at the copied frames
Fixes #419

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 17:10:00 +02:00
NetterSilverandClaude Haiku 5.5 330b237c9c Refresh linked layers when a library update changes only a style
Fixes #461

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 14:45:47 +00:00
NetterSilverandClaude Haiku 5.5 7689af50d6 Keep character-range text styles when publishing and placing components
Fixes #463

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:31:53 +02:00
bflatastic 9ba207e900 Merge #400: Let batch steps reference ids created by earlier steps (@edivanteixeira) 2026-10-15 19:54:08 +07:00
NetterSilverandClaude Haiku 5.5 ac7c91fc9c Reject layer IDs as targets of page.rename, delete and setBackground
Fixes #414

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:44:17 +02:00
bflatastic e11a182afd #400: a nested batch keeps its own step references
The outer batch passes a command.batch step on as written, so the inner
steps' `$step` references point at the inner batch's steps. The docs say
that `$step` is a reserved key in step params.
2026-10-15 18:30:05 +07:00