The undo command surface rebuilds — app-owned rows and explicit toolbar targets over FocusedValues
Edit ▸ Undo/Redo become the app's own replaced rows and the board toolbar pair takes explicit targets, both reading the focused session's BoardUndoManager through FocusedValues.undoStack (board windows publish the session's manager, card windows their own) — the nil-target route died with the SwiftUI window latch, 13-native-undo.md ▸ Rules ▸ command surface, re-ruled 2026-08-08. The rows enact the routing predicate themselves: text focus routes ⌘Z to the first responder's own manager, title and enablement included, re-derived at fire time with a beep for the stale window. NativeHistoryProvider turns @Observable so both surfaces re-derive on stack changes; a checkpoint-notification ticker covers plain text managers. .responderAction leaves ToolbarItemSpec with its only user; windowWillReturnUndoManager stays wired for AppKit's own asks. Live-probed on the fixture board (21/21): the row retitles to "Undo Add Lane" and crosses via real ⌘Z key events, ⇧⌘Z redoes via a window-server chord, the toolbar pair validates and fires, search-field and body-editor ⌘Z stay text undo with board stacks untouched, and a card window crosses its own stack with no fall-through. 2698 unit tests green. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -279,8 +279,10 @@ public struct HistoryStep {
|
||||
/// the seam is real", 12 — written when native undo was the free tier's; the proof it named was
|
||||
/// two working substrates, which the pivot left standing and the 2026-08-08 excision then narrowed
|
||||
/// back to one, `strategy/01-git-excision.md` — the seam itself is what stays proved either way).
|
||||
/// AppKit still needs an `UndoManager` to hand the responder chain; that adapter is
|
||||
/// `BoardUndoManager`, which sits *over* this protocol rather than inside it.
|
||||
/// The command surface still speaks `UndoManager` — the menu rows, the toolbar pair and AppKit's
|
||||
/// own asks all read one (13-native-undo.md ▸ Rules ▸ the command-surface bullet, re-ruled
|
||||
/// 2026-08-08); that adapter is `BoardUndoManager`, which sits *over* this protocol rather than
|
||||
/// inside it.
|
||||
/// - **No persistence promise.** The native stack dies with the session (13); a git provider's once
|
||||
/// survived relaunch because git does, before app-managed git was excised entirely (2026-08-08,
|
||||
/// `strategy/01-git-excision.md`). Both were honest implementations of these seven members; only
|
||||
@@ -326,7 +328,9 @@ public protocol HistoryProviding: AnyObject {
|
||||
func register(_ step: HistoryStep)
|
||||
|
||||
/// Whether there is a step to cross. What the Edit menu's Undo row and the toolbar's Undo item
|
||||
/// enable on, through the same responder-chain answer.
|
||||
/// enable on — both of them through one `BoardUndoManager` over this seam, which is what keeps
|
||||
/// the two surfaces from being two answers (13-native-undo.md ▸ Rules ▸ the command-surface
|
||||
/// bullet, re-ruled 2026-08-08).
|
||||
var canUndo: Bool { get }
|
||||
|
||||
var canRedo: Bool { get }
|
||||
|
||||
Reference in New Issue
Block a user