What's new
-
Diff loading spinner + honest failure states (#16): selecting a file/commit/stash no longer shows a blank pane (or a misleading "Select a file to view changes") while the diff loads. Loads still in flight after a 200ms grace period show a centered spinner in all three diff panes; a load that actually fails now shows "Couldn't load diff" instead of an eternal blank. Commit/stash diff loads are now cancellable, so rapid selection can't let a stale load clobber the newer one's diff.
-
Observation granularity overhaul (#16):
GitWorkbenchStore's UI state is now per-field@Observablestored properties (repo,commits,commitMessage,toast, …) instead of one monolithicstateproperty, so views re-evaluate only when fields they actually read change — a commit-message keystroke no longer re-derives the rail's branch trees, and dragging the History message divider no longer re-renders the whole window (ColumnLayoutis@Observabletoo).store.stateremains as a full snapshot for tests and headless hosts. Hot paths hardened alongside: split-diff rows and max line width derive once per diff (not per horizontal scroll tick), branch trees build in a value-diffable child, rows take selection as a value, and images/PDFs decode asynchronously — re-decoding when the bytes change, so an external edit to the viewed file refreshes the pane. -
Keyboard & VoiceOver accessibility (#16): file/commit/stash rows are real buttons; the stage box reads as a checkbox ("Staged, on/off"); icon-only segmented controls (unified/split, swipe axis) are labeled and expose selection; confirm cards answer Esc (cancel) and Return (confirm); the Staged/Changes collapse chevrons are labeled; the new-branch/tag name field takes focus declaratively; rail branch rows expose "Switch to / Check out this branch" as named accessibility actions.
Fixes
- Toasts now fade in and out (the transition previously never animated).
- History ref pills are keyed by the ref itself rather than list position, eliminating a class of stale-render risk when a commit's refs change in place.
For hosts
All API changes are additive: the granular store properties, isLoadingDiff / didFailDiffLoad, bindable commitMessage / diffMode / pendingRefName, and SegmentedOption.accessibilityLabel. store.state and WorkbenchState are unchanged — but reading store.state in a SwiftUI body now observes every field; prefer the granular properties in view code.
Zero new third-party dependencies; Swift 6 language mode preserved. 238 tests (was 233).
Full Changelog: 1.6.0...1.7.0