Skip to content

apple: keep textarea borderless + e2e fixes (semantics refresh, autofocus edge, hoisted toolbar id) - #52

Merged
tiensonqin merged 10 commits into
mainfrom
devin/1790338562-textarea-borderless
Sep 26, 2026
Merged

tiensonqin merged 10 commits into
mainfrom
devin/1790338562-textarea-borderless

Conversation

@tiensonqin

@tiensonqin tiensonqin commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes driving chat's composer/sidebar-restore PR (logseq/chat#24), plus root-cause fixes for both chat e2e failures that were failing on main.

  • Textarea borderless: c90fe35 added .roundedBorder to all non-search text controls, which put an unintended gray ring around the composer textarea. Textareas now keep the borderless design; buttons get explicit 44x44 sizing in the app (the iOS 44pt default-height removal was intentional).
  • Column press support: with_press/press-enabled was silently dropped for column — the protocol never allowed it, so the composer's tap-to-focus was a no-op. Adds PressEnabled + PressEvent to the column matrix and implements press handling on all four hosts (SwiftUI onTapGesture, Flutter GestureDetector, Qt TapHandler, WinUI Tapped).
  • Flutter: semantics refresh after modal removal (fixes android button.sidebar): markNeedsSemanticsUpdate early-returns on detached RenderObjects, so removing a modal route's overlay entries never re-dirtied any semantics ancestor — the platform a11y tree stayed frozen on the stale sheet. _refreshSemanticsAfterModalRemoval now marks the whole render tree dirty across two frames, and _scheduleRouteRemoval refreshes even on the !route.isActive early-return path.
  • Autofocus is edge-triggered (apple + flutter): FocusComposer toggles a flag, so a press while autofocus is already true produces a true→false→true edge. Hosts now treat any transition as a focus request instead of only false→true.
  • Apple: hoisted toolbar identifier (fixes ios toolbar.outliner.editor): a placement-hoisted toolbar renders via a zero-size Color.clear carrier, so its accessibility_identifier never reached the a11y tree (all button.outliner.editor.* buttons were present, the container id was not). The identifier is now carried on the first emitted ToolbarItem's content.

Link to Devin session: https://app.devin.ai/sessions/eab2eca00a5649d09fcf48626d9f09ef
Open in Devin Desktop: https://app.devin.ai/desktop/session/eab2eca00a5649d09fcf48626d9f09ef?variant=devin
Requested by: @tiensonqin

c90fe35 applied .roundedBorder to every non-search text control, which
puts a ~1px outlined box around multi-line textareas that used to sit
bare on their host card (e.g. chat composer-input). Textareas keep the
default borderless style; single-line fields keep the native chrome.
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

Lands the deferred Flutter parity for bd0c92c — the generated schema
gained _NodeKind.menuTrigger but the backend never handled it, so the
exhaustive switch in _buildNode failed to compile (surfaced by the
chat Android e2e build).

- menuTrigger() renders a MenuAnchor with a TextButton label
  (icon + text, accessibility label, enabled, foreground)
- dropdown-menu children may be menu-trigger (nested submenus);
  menu-trigger accepts only a dropdown-menu child
- text/enabled/foreground/icon/accessibility-label allowed on the kind;
  toolbar children and _canContainChildren include it
@devin-ai-integration devin-ai-integration Bot changed the title apple: keep textarea borderless apple: borderless textarea + flutter menuTrigger render Sep 25, 2026
with_press on a column previously emitted nothing on any platform:
the OCaml property/event matrices (and each backend's mirror) rejected
press-enabled for containers, so container-level taps were silently
dropped. Admit column so apps can wire container tap actions (e.g.
tap-to-focus).

- OCaml: property_supported PressEnabled + event_supported Press
- Apple: supports gate, performPress guard, LUIColumnView tap gesture
- Flutter: _supports, performAction pressable, column GestureDetector
- Qt: schema property/event arms, performPress, LuiColumn tap layer
- WinUI: CommonPropertySupported/EventSupported, PerformAction pressable
A detached RenderObject's markNeedsSemanticsUpdate is a no-op (!attached
early-returns), so removing a modal route leaves its semantics node linked
under a parent that is never re-dirtied and the platform a11y tree freezes
on the last emit — which still contains the sheet — hiding the new screen
from assistive tech (observed as android e2e button.sidebar assert
failing while the UI is visibly on the chat screen).

Refresh by marking every render object in the tree dirty across two
consecutive frames, covering both the removeRoute path and detaches that
land a frame later; also refresh when the route was already inactive.
onChange previously only focused on false->true edges, so a second focus
request while the flag already read true (field unfocused) produced no
edge and never refocused. Any transition now requests focus, which pairs
with producers pulsing the flag to force an edge.
The autofocus prop only reached TextField at build time, so later
transitions never moved focus. Pass the node handle's FocusNode into
_LUITextInput and requestFocus on any autofocus change, matching the
edge-triggered focus-request semantics.
A placement-hoisted toolbar renders through a zero-size Color.clear
carrier, so its accessibility identifier never reached the a11y tree —
iOS e2e's toolbar.outliner.editor assert failed while every toolbar
button was present. Apply the identifier to the first emitted
ToolbarItem's content (the fused capsule, or the first bare item).
@devin-ai-integration devin-ai-integration Bot changed the title apple: borderless textarea + flutter menuTrigger render apple: keep textarea borderless + e2e fixes (semantics refresh, autofocus edge, hoisted toolbar id) Sep 25, 2026
Two frames is not enough — a sheet's exit animation detaches its
overlay entries ~15 frames after removal is scheduled, so marks made
that early flush while the sheet is still attached and the a11y tree
freezes again at detach. Mark every frame for ~750ms.
…area-borderless

# Conflicts:
#	platform/apple/Sources/LUIAppleBackend/LUISwiftUIRoot.swift
#	platform/flutter/lib/lui_flutter_backend.dart
@tiensonqin
tiensonqin merged commit d2b3b07 into main Sep 26, 2026
4 checks passed
@tiensonqin
tiensonqin deleted the devin/1790338562-textarea-borderless branch September 26, 2026 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant