ReviewOS

also looking at this

craft-native/craft

fix(native): retain keyed controls and correct map and tab chrome

#368
Merged chris wants to merge codex/native-repeated-selector-identity into main
32 files +449 -100

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/android/templates/MainActivityNative.kt.templatemodified+4-1
Changes to packages/android/templates/MainActivityNative.kt.template
@@ -4935,8 +4935,11 @@ class MainActivity : AppCompatActivity() {
49354935 val explicitKey = authoredKey(node, props)
49364936 // Descendants are scoped to this retained identity, not its sibling
49374937 // position. Moving a keyed parent must retain its nested inputs too.
4938 // A test selector may intentionally identify several list rows. The
4939 // compiler's unique protocol ID must win over that legacy fallback.
49384940 val identity = explicitKey?.let { "${path.substringBeforeLast('.', "")}/$it" }
49394941 ?: protocolId?.let { "id:$it" }
4942 ?: props.optString("testID").takeIf { it.isNotBlank() }?.let { "${path.substringBeforeLast('.', "")}/$it" }
49404943 ?: path
49414944 val previous = previousControls[identity]
49424945 val reusableInput = previous as? EditText
@@ -5822,7 +5825,7 @@ class MainActivity : AppCompatActivity() {
58225825 }
58235826
58245827 private fun authoredKey(node: JSONObject, props: JSONObject): String? {
5825 val direct = listOf(node.optString("key"), props.optString("key"), props.optString("testID"))
5828 val direct = listOf(node.optString("key"), props.optString("key"))
58265829 .firstOrNull { it.isNotBlank() }
58275830 if (direct != null) return direct
58285831 return null