Skip to content

fix(binding): resolve elements by semantics identifier and non-String keys - #62

Open
charliewwdev wants to merge 2 commits into
mainfrom
fix/semantics-and-editable-text-targeting
Open

fix(binding): resolve elements by semantics identifier and non-String keys#62
charliewwdev wants to merge 2 commits into
mainfrom
fix/semantics-and-editable-text-targeting

Conversation

@charliewwdev

Copy link
Copy Markdown
Member

Fixes problem 3 of #52.

Summary

_findElementByKey matched ValueKey<String> and nothing else, so two common shapes were unaddressable:

  • Design-system fields. They wrap the inner editable in a private GlobalKey and expose only Semantics(identifier: ...). An agent had no handle on them — the report notes that only the "focus the field, then send an empty key" fallback worked.
  • Non-String keys. ValueKey<int>, enum-valued keys, etc. never matched at all.

Approach

Candidates are collected in tiers and the first non-empty tier wins:

  1. widget key (ValueKey of any type, compared by string form)
  2. Semantics.identifier
  3. Semantics.label

Ordering matters: a label is human-readable text that can easily collide with an unrelated widget's key, so a real key must beat a semantics annotation. Within a tier, the topmost-route preference added in #53 still applies.

Widening to ValueKey of any type is a superset of the old behaviour — ValueKey<String> resolves exactly as before.

enter_text needed no change: _findEditableText already descends from the matched element to the nearest EditableText, which is precisely what makes a matched Semantics wrapper usable. The new test pins that descent so it cannot regress.

Flutter version floor

Bumped environment.flutter to >=3.19.0 — verified via git tag --contains on flutter/flutter#138331 that 3.19.0 is the first release containing SemanticsProperties.identifier. The previous >=3.0.0 was already inaccurate: WidgetsBinding.rootElement needs 3.9.

Test plan

New test/element_lookup_test.dart (7 widget tests):

  • ValueKey<String> still resolves (no regression)
  • ValueKey<int>(42) resolves via '42'
  • Semantics(identifier: 'email_field') wrapping a TextField resolves, and an EditableText is reachable below the match
  • Semantics(label:) resolves
  • A widget key beats a colliding semantics label
  • Topmost route wins when the same key exists on a background and a pushed route
  • Unknown key returns null
  • Not vacuous: 3 of 7 fail against the old matching logic (int key, semantics identifier, semantics label); 7/7 pass with the fix
  • flutter analyze lib/flutter_skill.dart test/element_lookup_test.dart — no issues

findElementByKeyForTesting is added as a @visibleForTesting wrapper so the tie-breaking rules can be pinned without exposing the finder publicly.

🤖 Generated with Claude Code

… keys

Lookup by key only matched ValueKey<String>, which left common widgets
unreachable (issue #52, problem 3). Design-system fields wrap their inner
editable in a private GlobalKey and expose nothing but
Semantics(identifier: ...), so an agent had no handle on them at all —
only the "focus the field first, then send an empty key" trick worked.
Keys built from ints or enums never matched either.

Collect candidates in tiers — widget key, then semantics identifier, then
semantics label — and return the first non-empty tier. A real key has to
win over a semantics annotation because a label is human-readable text
that can collide with an unrelated widget's key. Within a tier the
existing topmost-route preference still applies.

Widening to `ValueKey` of any type is a superset of the old behaviour:
the value is compared by its string form, so ValueKey<String> resolves
exactly as before.

enter_text needs no change — it already descends from the matched element
to the nearest EditableText, which is what makes a matched Semantics
wrapper usable.

Bumps the declared Flutter floor to 3.19, the first release with
SemanticsProperties.identifier. The previous ">=3.0.0" was already
inaccurate; WidgetsBinding.rootElement needs 3.9.
Correcting the previous commit: 3.19 covers SemanticsProperties.identifier
but not Color.withValues at lib/flutter_skill.dart:4552, which landed in
3.27. Verified by grepping the flutter/flutter tags — absent in 3.24.0,
present in 3.27.0.

This is also why `dart analyze` has been failing on main: CI pins
FLUTTER_VERSION to 3.24.0, below what the source needs.
@charliewwdev

Copy link
Copy Markdown
Member Author

Correction to the version claim in the description above: the floor is 3.27.0, not 3.19.0.

3.19 covers SemanticsProperties.identifier, but lib/flutter_skill.dart:4552 already uses Color.withValues, which landed in Flutter 3.27. Verified by grepping the flutter/flutter tags — absent in 3.24.0, present in 3.27.0. Pushed as a follow-up commit.

This also explains a pre-existing failure worth flagging separately: dart analyze has been red on main, because .github/workflows/ci.yml pins FLUTTER_VERSION: 3.24.0 — below what the source needs:

error - lib/flutter_skill.dart:4552:12 - The method 'withValues' isn't defined for the type 'Color'.
error - packaging/npm/dart/bin/server.dart:1:8 - Target of URI doesn't exist: 'package:flutter_skill_npm/src/cli/server.dart'.

The second error is fixed by #61. The first needs FLUTTER_VERSION bumped to 3.27.0 in ci.yml (and release.yml), which I could not push — the available token lacks the workflow scope.

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