Commit Graph
923 Commits
Author SHA1 Message Date
BFlat 8dc3ab5703 Merge pull request #669 from yelintong/feat/flutter-codegen
M7: Flutter code generation
2026-10-29 13:37:49 +07:00
bflatastic a81efe5466 Merge main into #669 2026-10-29 11:52:03 +07:00
bflatastic 9b3683036c Merge main into #1210 2026-10-29 11:43:04 +07:00
BFlat 60ea32f171 Merge pull request #1465 from phonedu/mcp-agent-feedback
M12: MCP comment feedback and live change events
2026-10-29 10:51:24 +07:00
BFlat 91cc0f1fad Merge pull request #1406 from yelintong/feat/constraint-guides
ui: show constraint guides for a selected layer in its frame
2026-10-29 10:51:17 +07:00
BFlat 2e6612e002 Merge pull request #1457 from culiulemon/pr/misc-fixes
feat: property copy/paste, blend-mode hover preview and clipboard fixes
2026-10-29 10:47:30 +07:00
BFlat fbc1cc63ba Merge pull request #1462 from Skyfuller1303/fix/home-tab-sidebar-alignment
M7: line the Home tab's divider up with the icon rail
2026-10-29 10:45:54 +07:00
bflatastic 0cc380c228 Merge main into #1466 2026-10-29 10:08:11 +07:00
bflatastic 6abddb0f68 Merge main into #1465 2026-10-29 09:55:55 +07:00
bflatastic 158d402ee7 Merge main into #1457 2026-10-29 09:55:12 +07:00
bflatastic fe56681075 Merge main into #1406 2026-10-29 09:55:07 +07:00
bflatastic d7945584b3 Merge main into #1462 2026-10-29 09:54:48 +07:00
BFlat 7f646aac24 Merge pull request #1468 from samhyun/perf/web-zoom-settle
M8: the browser refines a zoom only once it has paused
2026-10-29 09:49:26 +07:00
BFlat 5804c0e2cc Merge pull request #1489 from ChristopherLinnett/issue/857-confirm-quit
fix(app): ask before ⌘Q quits with unsaved changes (#857)
2026-10-29 09:41:19 +07:00
BFlat 738f7c7692 Merge pull request #1470 from watchakorn-18k/fix/context-menu-frame-label
fix(ui): right-click on a frame's name label picks that frame
2026-10-29 09:37:58 +07:00
bflatastic e83f9691b3 Merge main into #1466 2026-10-29 09:32:26 +07:00
BFlat cff1d0bf45 Merge pull request #1487 from ChristopherLinnett/issue/1096-openurl-gesture
fix(present): prototype links open only behind the notice or a viewer's click (#1096)
2026-10-29 09:30:04 +07:00
bflatastic 6c18fe916b Merge main into #1466 2026-10-29 09:23:22 +07:00
bflatastic 2bc14d946b #1465: split the event and prompt code for cognitive complexity, drop the panel header button 2026-10-29 09:20:55 +07:00
bflatastic dfe83f63f0 Merge main into #1470 2026-10-29 09:19:59 +07:00
bflatastic 9d42833008 Merge main into #1465 2026-10-29 09:18:39 +07:00
bflatastic 5f58acdb35 #1406: guides for an absolute child of an auto layout frame, and a test 2026-10-29 09:17:25 +07:00
bflatastic fba0ae85c3 Merge main into #1406 2026-10-29 09:14:58 +07:00
bflatastic fdaaeaa218 Merge main into #1462 2026-10-29 09:11:30 +07:00
Nicek 1c253ef30d fix: pasted image keys stay archive-valid when the content hash is taken
The blend menu and its hover preview now live beside upstream's split menu module.
2026-10-29 09:46:50 +08:00
Nicek c6ba81b6e6 test: 同帧按下/松开绘制从按下点开始的回归用例 2026-10-29 09:33:55 +08:00
Nicek dd93a6a2a8 fix: 修复 PR #1457 的选择与拖拽评审问题
- 标签在选择边界外也参与收窄,Dev Mode 单击已选图层只选它
- 区分点击命中图层与描边空白处的拖拽回退目标
- 重排圆环按按下时的修饰键判断点击,画布外松手视为拖拽结束
- 修复 clippy unnecessary_get_then_check
2026-10-29 09:33:55 +08:00
Nicek f8ddb5a0a8 feat: 复制属性后显示提示 2026-10-29 09:33:55 +08:00
Nicek ce93dc6ff5 feat: 混合模式悬停预览、多选层点击与图层属性预览 2026-10-29 09:33:54 +08:00
Nicek 88477723c5 fix: ArkUI 百分比间距输出与同帧按下/松开坐标 2026-10-29 09:33:54 +08:00
Nicek bb495bcf70 feat: 属性与样式复制粘贴,含图片/图案跨文件处理与多语言 2026-10-29 09:33:20 +08:00
Christopher Linnett 0e508fd316 fix(app): a second quit before the window draws counts once (#857)
The app's logic runs while the main window is minimised, without the
frame that acts on a close. Two quits there queued the main window's close
twice: the first let it take over another window, and the second then
quit the app over that window's unsaved changes, as answered.

- close_current queues a window's close only once.
- Test: quitting_twice_before_the_window_draws_closes_it_once.
- docs/hardware-parity.md revision history.
2026-10-29 08:50:00 +08:00
Christopher Linnett 7660877845 fix(present): nothing opens or releases behind an open link notice (#1096)
- finish(): a viewer-fired link opens directly (notice skipped) only while
  no notice shows; any other link that fires while one shows is dropped.
- finish(): raising a notice ends the press under way, so its release
  doesn't fire the prototype's mouse-up actions (a link, a navigation)
  behind the notice, which takes no input while it shows.
- The mail notice says the link opens the mail app to write a message
  (opening a mailto: link doesn't send anything).
- Tests: nothing_opens_while_a_notice_shows_with_the_notice_skipped,
  a_press_that_raised_a_notice_doesnt_release_behind_it.
- docs/prototyping-parity.md row and revision history.
2026-10-29 08:50:00 +08:00
Christopher Linnett 73398cedf1 fix(app): ask before ⌘Q quits with unsaved changes (#857)
winit's default macOS app menu ends the process through AppKit's
`terminate:` at once, so ⌘Q and Quit from the menu bar never asked about
unsaved changes (the recovery copies were all that survived).

- Install craft-libs' app menu (craft-menu, same rev as the other
  craft-libs pins; macOS only). Its Quit sends the main window a close
  request, the same path as the window's close button, so
  windows::on_close_request cancels the close and the unsaved-changes
  question asks first. Failure to install keeps winit's menu and logs it.
- windows_tests::a_quit_with_unsaved_changes_waits_for_the_answer pins
  the contract the menu relies on: a close request with unsaved changes
  sends CancelClose and asks; Don't Save then closes.
- Like the close button it closes the main window only: with several
  windows open, each quit closes one (documented).
- docs/hardware-parity.md macOS row, status line and revision history.
- Cargo.lock: craft-menu, craft-quit, craft-keymap, muda and their deps;
  cargo's own minimal resolution also moves a few windows-sys/getrandom
  edges to versions already in the lock.
2026-10-29 08:11:13 +08:00
Christopher Linnett 53f47706ec fix(present): prototype links open only behind the notice or a viewer's click (#1096)
An Open link action carries a URL from the document and fires from whatever
trigger the prototype sets, so an unattended presentation could open web links
and mail messages one after another: a mail link bypassed the leaving-the-
prototype notice entirely, and a skipped notice let any trigger open any
number of links.

- finish() routes every openable URL, mail included, through the notice.
- Skipping the notice ("Don't show this again") opens at once only a link the
  viewer's own click, press, drag or key fired, one per frame. A delay, the
  pointer passing over a layer (enter, leave, hover) and a timed mouse
  trigger that fires after the gesture is over still show the notice, which
  then offers no checkbox: it couldn't skip that notice anyway.
- The player tags each queued link with whether the viewer fired it
  (Presenter::fire_from); an OpenUrl outside an interaction defaults to not.
- The notice covers mail links (new locale string, mail wording).
- Engine prefs/command doc text follows the rule; behavior untouched there.
- present_links_tests: shared setup helpers for the link tests; new
  tests for the skip rule (delay, hover, delayed mouse-up, key, one link per
  click, checkbox only for clicked links); the scheme-filter test now clicks
  with the notice skipped so the filter alone keeps those URLs out.
- docs/prototyping-parity.md row, status line and revision history updated.
2026-10-29 08:11:13 +08:00
Filip StrajnarandClaude Opus 5.5 8d7c094224 M1: the stroke weight keeps room for its value beside the variable button (#1452)
The stroke's position dropdown took half the row and the weight field what
was left after the per-side and Advanced buttons: about 40 pt at the
panel's default width, so the variable button sat on the weight's icon and
hid its value, and the row ran 3 pt past the panel's edge. The position
and the weight now share what the buttons leave: the panel's two columns
for layers without per-side strokes, and about 66 pt each with them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6E2qDnjtMzfPVuEP7iH
2026-10-28 22:10:28 +01:00
Dylan M. Taylor ffb4fc7e3e refactor(ui): simplify app and presentation handlers 2026-10-28 16:00:36 +00:00
Dylan M. Taylor 252d909427 refactor(ui): simplify widgets and dialogs 2026-10-28 16:00:36 +00:00
Dylan M. Taylor 927ceb0638 refactor(ui): simplify panels and menus 2026-10-28 16:00:36 +00:00
watchakorn-18kandClaude Sonnet 5.5 38ab0eaa6b docs(ui): document the right-click label pick and its tests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015wxxFg3gana4zaUKnyirTC
2026-10-28 22:27:29 +07:00
watchakorn-18kandClaude Sonnet 5.5 df6062d7fb fix(ui): right-click on a frame's name label picks that frame
The context menu looked only at what is under the pointer on the page, so a name label drawn over
its section selected the section. Copy link to selection then gave every frame in that section the
section's link. Labels now win, as they do on a press.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015wxxFg3gana4zaUKnyirTC
2026-10-28 22:14:06 +07:00
samhyunandClaude Fable 5.1 3773a60801 M8: the browser's wait after a preview never exceeds the render it may save
With a fixed 120 ms wait, a page whose full renders take 15–100 ms was held coarse for 120 ms
after a key zoom or a page switch, where before it was refined in the next frame. The wait is
now the last full render's time when that is shorter than `SETTLE_MS`: a wait never costs more
than the render it may save, and on a heavy page (seconds a render) it is 120 ms as before.

Also from review: the test that the wait counts from the preview no longer times a preview
render (a margin of a few milliseconds under load); a sleep between the request and the poll
stands in for the render, with the whole settle as margin. `Inline::in_flight` says that a
preview's wait counts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-28 22:53:07 +09:00
phonedu 8e6b3bf449 M12: MCP comment feedback and live change events
Comments become the task queue for an attached or headless MCP client: comment.prompt returns a bounded Markdown brief, the Comments panel gains Copy for AI, and the MCP server exposes fix_comments, watch_comments, figcraft://comments and wait_for_changes. Mutating comment.* commands append to a bounded in-memory event log; the control channel's events.poll long-polls it without the UI thread, and a successful batch commits its events only if the whole batch lands. No model, network dependency, asset or file-format change.
2026-10-28 21:42:31 +08:00
samhyunandClaude Fable 5.1 8c951810ab M8: a test for same-zoom requests before a zoom refines; the gaps status line
From the review of #1468: a pan or an edit at the new zoom before its full render has run
renders from scratch too, so it shows a preview and restarts the wait instead of running a
blocking full render between it and the next step; once refined, requests at that zoom build
on the kept image and are refined at once. The new test pins both down. The status line of
`docs/gaps.md` now carries the date of the gap 7 entry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-28 22:29:55 +09:00
samhyunandClaude Fable 5.1 f24a8312f7 M8: the browser refines a zoom only once it has paused
The browser renders on the UI thread. A zoom showed its coarse preview and then, in the very
next frame, ran the full render, so every wheel step of a continuous zoom had a blocking full
render between it and the next: on a heavy page each one took seconds, and the zoom stuttered
for as long as it went on.

The browser's worker (`Inline`) now refines a preview only once no newer request has come for
`SETTLE_MS` (120 ms) after the preview was shown: the zoom has paused. Each wheel step still
shows its preview at once, and the worker asks for a repaint when the wait is over. Pans and
edits have no preview and are refined at once, as before. The desktop has a render thread of
its own and is unchanged. A zoom passing through a scale also no longer spends a full render
there.

The wait counts from the preview being handed over, not from the request: rendering the
preview can itself take longer than the wait (the page is blocked meanwhile, so no newer
request could have come), and counted from the request the full render would follow in the
very next frame, as before.

Measured in Chrome on a synthetic page of 20 images, 60 shadowed rectangles and two
background blurs (a full render takes about 3.7 s, a preview about 250 ms), 20 wheel steps in
and 20 out, 50 ms apart, three runs each: the frame interval's p95 went from 3.7 s to 240 ms,
the frames over 100 ms from 79–80 (one full render per step) to 39–41 (one preview per step),
and the zoom took 10–12 s instead of 141 s. The one full render after the pause still takes as
long as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-28 22:10:27 +09:00
hussain-hz 636096fad3 M10: add Arabic draft interface catalog
Translate 2508 interface entries from English, keep count-neutral plurals, and gate the web catalog on Arabic font readiness. Record AI assistance and pending native review.

AI-assisted-by: OpenAI Codex
2026-10-28 15:16:31 +03:00
Skyfuller1303 4b13e4e3cf M7: line the Home tab's divider up with the icon rail
The Home tab started at x=8 and was 44 wide, so its divider sat at x=52 while the icon rail below is 56 wide. Without inset window buttons the Home tab now ends at the rail's width (shared RAIL_WIDTH constant), so the divider continues the rail's edge. The inset (macOS) title bar keeps its 44-wide Home tab.
2026-10-28 10:00:02 +01:00
aiongg bdb7e84606 fix(ui): dropdown menus grow back after a search with no matches (#1429)
* feat(ui-egui): font family menu keeps its search field and grows back after a filter clears

Repin craft-libs to the shared dropdown (craft-ui), move the font family menu to
craft_ui::combo::Menu with the search in a fixed header, and use craft_ui::ComboBox
for the credits sort. clippy bans egui::ComboBox.

* chore(deps): craft-libs 60d60d48 (dropdown fixes)

* chore(deps): craft-libs 4d7b82f7 (dropdown fixes)

* chore(deps): craft-libs 92d392cf (#387 merged)

* fix(ui-egui): craft-ui on every target (wasm uses the shared ComboBox too)
2026-10-27 10:28:10 -04:00
叶林橦 5f7aea91f9 ui: rebuild the toolbar pill on a 32 pt grid, without the Resources button
Brings #1210 onto main as it stands after #1019 and #1209, and keeps both:

- #1019's flyout caret keeps its 16 pt target, 2 pt clear of its tool (#988).
- #1209's narrow-window handling stays as it landed: the pill is never wider
  than the canvas less a margin and its buttons scroll inside it under a drag
  or the wheel, the help button lifts above it when they'd overlap, and the
  pill still clips to itself rather than floating over the panels.

The design itself, as #1210 proposed it:
- One grid for every state of the pill: 32 pt cells, 8 pt padding, 8 pt between
  top-level items (the divider included), a 1 pt divider as tall as the content,
  16 pt carets, 14 pt mode marks, and a 32 pt mode strip whose current mode is a
  plain inset with no outline.
- The Resources button goes; the left rail's Assets tab, Shift+I, Alt+2 and
  View > Panels > Assets remain the ways into the Assets panel (and the locale
  key, its test and the parity notes go with it).
- The vector edit and shape builder pills move onto the same grid, so a pill
  never changes its spacing as the tool changes.

main_width is now the same walk the pill draws, and a test walks it for the
design and board toolbars: the last item ends exactly PAD from the right edge.
That caught the board pill asking for 8 pt more than it drew.
2026-10-27 12:28:49 +08:00
叶林橦 59b9b90ee0 ui: show constraint guides for a selected layer in its frame
Split out of #932 (the 2 px outlines and missing frame radius handles there
move the canvas away from the reference tool, but the constraint-guides part
is good on its own — bflatastic, #issuecomment-6420566791). When a layer inside
a non-auto-layout frame is selected, blue dashed guides show how it is pinned:
a left/right/top/bottom constraint draws a line from the layer's edge midpoint
to the frame edge, and both-axis constraints draw both. A centre constraint
marks the layer itself with a short solid bar through its middle — horizontal,
vertical, or a cross when centred on both axes — rather than a guide reaching
the frame's centre.
2026-10-27 11:56:53 +08:00