Fix native toolbar to reflect formatting state after kill/resume#1024
Draft
samuelpecher wants to merge 2 commits into
Draft
Fix native toolbar to reflect formatting state after kill/resume#1024samuelpecher wants to merge 2 commits into
samuelpecher wants to merge 2 commits into
Conversation
NativeAdapter would not dispatch attributes consistently on editor load/reset and editor operations, leaving the toolbar out of sync. This streamlines the attributes code between the native and browser bar, both pulling all format information from Selection.getFormat, which itself has been streamlined and ligned. The toolbars will now correctly report status for non-RangeSelections, namely that all attributes are disabled. - Initialize currentlyFocused with focus listeners so that an inconsistent state is not kept on reset - Move attributes calcs into NativeAdapter so that the BrowserAdapter is a true noop - Simplify toolbar refresh code - Deduplicate selection guards - Boolean() isPressed for undefined-safety
ed55392 to
8cf2e30
Compare
Splits coverage along the seam where the test belongs: - vitest (`test/javascript/native/`): adapter lifecycle, registration, dispatch shape, freeze/thaw — anything that can be asserted without exercising real Lexical selection behavior. Shared `helpers/attributes_capture.js` hard-codes the public contract (10 attribute keys, top-level link/highlight/headingTag, type invariants per field) and throws on every violation. - playwright (`test/browser/tests/native/`): everything that needs a real Lexical instance — format toggles, format detail correctness (link.href, highlight color, heading.tag), multi-format spans, selection-driven dispatch, history. Shared `helpers/native_capture.js` registers a real NativeAdapter (exposed on `window.LexxyNativeAdapter` from the fixture) and asserts the same contract. Removes three vitest files (`adapter_registration`, `attributes_change`, `selection_freeze`) whose coverage is redistributed across the new files.
8cf2e30 to
7e5304a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes Basecamp card #9828466892 — on iOS/Android, after the host app is killed and the composer reopened, the native toolbar buttons (bold, italic, etc.) no longer reflected the active formatting state.
Two compounding root causes:
#resetleftcurrentlyFocusedset totrueacross disconnect/reconnect, so the nextfocusinshort-circuited at the!this.currentlyFocusedguard and never re-synced the toolbar.attributes-changeran synchronously against an editor whose state hadn't settled (noRangeSelectionyet, or a stale post-setContentselection), so iOS cached an empty/wrong payload.The fix:
dispatchAttributesChange(attributesFn: () => Attributes)—BrowserAdapterdoesn't call the closure (free);NativeAdaptercalls it, merges with module-levelDEFAULT_ATTRIBUTES, and dispatches thelexxy:attributes-changeevent.RangeSelection, the editor returns{}and the adapter merges it withDEFAULT_ATTRIBUTES— native consumers always receive a renderable payload from the first event onward.currentlyFocusedis reset in#registerFocusEvents(close to the focus-tracking logic) on every connect.Public contract change for native consumers
The
lexxy:attributes-changeevent detail now carriesheadingTag(string"h2"/"h3"/"h4"ornull) at top-level and atattributes.heading.active. Both fields hold the same value — top-levelheadingTagis preserved for backward compat with consumers who read it there. New consumers can read either;attributes.heading.activeis the canonical internal location.Test plan
test/javascript/native/state_restoration.test.js) fails onmain, passes on this branch.test/browser/tests/formatting/toolbar_active_state.test.js).