Commit Graph
9 Commits
Author SHA1 Message Date
Mateus Villain 825bb708df M7: fields select their text on focus
A click or Tab into a one-line field selects all of its text, so typing
replaces the value, as in Figma: hex and colour fields, inline fields
(a fill's hex, variable values, renames), names, the font size field,
search boxes and dialog fields (widgets::select_all_on_focus). A drag
from the press still selects only what it covers; multi-line fields
keep the caret where clicked.

The first click into an inline field (a fill's hex) now takes the
keyboard: egui dropped the focus of the editor created by that click,
so it took a second click.
2026-10-15 13:54:04 -03:00
BFlat a2e2012fdc M7: localization layer (#128)
UI strings come from per-language TOML catalogs compiled in (English text as the key and fallback, named placeholders, one/other plurals, context suffixes); command labels are translated at display time while ids, CLI, MCP and control output stay English; accessibility names follow. Preferences > Language (System / English / Español, live; the system language from the OS or the browser), pref.language for scripts. A key check test guards the catalogs. The Spanish catalog is a machine draft awaiting native review; docs/translating.md explains adding a language.
2026-10-11 16:21:16 +07:00
BFlat 7f9f2a0873 M9: branches: create, update from main, review and merge (#119)
Branches live inside the .figcraft file (base and head snapshots, own id space). Update from main and merge are three-way merges over the collaboration change sets; a conflict (same property changed on both sides, or delete vs edit) must be resolved branch-or-main before merging, which is one undo step on main. The review dialog reuses Dev Mode's compare view; branch tabs show a banner; File > Create branch; branch.* commands for CLI and MCP.
2026-10-11 12:45:38 +07:00
BFlatandClaude Opus 5.5 abe5ff3a1a M6: Dev Mode compare changes, focus view, annotation categories (#97)
- Compare changes: a ready-for-dev frame or section keeps a snapshot of itself from just before
  its first change (Document::dev_snapshots, saved only while changed; dropped on resolve, re-mark,
  other status or delete). `dev.compare {id?, show?}` diffs it layer by layer: added/removed
  layers, and property changes formatted like Inspect (`width 120 → 136`, `fill #FF0000 →
  #E03030`, text, parent, order, component, auto layout, typography, effects). The compare view
  shows before / now side by side or overlaid with a slider, changed layers outlined, the list of
  changes and Resolve change.
- Focus view: `dev.focus {id? | direction}` / `dev.unfocus`: one frame drawn and hit alone
  (render Options::solo), a bar with name, status, Compare changes, previous / next ready frame and
  exit; Escape leaves.
- Annotation categories: defaults plus the file's own with colours (`annotation.categories`,
  `addCategory`, `editCategory`, `removeCategory`), `category` on annotations, coloured callouts,
  a category filter and editor in the Inspect panel; stored backwards-compatibly.
- Shared widgets::icon_button / canvas_banner / dropdown_lead; has_status moved to the engine.
- Tests: devcompare_tests, devfocus_tests, annotation_categories_tests, doc handoff_tests, render
  solo_tests, UI dev_mode_tests.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 23:29:17 +07:00
BFlatandClaude Opus 5.5 c49a72ea88 M8: accessibility: screen reader names, keyboard navigation mode (#96)
* M8: accessibility: screen reader names, keyboard navigation mode

- Screen readers: the custom-painted controls report a role, name, value and
  state to AccessKit (number and text fields, dropdowns, segmented and toggle
  buttons, tools with their keys, layer rows as tree items, pages, tabs, menu
  items, the canvas describing the selection), from the shared widget helpers
  and a `Tip` trait for ad-hoc icon buttons. Regions are named containers.
- Keyboard navigation: F6 / Shift+F6 (view.nextRegion / view.previousRegion)
  cycle the toolbar, layers, canvas and properties; Tab / Shift+Tab move within
  a region and wrap; Enter or Space activate; arrows move along the toolbar and
  through the layer rows; menus and flyouts opened from the keyboard take it and
  give it back; Escape returns to the canvas. A focus ring (new `focus` token)
  shows until the next pointer press. Tab on the canvas selects the next layer
  again instead of moving egui's focus to the tab strip; Enter that starts a
  field edit no longer ends it.
- Reduced motion: pref.reduceMotion and the system setting (Windows
  UISettings, macOS, GNOME, prefers-reduced-motion) turn egui's animations off.
- Contrast: light secondary and accent text meet WCAG AA.
- ui.inspect reports focus {region, keyboard, control} and reduceMotion;
  ui.set {focusRegion}.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* M8: parity report command count after merging main

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* M8: accessibility: regression test against nested egui context locks

A debug build's temporary logging called the context inside a context closure and hung; the shipped code never does. Document the rule in a11y.rs and run every accessibility path with the AccessKit tree on, so a nested call fails the test (debug builds panic after 10 s) instead of hanging.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 23:02:50 +07:00
BFlatandClaude Opus 5.5 0c3494b021 M7: popup menus sized to their content (#83)
egui measures a popup in an invisible first pass as wide as the width it is
given, else its 600 px default area width, and menu rows filled the available
width, so every menu opened from the right panel came out about 600 px wide.

- right::menu_popup / context_popup: menus measured at the opening control's
  width, text kept on one line; every Popup::menu and context menu uses them.
- menu_row takes the larger of the menu's width and its own content (label,
  shortcut, art width), so a menu is as wide as its widest row and at least as
  wide as its dropdown; explicit .width(w) is now a minimum. Menus at the
  panel edge stay inside the window.
- Headless tests: a menu fits its widest row without wrapping, and the
  Inspect panel's dropdown menu fits the panel.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 16:16:35 +07:00
BFlatandClaude Opus 5.5 e0200acbae M6: autosave checkpoints in version history (#38)
Every 30 minutes, each open document with unsaved changes since its last
version gets an automatic "Autosave" version (flagged `auto` in the file).
The newest 20 autosaves are kept; older ones make room and user versions
are never dropped for them. Runs of autosaves fold into one line in the
Version history panel. New command version.autosave.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 05:48:21 +07:00
BFlatandClaude Opus 5.5 ce317cdf42 M6: view a version on the canvas before restoring it (#36)
Clicking a version in Version history shows it in place of the document,
read-only, with a banner to restore it or go back to the current version
(clicking Current version or closing the panel goes back too). Edits,
undo and gestures are refused while a version is shown; saving, closing
and restoring end the preview first, so the document and its unsaved
state are never touched by it.

New commands version.preview and version.exitPreview; version.list marks
the shown version.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 05:34:06 +07:00
BFlatandClaude Opus 5.5 72b8c5d154 M6: version history: versions saved in the .figcraft file, version commands and panel (#21)
- Versions now belong to the document (DocState.versions) instead of a process-global map keyed by
  document uid, so they survive closing the file. A new, renamed or deleted version marks the file
  as changed.
- .figcraft: `versions/index.json` (id, name, description, time, image hashes) plus one deflated
  `versions/<id>.json` snapshot per version; images only versions use are stored once and kept with
  them. Snapshots read from a file are parsed on first use (and written back as-is). Readers that
  don't know versions ignore the entries; files without versions load unchanged. Damaged, missing,
  oversized or duplicate entries are skipped and reported, never failing the load. At most 100
  versions per file; names and descriptions are clipped.
- Commands: `file.saveVersion {name?, description?}` returns the version; `version.list`;
  `version.restore {id | index}` (one undo step, keeps the file name, stays on the current page);
  `version.rename {id | index, name, description?}`; `version.delete`; `version.duplicate` (opens
  the snapshot in a new tab). Indexes are validated: a negative index used to restore version 0.
  `req_index` param helper shared with the guide commands.
- Version history panel in the left sidebar in place of Pages and Layers (File > Show version
  history; Save to version history opens it with the form): save form (title, description),
  "Current version" on top and the versions newest first on a timeline with name, relative time and
  description; per-version menu (also right-click): Restore, Rename (title and description inline),
  Duplicate, Delete (confirmed inline). New shared `widgets::button`.
- `figcraft-cli run --out x.figcraft` keeps the version history.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-10 04:16:18 +07:00