Commit graph

317 commits

Author SHA1 Message Date
Danila Poyarkov 4077dcbd44 fix: preserve authored instance sizing through synchronization 2026-09-14 00:24:52 +03:00
Danila Poyarkov 4340f864a4 test(properties): group corner specs by domain 2026-09-13 14:52:20 +03:00
Danila Poyarkov eb38da0d08 fix(properties): preserve shared corner bindings in collapsed controls 2026-09-13 14:45:26 +03:00
Danila Poyarkov df28cf5832 chore: update property controls with master 2026-09-13 14:11:22 +03:00
Danila Poyarkov 7af5e05f9c test(snapping): verify pixel rounding without guides 2026-09-13 14:02:16 +03:00
Danila Poyarkov de6c0efc00 fix(renderer): preserve proportions of FIT image fills 2026-09-13 13:48:11 +03:00
Danila Poyarkov 0dd1014c2a fix(properties): simplify Effect styles and equivalent corners 2026-09-11 03:27:27 +03:00
Danila Poyarkov 89b60b9870 fix(clipboard): preserve typed selection data across copy and paste 2026-09-11 02:59:31 +03:00
Danila Poyarkov b6f015a9f6 fix: address Select forwarding and MCP readiness review 2026-09-10 23:54:03 +03:00
Danila Poyarkov a4a916c97a test: seed motion preferences through Playwright storage state 2026-09-10 23:24:06 +03:00
Danila Poyarkov cf86685c51 test(motion): cover legacy preferences and mobile Off mode 2026-09-10 23:13:31 +03:00
Danila Poyarkov 70341c33a1 feat(settings): centralize motion policy and add animation preference 2026-09-10 23:10:24 +03:00
Danila Poyarkov cc99e6ecb3 fix(dialog): honor reduced motion over state animations 2026-09-10 22:40:19 +03:00
Danila Poyarkov d3b8942dcc test(properties): refresh verified panel snapshots 2026-09-10 22:29:45 +03:00
Danila Poyarkov ccb9dcdd5b test(chat): describe streaming animation coverage accurately 2026-09-10 21:41:11 +03:00
Danila Poyarkov 7f80296c3b fix(ui): preserve focus for composed icon triggers 2026-09-10 21:41:10 +03:00
Danila Poyarkov 608cbc9960 fix(chat): animate inserted Markdown lists and code lines 2026-09-10 19:49:37 +03:00
Danila Poyarkov 3d74f52344 fix(properties): simplify style controls and anchor variable pickers 2026-09-10 19:49:37 +03:00
Danila Poyarkov eb277dd2a9 fix(settings): stabilize model editing and animate dialogs 2026-09-10 19:49:36 +03:00
PAVEL TKACHEV 6e74ad2a51
fix(pen): honor layout and sizing defaults (#652)
Fixes #564.
2026-09-10 17:02:56 +03:00
Danila Poyarkov a779edd08a
refactor: scope browser test instrumentation and global types (#667) 2026-09-10 14:26:36 +03:00
Danila Poyarkov 77739c42a4
fix(bindings): resolve modes and preserve edit transactions (#671)
* fix(bindings): capture mode edits and expose unresolved values

* fix(bindings): correct unresolved accessibility metadata

* fix(bindings): distinguish mixed identities from unresolved values
2026-09-10 12:14:04 +03:00
Danila Poyarkov e69ba75c12
refactor(ui): compose shared editor controls (#670)
* refactor(ui): extract shared action and navigation primitives

* refactor(ui): compose settings and libraries with shared tabs

* feat(ui): preserve native activation and toolbar keyboard navigation

* refactor(home): share document entries and accessible input controls

* fix(layers): share virtualized row geometry and selection styling

* refactor(layout): compose spacing and readable dimension controls

* refactor(properties): compose advanced strokes and inline effects

* refactor(ui): reuse actions in page and property controls

* refactor(settings): adopt shared actions without changing workflows

* refactor(ui): share collaboration and provider actions

* refactor(ui): finish shell and paint action composition

* test(ui): restore extracted control and settings coverage

* test(ui): complete workflow extraction coverage

* fix(ui): address review and trim redundant snapshots

* fix(layout): preserve single-step Undo for guides and wrap
2026-09-10 12:09:06 +03:00
Danila Poyarkov 6cec1b2c58
fix: prevent repeated Keychain prompts and isolate native tests (#664)
* fix: prevent repeated Keychain prompts and isolate native tests

* fix: make credential settings contextual and actionable

* fix: refresh credential recovery state in open Settings

* fix: allow retrying credential status checks

* fix: recover credential access after backend panics

* test: centralize native Tauri invocation

* refactor: clarify credential preferences workflow path
2026-09-09 13:41:55 +03:00
Danila Poyarkov 86269ff440 Merge remote-tracking branch 'origin/master' into fix-pr-657 2026-09-08 13:20:09 +03:00
Danila Poyarkov 85eb57559e fix(keyboard): match Figma zoom behavior 2026-09-08 12:29:55 +03:00
Danila Poyarkov b4e479d9d0
feat: persist AI conversations and add chat history (#661)
* feat: persist AI conversations and add chat history

Store transcripts and attachment previews in IndexedDB, separate conversation history from transport lifetime, and add document-aware switching with shared Storybook coverage. Preserve interrupted activity and guard stale writes and async switches.

* test: group chat history tests by domain

* feat: simplify chat history navigation and diagnostics

Use a compact header with searchable document-scoped history and a correctly anchored conversation menu. Move diagnostic copying into the menu with copy-result feedback, and separate Storybook fixtures from composition.

* fix: address chat history review findings

* test: cover harness shutdown and restored chat scrolling

* fix: preserve Portless proxy port in MCP routes

* docs: clarify UI animation conventions

* feat: configure reasoning display and animate disclosure

* fix: separate transcript following from reasoning disclosure

* fix: restore selected chat after document recovery

* refactor: separate chat history persistence and sessions

* style: format reasoning story imports
2026-09-08 11:19:07 +03:00
7ot0m3 992102f3a5 test(keyboard): exercise zoom shortcuts with real input 2026-09-07 10:51:54 +08:00
7ot0m3 ec6c42f0e5 fix(keyboard): route zoom shortcuts to canvas 2026-09-07 10:36:10 +08:00
PAVEL TKACHEV c946337f3d
fix(pen): resolve ordinary variable references (#622)
* fix(pen): resolve ordinary variable references

Recognize nonempty dollar-prefixed variable names while preserving double-dash references and existing bindings.

Add parser regressions, a reproducible .pen fixture, and visual coverage comparing variable references with literal values.

Update the Unreleased changelog for #563.

* test(pen): strengthen variable reference coverage

---------

Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-09-06 23:50:03 +03:00
Danila Poyarkov 61f11e7d24 fix(ai): surface actionable provider failures
- Classify authentication, access, model, rate-limit, network, and credit errors\n- Preserve the original provider error across the no-output stream consequence\n- Add optional toast actions for opening model settings\n- Consume handled chat send rejections to avoid global unhandled errors\n- Localize provider failure guidance and cover the authentication flow
2026-09-04 16:41:03 +03:00
Danila Poyarkov b9731f6a90 test(chat): isolate domain specs and real LLM runs
- Replace the shared serial page with isolated configured-chat fixtures\n- Split composer, attachment, Markdown, profile, navigation, and response behavior\n- Use Playwright's structured @real-llm tag with a credential-gated config\n- Keep mock stream construction and page operations in focused helpers
2026-09-04 11:50:12 +03:00
Danila Poyarkov 1455fab099 test(chat): isolate real LLM smoke coverage
- Keep deterministic chat tests permanently bound to the mock transport\n- Add an explicit @real-llm Playwright project and package script\n- Skip the paid OpenRouter smoke test clearly when its credential is absent
2026-09-04 11:31:31 +03:00
Danila Poyarkov c3a560d2b9 test(chat): extract browser harness
- Move chat app setup and shared locators into the test helper domain\n- Move mock AI stream construction out of the panel specification\n- Keep the panel behavior suite focused on user-facing assertions
2026-09-04 11:26:30 +03:00
Danila Poyarkov bd24220b9a feat(chat): preserve node attachments in history
- Generalize transcript presentations across image and node attachments\n- Snapshot referenced nodes when sending so history survives graph changes\n- Reuse one attachment card and viewer for both attachment kinds\n- Localize attachment actions and remove image-processing details from the viewer
2026-09-04 10:55:42 +03:00
Danila Poyarkov c5158edc82 fix(chat): redesign Design profile picker
- Give configured profiles a full-width multiline selection surface\n- Show resolved model and provider metadata with a stable selection indicator\n- Keep Vision capability compact and link back to model-role settings\n- Split chat Markdown and profile themes into focused domain files
2026-09-03 20:58:32 +03:00
Danila Poyarkov f5db783797 fix(chat): align vision and model role UX
- Restore attachment inset spacing through the InputGroup theme slot\n- Mark curated multimodal models as Vision-capable and repair saved capability metadata\n- Default Vision to the Design profile when that profile accepts images\n- Use configured Design profiles in the composer instead of raw provider models\n- Surface missing Vision configuration directly in Settings\n\nCo-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>
2026-09-03 19:58:09 +03:00
Danila Poyarkov a8c7fedadb feat(chat): unify composer attachments
- Render node references and images with one attachment-card layout\n- Generate live previews for referenced scene nodes\n- Make the current-selection control toggle its active selection\n\nCo-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>
2026-09-03 19:05:10 +03:00
Danila Poyarkov 21b1d25bff fix(chat): derive Markdown image origin at runtime
- Restrict assistant-rendered images to the active deployment origin\n- Cover local and self-hosted origins without hardcoded production hosts\n- Verify cross-origin, insecure, and data image rejection in browser tests\n\nCo-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>
2026-09-03 14:12:14 +03:00
Danila Poyarkov dd53d08474 refactor(chat): adopt upstream Markdown v2
- Replace the fork-era Markdown integration with Comark and an explicit Shiki extension\n- Centralize OpenPencil theming, parser lifecycle, controls, and URL hardening\n- Remove Mermaid stubs and bundled math or diagram dependencies\n- Address contextual composer review findings and extend browser coverage\n\nCo-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>
2026-09-03 13:34:55 +03:00
Danila Poyarkov f0afe3c4d7 feat(chat): adopt contextual composer improvements
- Pin selected layers as bounded context without exposing metadata in transcript bubbles
- Show collapsible reasoning and copy individual assistant responses
- Autosize multiline prompts and cover the new chat states in browser tests

Co-authored-by: Jason Kneen <jason.kneen@bouncingfish.com>
2026-09-03 11:40:50 +03:00
Danila Poyarkov 0e9c0ee6cf
feat: add searchable command palette
Adds a localized, Fuse-powered command palette for app actions and a reusable Vue SDK primitive, with Storybook and Playwright coverage.
2026-09-01 23:08:32 +03:00
Danila Poyarkov 9bb9478833
refactor: replace complex conditional object spreads
- Add a typed, modular custom Oxlint rule package with direct regression coverage
- Replace complex conditional object spreads with explicit construction across the repository
- Preserve all existing custom rule registrations and diagnostic behavior
2026-09-01 19:49:57 +03:00
Ed-Key 9b48e47329 feat(canvas): render arrow stroke caps on lines and open vectors
ARROW_LINES and ARROW_EQUILATERAL stroke caps were accepted by the schema
and round-tripped from .fig files, but the renderer mapped every cap to
Butt, so imported arrows lost their heads and arrows could not be drawn
locally.

Add a pure arrow-cap geometry module to scene-graph (open-endpoint
collection with per-vertex cap overrides, weight-scaled head geometry)
and draw heads in the stroke color for LINE nodes and open VECTOR
centerline strokes, including the dashed-centerline path. Fold the head
reach into strokeOverflow and the node picture margin so heads are not
cropped by visual bounds, caches, or culling. Round-trip per-vertex
stroke caps through the .fig vector style override table so one-ended
Figma arrows import correctly. Expose both caps in the stroke inspector
cap picker with localized labels, and cover the renderer with an
arrow-stroke-caps Playwright canvas snapshot.

Claude-Session: https://claude.ai/code/session_012zjEbyLSBYyPpJP4fu1XNB
2026-08-31 21:25:38 +03:00
Danila Poyarkov 379ef8b62d
perf(canvas): rebuild navigation rendering (#591)
* perf(canvas): add traced navigation benchmarks

- Record and replay timestamped pan and zoom gestures through DOM and CDP input paths\n- Correlate input, viewport, render, long-task, and retained-backing events in Chromium traces\n- Report frame pacing, latency, jump, anchor drift, and crisp-settlement metrics

* perf(canvas): stabilize navigation comparisons

- Separate low-overhead metric runs from optional CPU-profile traces\n- Warm scenarios before recording and use a consistent SwiftShader browser configuration\n- Add a canonical momentum-pan reversal gesture alongside pinch reversal

* fix(canvas): require hardware GPU navigation benchmarks

- Run macOS performance captures through Metal-backed ANGLE and reject accidental SwiftShader fallback\n- Record the GL renderer and reserve software GPU mode for portable correctness smoke runs

* perf(canvas): cache shadow rasters for crisp backing

- Rasterize local drop and inner shadows only while constructing retained scene backing\n- Bound native image memory and invalidate cached entries with node and renderer lifecycle changes\n- Quantize zoom-aware raster resolution and reuse nearby scales without lowering normal scene quality

* test(canvas): verify retained shadow raster fidelity

- Compare settled retained-backing shadow output with direct CanvasKit rendering\n- Keep backdrop blur on the picture fallback and exercise graph-driven cache invalidation\n- Cover updates, deletion, and reparenting through actual SceneGraph events

* perf(canvas): benchmark real FIG fixtures

- Serve exact local fixture bytes through an isolated Playwright route for production preview runs\n- Wait for document loading and page population before zooming to fit and recording navigation\n- Record the resolved fixture path in benchmark environment artifacts

* fix(canvas): preserve nested effect subtree pictures

- Keep deeply nested shadow documents on one retained subtree picture instead of exploding them into per-node image draws\n- Restrict shadow raster acceleration to effect-bearing page children\n- Cover nested shadow fallback and restore gold-preview FIG pinch performance to master levels

* refactor(canvas): share recorded wheel sample type

* perf(canvas): defer backing settlement across zoom reversals

- Track explicit navigation phases and gesture generations instead of inferring idle from viewport timing\n- Cancel or defer retained backing construction while pan, zoom, momentum, or tentative settlement is active\n- Add a repeated short-pause pinch reversal fixture based on the user trace

* perf(canvas): index bounded render chunks

- Split oversized painter subtrees into self-paint and bounded descendant chunks without dropping container visuals\n- Bulk-load chunk visual bounds into RBush for selective world-space queries\n- Cover bounded updates and gold-preview build/query complexity before tile rendering consumes the index

* refactor(canvas): namespace render chunk coverage

* perf(canvas): model chunk paint context

- Preserve ancestor transform and clip dependencies for independently renderable chunks\n- Keep opacity, blend, blur, and mask isolation subtrees atomic until command-level splitting exists\n- Report oversized atomic chunks and lock gold-preview to bounded painter units

* perf(canvas): record pixel-correct render chunks

- Record interruptible chunks in world coordinates with ancestor transforms, clips, and chunk-local culling bounds\n- Draw opacity, blend, blur, and mask isolation chunks directly into destination surfaces in painter order\n- Compare composited chunk output with direct CanvasKit rendering instead of relaxing visual thresholds

* perf(canvas): render selective world tiles

- Map world regions to fixed 256-device-pixel tile targets and quantized sharpness levels\n- Query only intersecting render chunks and preserve atomic destination compositing\n- Match multi-tile CanvasKit output against direct rendering and measure gold-preview tile cost

* perf(canvas): cache chunk pictures across tiles

- Reuse world-space chunk command pictures for every intersecting tile\n- Pool 256-pixel tile surfaces and expose allocation, draw, flush, and snapshot timings\n- Keep expensive atomic foreground blur visible as an over-budget scheduler constraint

* perf(canvas): schedule cached tile rendering

- Bound tile images with an LRU cache and reuse pooled CanvasKit surfaces\n- Plan mandatory holes, stale visible refreshes, and overscan by navigation and content generation\n- Stop jobs at a strict deadline while reporting fallbacks, stale work, overruns, and over-budget effects

* perf(canvas): integrate progressive tiled rendering

- Keep retained scene output as the interaction fallback while exact tiles refine only after navigation becomes idle
- Centralize runtime URL flags and pass renderer selection through the typed Vue canvas API
- Replace benchmark sleeps with explicit mode-aware renderer settlement and report exact tiled coverage
- Preserve bounded scheduler metrics, generation cancellation, native resource cleanup, and shared visual-bounds logic

* refactor(app): centralize runtime query configuration

- Parse collaboration, recent-files, benchmark, presentation, and renderer flags in one typed app module
- Remove ad hoc URL parsing from workspace and collaboration runtime consumers
- Cover supported values and production-safe defaults without adding a repository lint rule

* fix(canvas): replace fallback pixels with exact tiles

- Render opaque page-background tile cells and install them with source replacement instead of double-compositing translucent scene content
- Exercise the live progressive controller against direct rendering across masks, effects, blend isolation, images, fallback text, transforms, and clipping
- Preserve the bounded reversal path with zero Long Tasks and exact settlement near 128 ms on gold-preview.fig

* perf(canvas): invalidate tiled content selectively

- Index chunk dependencies across contained nodes and transform or clipping ancestors
- Re-record affected chunk pictures and invalidate tiles intersecting old or new visual bounds
- Advance unaffected cached tiles to the new scene generation instead of rebuilding the full chunk index and tile cache
- Keep structural graph mutations on the safe full-rebuild path and cover selective refresh end to end

* perf(canvas): bound atomic blur tile refresh

- Render atomic blur chunks with tile-local isolation bounds and blur halos instead of replaying full-subtree layers
- Keep content refresh behind the retained fallback, cap GPU submissions to four tile jobs per frame, and adapt estimates from measured work
- Preserve large-radius CPU over-budget visibility while preventing Metal-backed refresh bursts and deferred GPU overload
- Add deterministic node-mutation benchmarks and summarize scheduler throughput, job duration, overruns, and exact content settlement

* perf(canvas): cancel obsolete tile refresh generations

- Count and report queued jobs removed by content or navigation generation changes
- Add deterministic mutation-then-reversal benchmark support without sleeps
- Assert exact tile work remains suspended during navigation and resumes for the final viewport
- Summarize cancellation alongside scheduler throughput, overruns, and settlement metrics

* test(canvas): cover live tiled blur settlement

- Load gold-preview.fig through the real tiled canvas surface and wait on explicit renderer settlement
- Commit the settled radius-210 large-blur browser snapshot
- Replay the canonical zoom reversal during refresh and require byte-identical final canvas convergence

* fix(canvas): harden renderer resource lifecycle

- Release tiled surfaces, images, pictures, and queued work across surface, font, graph, page, structure, and renderer lifecycle boundaries
- Restore pooled canvas, viewport, and backing state through exception-safe native recording and raster paths
- Rebuild tiled chunk topology only when isolation requirements actually change, preserving selective blur mutation performance
- Document deterministic active-renderer settlement and add lifecycle, graph replacement, cache failure, and surface replacement regressions

* test(canvas): remove source-matching renderer claims

- Delete the autopsy suite that inferred runtime correctness from source text, regexes, line placement, and symbol counts
- Keep renderer ordering, cache cleanup, effect behavior, and pixel fidelity covered by executable behavioral and lifecycle tests

* perf(canvas): present retained backing during tiled navigation

- Profile production reversal traces and attribute tiled p95 cost to GPU command-buffer flushes from full-scene fallback replay and tile presentation
- Use the retained backing as the moving fallback while tile scheduling and cached lookup remain allocation-free
- Defer tile image presentation until idle and expose visible versus presented tile counts in navigation telemetry
- Reduce tiled reversal render p95 from about 8ms to 0.3ms while preserving exact idle replacement and visual parity

* perf(canvas): prioritize visible tile settlement

- Profile per-tile allocation, draw, flush, snapshot, and chunk costs through scheduler telemetry
- Defer overscan until all visible exact tiles are covered
- Replace the four-job idle cap with a higher safety ceiling while the measured five-millisecond deadline controls cheap work
- Reduce mutation-plus-reversal exact settlement from about 272ms to 160ms without Long Tasks, overruns, or over-budget jobs

* refactor(canvas): clarify renderer lifecycle boundaries

- Extract retained backing state types and navigation preview timing\n- Isolate tiled scheduler telemetry from frame orchestration\n- Document settlement and CanvasKit ownership invariants\n- Preserve hot drawing loops, budgets, cache limits, and rendering decisions

* fix(canvas): preserve current label rendering

Retain the merged paragraph-label cache lifecycle and substituted-font readiness while reconstructing the renderer stack on current master.

* test(canvas): keep tile benchmark assertions deterministic

Keep performance timing in benchmark telemetry while asserting structural tile selectivity and cache behavior in CI.

* feat(canvas): expose experimental tiled rendering

- Persist retained or tiled canvas mode in General settings\n- Keep retained rendering as the default and apply changes after reload\n- Preserve URL overrides for deterministic benchmarks and support reproduction

* refactor(app): centralize renderer preference state

Expose renderer override provenance from runtime configuration and keep the settings control's derived state separate from its explicit persistence action.

* refactor(app): share settings layout anatomy

Reuse slot-based section headers and bordered groups while keeping each settings control row explicit.

* fix(canvas): harden tiled renderer boundaries

- Bound low-zoom tile planning and handle failed tile surface allocation\n- Preserve effect raster dependencies, runtime-safe clocks, and navigation timing contracts\n- Keep benchmarks deterministic, backward compatible, and accurately localized

* fix(canvas): invalidate dependent node pictures

Track first-child shadow dependencies for retained node pictures so child geometry updates cannot leave stale parent shadows.
2026-08-31 13:39:40 +03:00
Danila Poyarkov 35667d84b5
fix(canvas): edit section labels inline (#608)
* fix(canvas): edit section labels inline

- Vertically center shaped section titles using cached paragraph metrics\n- Add generalized canvas-label edit state and a reusable inline label control\n- Match dark and light label presentation while editing and commit renames with undo

* fix(canvas): align label contrast handling

Use shared WCAG contrast selection for rendered and edited canvas labels while retaining exact node-fill presentation in the editing overlay.

* fix(canvas): composite translucent label colors

Choose label foreground contrast after compositing translucent section fills against the active canvas background.
2026-08-30 22:24:08 +03:00
Danila Poyarkov 0f64cecc49
fix(text): finalize font readiness and label shaping (#593)
* fix(text): prepare browser fonts atomically

- Fetch approved Fontsource resources directly in browsers with bounded responses and retryable provider failures
- Limit page font resolution concurrency and retain live Inter substitution paragraphs after baked glyph invalidation
- Shape frame, section, and component labels through a bounded native Paragraph cache
- Cover real Geist, Geist Mono, and Roboto Mono browser loading plus substitution and cache lifecycle behavior

* test(canvas): cover substitution and label shaping

- Capture baked missing-font text before editing, live Inter substitution on first input, and visible undo output
- Assert text-picture and derived-glyph invalidation with finalized substituted readiness
- Cover shaped frame, rotated frame, section, component, component-set, ellipsis, kerning, and zoom label presentation

* fix(text): preserve same-origin fetches during font resolution

- Route same-origin application and fixture requests through native fetch while Unifont temporarily proxies global HTTP requests
- Keep the external provider HTTPS allowlist enforced for cross-origin font resources
- Cover the production race discovered while loading gold-preview.fig during provider initialization

* fix(text): preserve substituted path glyphs

- Keep imported derived curved glyphs for text-on-path layers when exact fonts finalize as substituted
- Cover substituted path rendering through the runtime renderer and refresh the corrected visual oracle
- Update shaped Inter measurement badges and merged typography panel snapshots after visual inspection
- Search virtualized font catalogs explicitly and restore the canvas screenshot helper used by broad E2E coverage

* fix(text): use browser font transport without desktop warning

- Keep the browser provider implementation aligned with current settings behavior after splitting from preparation

* test(text): inject same-origin browser font context

- Keep the transport test deterministic outside a Window global

* fix(text): preserve final browser font transport hardening

- Carry the same-origin large-document bypass and bounded cross-origin provider checks from the preserved integration snapshot

* fix(text): initialize font transport outside Window contexts

- Keep unit and headless module imports safe while browsers use their current origin

* test(text): satisfy async visual fixture contract

- Return from the resolver setup continuation after requesting render

* test(canvas): include paragraph cache lifecycle

* fix(text): cancel queued browser font loads

- Race serialized provider work against preparation cancellation\n- Release queue slots after cancelled waiters without disturbing active requests\n- Reuse one section-title paragraph cache entry for measurement and drawing

* fix(text): close font queue cancellation races

- Release reserved proxy queue slots when cancellation lands after queue acquisition\n- Skip paragraph work for zero-width section labels

* fix(text): abort active provider resolution

- Race active provider resolution against its preparation signal and restore the temporary fetch proxy promptly\n- Forward cancellation through proxied provider requests\n- Align the renderer font-readiness facade with substituted text
2026-08-30 14:33:32 +03:00
Danila Poyarkov 6f5638380a
feat(app): prepare documents atomically per tab (#592)
* feat(app): show atomic document loading progress

- Preserve the existing full-canvas pencil loader while adding phase, detail, accessible status, and honest determinate progress
- Keep one generation-safe load owner across FIG decoding, graph preparation, page population, fonts, fallbacks, layout, viewport fitting, and first-render fade
- Prevent nested page setup and viewport cleanup from revealing partially prepared documents
- Cover obsolete sessions, font-resolution ownership, and staged loader UI

* refactor(app): scope editor preparation per tab

- Replace the shared loading boolean with one reactive preparation snapshot and one imperative controller per editor store
- Keep Core page work progress-only and inject canvas suspension from the app boundary
- Route FIG, storage, recovery, DOM import, and page switching through reusable tab-local preparation handles
- Abort only the closing tab's operation and cover generation safety, multi-tab isolation, progress UI, and disposal

* fix(editor): commit prepared pages atomically

- Prepare population, fonts, fallbacks, and layout without changing the visible page
- Reject cancelled and stale prepared pages before committing viewport, selection, and page events
- Keep the preparation overlay until the committed scene version is presented
- Cover call order, cancellation, stale generations, and presentation acknowledgement

* fix(app): stage imported documents before commit

- Prepare imported graphs in an isolated Core editor before replacing the live document
- Share font loading while keeping live selection, graph, renderers, and history untouched during staging
- Preserve the previous graph when staging is cancelled or fails and remove the duplicate pre-font layout pass

* refactor(app): namespace preparation UI

- Move canvas and tab preparation presentations into focused subfolders with concise component names
- Share progress and phase presentation helpers across preparation surfaces
- Show tab-local preparation status without covering the active canvas for background work

* fix(app): cancel preparation work at source

- Publish typed per-store preparation lifecycle events with explicit completion, cancellation, and failure outcomes
- Propagate tab-local AbortSignals through FIG parsing, population workers, and browser font downloads
- Keep cancellable font requests outside shared in-flight caches while retaining globally completed font registrations
- Stop FIG manifest previews from replacing the live graph before atomic document commit

* fix(app): cancel storage and DOM preparation

- Propagate preparation signals through S3 downloads, byte progress, local-cache boundaries, and DOM/CSS conversion checkpoints
- Reuse merged diagnostics and localized toasts for document, storage, and presentation failures
- Replace manual font concurrency and presentation timers with es-toolkit limitAsync and withTimeout
- Guard stalled first presentation and fix the merged recovery dialog title bindings

* fix(app): stage reload and font retry

- Prepare reload graphs in isolation and preserve the current document on read, decode, font, or layout failure
- Restore page and viewport state only after atomic graph commit with cancellable reload reads
- Run font Retry as a tab-local preparation with cache reset, final layout, picture invalidation, and presentation acknowledgement
- Keep completed document pixels visible while Retry reports activity in the tab

* fix(app): enforce exclusive preparation outcomes

- Complete document, storage, recovery, and DOM preparations only after successful commit
- Keep failed and cancelled handles terminal so lifecycle events cannot report contradictory outcomes
- Preserve external AbortError identity across storage timeouts and cancel streamed readers without returning partial bytes
- Cover credential-free pre-abort, mid-stream cancellation, progress cutoff, and terminal outcome exclusivity

* feat(diagnostics): record preparation outcomes

- Persist completed, cancelled, and failed preparation lifecycles through the validated diagnostics recorder
- Store only operation kind, outcome, cancellation or failure category, terminal phase, and coarse duration bucket
- Exclude document subjects, font families, storage identities, URLs, raw durations, messages, and stack traces

* chore(app): keep browser font tests with typography split

- Remove the browser font transport test inherited from a mixed cancellation commit; the source and coverage remain on the typography branch and safety snapshot

* test(vue): assert injected render suspension

- Exercise shouldSuspendRender instead of removed Core loading state\n- Preserve the contract that rendering resumes without a version change

* test(app): complete atomic preparation contracts

- Acknowledge first presentation in headless file-open tests\n- Assert the cancellable font-loading signature at the Tauri fallback boundary

* fix(app): preserve preparation cancellation

- Stage imported graphs before mutating live tabs and propagate aborts through page, DOM, font, and storage work\n- Use the accessible progress primitive and clamp determinate values\n- Cover fallback-font cancellation and yield pending-open test polling to the task queue

* test(text): await fallback font request cancellation

Start the mocked remote font request before aborting so the test proves that the active request receives the preparation signal.
2026-08-30 12:21:49 +03:00
PAVEL TKACHEV d178a7fd70
feat(app): add language picker to General settings
* feat(app): add language picker to General settings

- Reuse the persisted locale setting in General settings
- Localize the setting description across supported languages
- Cover immediate switching and reload persistence

* test(app): verify persisted language selection

---------

Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-08-29 16:01:03 +03:00
Danila Poyarkov 8408b56721
refactor(app): modernize browser clipboard adapter (#601)
* refactor(app): isolate system clipboard adapters

- Split browser and Tauri clipboard behavior into focused adapters\n- Inject browser clipboard capabilities into unit-testable operations\n- Remove navigator and document mutation from headless clipboard tests

* refactor(app): delegate browser clipboard fallbacks

- Use copy-to-clipboard for modern rich MIME writes and execCommand fallback\n- Keep OpenPencil-specific HTML and plain-text payload construction at the adapter boundary\n- Remove hand-rolled browser capability and selection handling

* test(clipboard): verify rich browser menu round-trip

- Exercise copy from the browser Edit menu under a user gesture\n- Verify text/html and text/plain ClipboardItem formats\n- Paste the system clipboard payload back into the canvas

* refactor(clipboard): reduce adapter surface

- Expose only command dispatch and the injectable system clipboard contract\n- Keep browser and Tauri copy/paste operations private to their adapters\n- Rename the in-memory DataTransfer fallback and share design HTML recognition

* fix(clipboard): harden format and fallback handling

- Require complete OpenPencil or Figma clipboard markers\n- Await browser writes so adapter failures resolve false\n- Write plain-only Tauri payloads as text and reject unrelated clipboard text

* fix(clipboard): reject unrelated current browser data

* fix(clipboard): bind fallbacks to copied selection

- Match cached rich HTML to the current Tauri plain-text fallback\n- Preserve nodes when selection changes during an asynchronous cut\n- Reject unrelated current browser HTML before consulting memory

* fix(clipboard): reuse the shared memory payload type

* fix(clipboard): scan design markers linearly

* fix(clipboard): distinguish unavailable and empty reads

* style(clipboard): use includes for marker closure

* test(clipboard): avoid wall-clock marker assertions
2026-08-28 14:37:42 +03:00