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
packages/android/src/grid-rows.test.tsmodified+56-0
Changes to packages/android/src/grid-rows.test.ts
@@ -2,6 +2,34 @@
22import { test } from 'bun:test'
33import { runKotlinFixture } from './testing'
44
5test('snaps authored padding to the nearest physical pixel at fractional density', async () => {
6 const template = await Bun.file(new URL('../templates/MainActivityNative.kt.template', import.meta.url)).text()
7 const padding = template.match(/internal fun craftNativePadding\([^]*?\n\}/)?.[0]
8 const number = template.match(/private fun craftNativeNumber\([^]*?\n \?\.takeIf \{ it\.isFinite\(\) \}/)?.[0]
9 if (!padding || !number) throw new Error('Native padding normalization is missing')
10 await runKotlinFixture(`
11import kotlin.math.roundToInt
12
13class JSONObject(private val values: Map<String, Any?>) {
14 fun opt(name: String): Any? = values[name]
15}
16${number}
17${padding}
18
19fun main() {
20 val density = 2.625f
21 check(craftNativePadding(JSONObject(mapOf("padding" to 4)), "padding", 0, density) == 11)
22 check(craftNativePadding(JSONObject(mapOf("padding" to 8)), "padding", 0, density) == 21)
23 check(craftNativePadding(JSONObject(mapOf("padding" to 4)), "padding", 0, 1f) == 4)
24 for (invalid in listOf(null, -1, Double.NaN, Double.POSITIVE_INFINITY, true, "4")) {
25 check(craftNativePadding(JSONObject(mapOf("padding" to invalid)), "padding", 7, density) == 7)
26 }
27 check(craftNativePadding(null, "padding", 7, density) == 7)
28 println("PASS native padding rounds once to the nearest physical pixel and retains invalid-value defaults")
29}
30`)
31}, 180_000)
32
533test('sizes occupied and empty explicit grid rows after padding and fractional gaps', async () => {
634 const template = await Bun.file(new URL('../templates/MainActivityNative.kt.template', import.meta.url)).text()
735 const allocation = template.match(/ val rowHeights = if \(gridRows != null\) \{[\s\S]*?\n \} else naturalRowHeights/)?.[0]
@@ -34,3 +62,31 @@ fun main() {
3462}
3563`)
3664}, 180_000)
65
66
67test('encodes shared grid counts as the unsigned integer fields in the native ABI', async () => {
68 const template = await Bun.file(new URL('../templates/MainActivityNative.kt.template', import.meta.url)).text()
69 const columns = template.match(/^[^\n]*put(?:Enum)?\(base, 29, node\.gridColumns[^\n]*$/m)?.[0]
70 const rows = template.match(/^[^\n]*if \(explicitRowsAware\) put(?:Enum)?\(base, 34, [^\n]*$/m)?.[0]
71 const directColumns = template.match(/^[^\n]*put(?:Enum)?\(base, 29, 1f?\)[^\n]*$/m)?.[0]
72 if (!columns || !rows || !directColumns) throw new Error('Shared grid count serialization is missing')
73 await runKotlinFixture(`
74data class GridNode(val gridColumns: Int, val gridRows: Int?)
75
76fun main() {
77 val base = 0
78 val node = GridNode(2, 3)
79 val explicitRowsAware = true
80 val nodeData = FloatArray(35) { Float.NaN }
81 fun put(base: Int, index: Int, value: Float) { nodeData[base + index] = value }
82 fun putEnum(base: Int, index: Int, value: Int) { put(base, index, Float.fromBits(value)) }
83${columns}
84${rows}
85 check(nodeData[29].toRawBits() == 2) { "grid_columns is not encoded as u32" }
86 check(nodeData[34].toRawBits() == 3) { "grid_rows is not encoded as u32" }
87${directColumns}
88 check(nodeData[29].toRawBits() == 1) { "direct layout grid_columns default is not encoded as u32" }
89 println("PASS native grid counts retain the integer bit patterns consumed by Zig")
90}
91`)
92}, 180_000)