ReviewOS

also looking at this

craft-native/craft

fix(mobile): preserve native editing, navigation, and durable media requests

#369
Merged chris wants to merge codex/native-vertical-scroll-tab-swipes into main
36 files +864 -185

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/src/grid-rows.test.tsmodified+25-0
Changes to packages/android/src/grid-rows.test.ts
@@ -34,3 +34,28 @@ fun main() {
3434}
3535`)
3636}, 180_000)
37
38
39test('encodes shared grid counts as the unsigned integer fields in the native ABI', async () => {
40 const template = await Bun.file(new URL('../templates/MainActivityNative.kt.template', import.meta.url)).text()
41 const columns = template.match(/^[^\n]*put(?:Enum)?\(base, 29, node\.gridColumns[^\n]*$/m)?.[0]
42 const rows = template.match(/^[^\n]*if \(explicitRowsAware\) put(?:Enum)?\(base, 34, [^\n]*$/m)?.[0]
43 if (!columns || !rows) throw new Error('Shared grid count serialization is missing')
44 await runKotlinFixture(`
45data class GridNode(val gridColumns: Int, val gridRows: Int?)
46
47fun main() {
48 val base = 0
49 val node = GridNode(2, 3)
50 val explicitRowsAware = true
51 val nodeData = FloatArray(35) { Float.NaN }
52 fun put(base: Int, index: Int, value: Float) { nodeData[base + index] = value }
53 fun putEnum(base: Int, index: Int, value: Int) { put(base, index, Float.fromBits(value)) }
54${columns}
55${rows}
56 check(nodeData[29].toRawBits() == 2) { "grid_columns is not encoded as u32" }
57 check(nodeData[34].toRawBits() == 3) { "grid_rows is not encoded as u32" }
58 println("PASS native grid counts retain the integer bit patterns consumed by Zig")
59}
60`)
61}, 180_000)
packages/android/templates/MainActivityNative.kt.templatemodified+2-2
Changes to packages/android/templates/MainActivityNative.kt.template
@@ -1432,12 +1432,12 @@ internal class CraftNativeFlexLayout(context: Context) : LinearLayout(context) {
14321432 put(base, 26, node.padding[3].toFloat())
14331433 put(base, 27, node.padding[0].toFloat())
14341434 putEnum(base, 28, if (node.grid) 1 else 0)
1435 put(base, 29, node.gridColumns.toFloat())
1435 putEnum(base, 29, node.gridColumns)
14361436 put(base, 30, node.rowGap)
14371437 put(base, 31, node.columnGap)
14381438 if (fields >= 33) putEnum(base, 32, (if (node.reverse) 1 else 0) or (if (node.wrapReverse) 2 else 0))
14391439 if (autoRowsAware) put(base, 33, sharedLength(node.gridAutoRows, contentHeight))
1440 if (explicitRowsAware) put(base, 34, (node.gridRows ?: 0).toFloat())
1440 if (explicitRowsAware) putEnum(base, 34, node.gridRows ?: 0)
14411441 val firstChild = cursor
14421442 node.children.forEach { child -> write(child, contentWidth, contentHeight, false, node.direction) }
14431443 treeMeta[index * 2] = firstChild.toFloat()
scripts/native-renderer-contract.test.tsmodified+2-1
Changes to scripts/native-renderer-contract.test.ts
@@ -2070,7 +2070,8 @@ describe('native renderer component contract', () => {
20702070 expect(android).toContain('private data class SharedTreeResult(')
20712071 expect(android).toContain('grid = nested?.grid ?: false')
20722072 expect(android).toContain('putEnum(base, 28, if (node.grid) 1 else 0)')
2073 expect(android).toContain('put(base, 29, node.gridColumns.toFloat())')
2073 expect(android).toContain('putEnum(base, 29, node.gridColumns)')
2074 expect(android).toContain('if (explicitRowsAware) putEnum(base, 34, node.gridRows ?: 0)')
20742075 expect(android).toContain('CraftNative.layoutTree(width.toFloat(), height.toFloat(), nodeData, treeMeta)')
20752076 expect(android).toContain('CraftNative.layoutTreeV2(width.toFloat(), height.toFloat(), nodeData, treeMeta)')
20762077 expect(android).toContain('CraftNative.layoutTreeV3(width.toFloat(), height.toFloat(), nodeData, treeMeta)')