Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
3fd2932
feat: add React Native UIKit runtime primitives
DjDeveloperr Jun 29, 2026
831d34a
docs: record RN module PR packaging
DjDeveloperr Jun 29, 2026
096b2b8
fix: preserve dynamic native class identity
DjDeveloperr Jun 29, 2026
bd296cd
fix: cache write-only runtime property values
DjDeveloperr Jun 29, 2026
c0acd15
fix: cache unreadable runtime setter values
DjDeveloperr Jun 29, 2026
2b5ec0a
fix: persist UIAppearance proxy setter values
DjDeveloperr Jun 29, 2026
049f9af
fix: guard UIAppearance proxy detection
DjDeveloperr Jun 29, 2026
473788d
fix: tag UIAppearance proxy results
DjDeveloperr Jun 29, 2026
3ad3920
fix: identify UIAppearance proxy fallbacks safely
DjDeveloperr Jun 29, 2026
45c6df6
fix: tag static UIAppearance selector results
DjDeveloperr Jun 29, 2026
cb4fc1a
fix: cache metadata UIAppearance setters
DjDeveloperr Jun 29, 2026
9699fef
fix: cache protocol UIAppearance accessors
DjDeveloperr Jun 29, 2026
c26766e
fix: cache selector group UIAppearance accessors
DjDeveloperr Jun 29, 2026
94df696
fix: dispatch UIAppearance proxy setters via target metadata
DjDeveloperr Jun 29, 2026
2c6bce7
fix: detect UIAppearance targets from exact descriptions
DjDeveloperr Jun 29, 2026
c7454bc
fix: install UIAppearance target prototypes
DjDeveloperr Jun 29, 2026
ac94954
fix: avoid UIAppearance proxy getter hangs
DjDeveloperr Jun 29, 2026
58e5522
fix: limit appearance proxy accessors to UIKit
DjDeveloperr Jun 29, 2026
14caab6
fix: cache appearance values from runtime setters
DjDeveloperr Jun 29, 2026
1b12a71
fix: cache appearance values from host sets
DjDeveloperr Jun 29, 2026
7eae675
fix: prefer writable appearance proxy members
DjDeveloperr Jun 29, 2026
99889cb
fix: stabilize object expando runtime keys
DjDeveloperr Jun 29, 2026
72f1af0
test: expose iOS simulator hangs
DjDeveloperr Jun 29, 2026
d4cae97
fix: bridge indexed collection subclass aliases
DjDeveloperr Jun 29, 2026
197577e
test: trace NSMutableArray native callback
DjDeveloperr Jun 29, 2026
289e52c
test: trace NSMutableArray JS dispatch
DjDeveloperr Jun 29, 2026
c201b4c
fix: dispatch instance base selectors through super
DjDeveloperr Jun 30, 2026
20dbc6b
fix: preserve receiver identity for base initializers
DjDeveloperr Jun 30, 2026
b016ae8
fix: preserve initializer receiver identity
DjDeveloperr Jun 30, 2026
7d7e9d3
fix: persist JS subclass instance fields
DjDeveloperr Jun 30, 2026
1723f06
fix: enumerate JS indexed collection subclasses
DjDeveloperr Jun 30, 2026
7242ea9
test: trace NSMutableArray iOS hang
DjDeveloperr Jun 30, 2026
bd5c264
fix: preserve initializer bridge state
DjDeveloperr Jun 30, 2026
ca53096
fix: construct JS subclasses through remembered init
DjDeveloperr Jun 30, 2026
59a756f
fix: preserve init receiver native identity
DjDeveloperr Jun 30, 2026
3b7a492
fix: guard JS callbacks during subclass init
DjDeveloperr Jun 30, 2026
2295794
fix: prefer JS subclass property accessors
DjDeveloperr Jun 30, 2026
241c994
fix: prefer JS subclass property setters
DjDeveloperr Jun 30, 2026
353e727
fix: invoke JS subclass property setters
DjDeveloperr Jun 30, 2026
3087119
fix: resolve JS subclass registered prototypes
DjDeveloperr Jun 30, 2026
dc038a4
fix: honor V8 native instance prototype accessors
DjDeveloperr Jun 30, 2026
3743381
fix: suppress JS accessor callback reentry
DjDeveloperr Jun 30, 2026
2730d71
docs: update RNS parity progress
DjDeveloperr Jun 30, 2026
1c8c835
fix: gesture delegate dispatch + callback exception debugging
DjDeveloperr Jul 7, 2026
b5fcf6b
fix: worklet capture-order hazards in RN module surface
DjDeveloperr Jul 7, 2026
0310946
perf: kill per-frame host layout loop + crossing profiler
DjDeveloperr Jul 7, 2026
2354bc1
perf: crossing profilers + prologue JSON dedupe verification
DjDeveloperr Jul 7, 2026
635ff1a
docs: measured interop physics + count-driven latency verdict
DjDeveloperr Jul 7, 2026
aa63ac9
perf: per-phase interop call attribution at the bridge choke points
DjDeveloperr Jul 7, 2026
def1d15
docs: attribution round 2 — register memos, host-ready dedupe, curren…
DjDeveloperr Jul 7, 2026
4b10f28
docs: round 3 — exposure-key wall, lane-race warning, refactor is next
DjDeveloperr Jul 8, 2026
a0ba862
feat: adoptHostViewAsControllerView hosting primitive
DjDeveloperr Jul 9, 2026
b7e345a
docs: refactor step 1 landed + environment warning for lane verification
DjDeveloperr Jul 9, 2026
4bf43fa
docs: simdeck-free perf harness + double-walk root cause of push stall
DjDeveloperr Jul 9, 2026
c4f2da7
docs: correct root cause — single manual layout walk, not double; ado…
DjDeveloperr Jul 9, 2026
33bf8d2
docs: two negative results — load-bearing layout walk + per-push comm…
DjDeveloperr Jul 9, 2026
72e26b6
feat: adopted-controller frame ownership (nav controller owns the frame)
DjDeveloperr Jul 9, 2026
14facdc
feat: adoption self-heal + root frame seeding (flag-gated, default OFF)
DjDeveloperr Jul 10, 2026
afa6331
docs: adoption refactor — proven win + size-feedback primitive is the…
DjDeveloperr Jul 10, 2026
673ed80
feat: UIKit->shadow-tree size-feedback primitive for adopted hosts
DjDeveloperr Jul 10, 2026
dfcd4d4
feat: size-feedback only pushes the settled full-height size
DjDeveloperr Jul 10, 2026
95e4e9d
docs: size-feedback primitive built+working; root blocked on first-sc…
DjDeveloperr Jul 10, 2026
023f50e
docs: correct root-cause — prop reaches createController; two remaini…
DjDeveloperr Jul 10, 2026
8902502
docs: discriminating test — root failure is (b) layout-propagation, n…
DjDeveloperr Jul 10, 2026
711831a
feat: worklet-runtime log bridge + adoption pushes stable window size
DjDeveloperr Jul 10, 2026
cd8970e
docs: BREAKTHROUGH — log bridge found the marker bug, root screen ren…
DjDeveloperr Jul 10, 2026
68c342c
docs: correction — content is present + scrollable; adoption function…
DjDeveloperr Jul 10, 2026
68ebf7c
docs: initial-scroll gap root-caused — adopted Fabric stack host is h…
DjDeveloperr Jul 10, 2026
221f82e
fix: adopted RNSScreenStack host fills viewport + re-renders hosted s…
DjDeveloperr Jul 10, 2026
faed963
fix: keep adopted stack-host viewport fill; drop unreliable content r…
DjDeveloperr Jul 10, 2026
74bef79
fix: RNS-exact single sizing authority for adopted native-stack hosting
DjDeveloperr Jul 10, 2026
0c27c9e
fix: RNS-exact modal teardown — never restore unmounted views, defer …
DjDeveloperr Jul 10, 2026
e479601
fix: eliminate AB-BA worklet/main-queue deadlock
DjDeveloperr Jul 11, 2026
310f82a
docs: extend lock-hierarchy comments to forbid synchronous render-ser…
DjDeveloperr Jul 11, 2026
73052a6
perf: drop dead-weight synchronous worklet crossing in UIKit-host mou…
DjDeveloperr Jul 13, 2026
363eceb
fix: SEAM D STAGE 0 - make Fabric transactionCommitted delivery exact…
DjDeveloperr Jul 16, 2026
142bea8
fix: native one-shot `mounted` lifecycle delivery (Path A, Change 1/2)
DjDeveloperr Jul 16, 2026
76764be
fix: gate UIKit-host update on serializable-payload change, not funct…
DjDeveloperr Jul 16, 2026
2543640
feat: surface Fabric per-host delivery token to JS (Seam D foundation…
DjDeveloperr Jul 16, 2026
78dd514
feat: lightweight always-on interop-call counter for pop-perf gating …
DjDeveloperr Jul 16, 2026
5806956
fix: restore first-access inherited-selector resolution for ClassBuil…
DjDeveloperr Jul 18, 2026
fc9dbe6
fix: restore unconditional Fabric handle delivery for fill-sizing hos…
DjDeveloperr Jul 18, 2026
c73855e
create @nativescript/react-native-screens package (M1 Step A: extract…
DjDeveloperr Jul 18, 2026
c698382
M1 Step B — package consumed by stock react-navigation (native-first …
DjDeveloperr Jul 18, 2026
d37b53b
fix false dismissal of modally-presented screens (blank modal) — excl…
DjDeveloperr Jul 18, 2026
5227c65
fix content-readiness probe to see through ActivityView wrapper — col…
DjDeveloperr Jul 18, 2026
2edb6db
fix(screens): repair D6 pop snapshot — worklet capture order, expando…
DjDeveloperr Jul 18, 2026
084a86d
render native header right bar button items (descriptor-driven) — hea…
DjDeveloperr Jul 18, 2026
dad66b8
wire left bar button items — header parity
DjDeveloperr Jul 18, 2026
ca7018e
restore real Yoga layout for hosted subviews (stop the fill from supp…
DjDeveloperr Jul 18, 2026
09cc92b
react-native-screens: close import-crash and flag-shape parity gaps
DjDeveloperr Jul 19, 2026
cbf946c
react-native-screens: implement react-freeze parity for blurred screens
DjDeveloperr Jul 19, 2026
60924da
react-native-screens: close modal presentation parity with upstream RNS
DjDeveloperr Jul 19, 2026
8e36c81
react-native-screens: Wave 1 event correctness + dismissal prevention
DjDeveloperr Jul 19, 2026
3ff911a
react-native-screens: revert modal/pageSheet sheet mapping — it stran…
DjDeveloperr Jul 19, 2026
f7b8b6a
react-native-screens: stackAnimation 'none', modal fade/flip, replace…
DjDeveloperr Jul 19, 2026
383de51
react-native-screens: Wave 4 header styling — title/large-title fonts…
DjDeveloperr Jul 19, 2026
56c48aa
host React header-right elements as UIBarButtonItem.customView via en…
DjDeveloperr Jul 19, 2026
8779df6
host React headerTitle and headerLeft elements in the navigation bar …
DjDeveloperr Jul 19, 2026
059c8a8
fix(ios): skip Auto-Layout-owned subviews in the detached-children fi…
DjDeveloperr Jul 23, 2026
53b2da7
feat(react-native-screens): land ScreenFooter and FullWindowOverlay s…
DjDeveloperr Jul 23, 2026
4f3a9bc
test(react-native-screens): host-side jest net — React Nav native-sta…
DjDeveloperr Jul 23, 2026
8564e3d
feat(react-native-screens): custom stackAnimation animators (Blocker A)
DjDeveloperr Jul 23, 2026
b621f01
feat(react-native-screens): host-side system-integration window trait…
DjDeveloperr Jul 23, 2026
13109d1
feat(react-native-screens): RNS SearchBar parity (descriptor-style UI…
DjDeveloperr Jul 23, 2026
fd6b957
test(screens-itest): on-simulator asserting integration harness (core…
DjDeveloperr Jul 23, 2026
9f13a88
merge(parity-batch1): animator-variants — 6 custom stackAnimation var…
DjDeveloperr Jul 23, 2026
b8b1f1c
test(screens-itest): parity suite — animation variants, status-bar tr…
DjDeveloperr Jul 23, 2026
a31f071
test(screens-itest): scope the parity gate to what device verificatio…
DjDeveloperr Jul 23, 2026
ef301d2
merge(parity-batch1): animator-variants — custom stackAnimation anima…
DjDeveloperr Jul 23, 2026
34f213f
test(screens-itest): correct the slide_from_bottom finding — intermit…
DjDeveloperr Jul 23, 2026
2668e58
Merge branch 'searchbar' into searchbar-r
DjDeveloperr Jul 23, 2026
ad56c91
fix(react-native-screens): call setShowsCancelButton:animated: by its…
DjDeveloperr Jul 23, 2026
2444e3f
Merge branch 'statusbar' into statusbar-r
DjDeveloperr Jul 23, 2026
721660e
wip(statusbar): trait forwarding chain + accessor overrides (with tem…
DjDeveloperr Jul 23, 2026
045cc02
Merge branch 'searchbar-r' into parity-integration
DjDeveloperr Jul 23, 2026
80b0119
fix(react-native-screens): per-screen window traits now reach UIKit (…
DjDeveloperr Jul 24, 2026
751a827
merge(parity-batch1): searchbar + statusbar — both device blockers fi…
DjDeveloperr Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ jobs:
IOS_TEST_TIMEOUT_MS: "600000"
IOS_TEST_INACTIVITY_TIMEOUT_MS: "180000"
IOS_LOG_JUNIT: "1"
IOS_TEST_VERBOSE_SPECS: "1"
IOS_SIMCTL_QUERY_TIMEOUT_MS: "10000"
run: npm run test:ios
388 changes: 388 additions & 0 deletions .oracle-context/ns-rns-first-paint/demo-react-navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,388 @@
const [transition, setTransition] = useState("idle");

useEffect(() => {
const start = navigation.addListener("transitionStart", (event) => {
logReactNavTiming(
`home-transition-start-${event.data.closing ? "closing" : "opening"}`,
);
setTransition(event.data.closing ? "closing" : "opening");
});
const end = navigation.addListener("transitionEnd", (event) => {
logReactNavTiming(
`home-transition-end-${event.data.closing ? "closing" : "opening"}`,
);
dumpNativeScriptRNSGeometry(
`home-transition-end-${event.data.closing ? "closing" : "opening"}`,
);
setTransition(event.data.closing ? "closed" : "open");
});

return () => {
start();
end();
};
}, [navigation]);

const pushDetail = useCallback(() => {
logReactNavTiming("push-onPress");
navigation.push("Detail", { serial: Date.now() % 10000 });
scheduleTraceExport("push", 1200);
}, [navigation]);

const presentModal = useCallback(() => {
logReactNavTiming("modal-present-onPress");
navigation.navigate("Modal");
scheduleTraceExport("modal-present", 1200);
}, [navigation]);

return (
<ScrollView
contentInsetAdjustmentBehavior="automatic"
scrollIndicatorInsets={{ bottom: 0 }}
style={styles.screen}
contentContainerStyle={styles.content}
>
<View style={styles.headerBlock}>
<Text selectable style={styles.title}>
RNS native-stack parity
</Text>
<Text selectable style={styles.bodyText}>
{buildDescription}
</Text>
</View>

<View style={styles.card}>
<Text selectable style={styles.cardTitle}>
NativeScript port path
</Text>
<View style={styles.statusList}>
{rows.map(([label, value]) => (
<View key={label} style={styles.statusRow}>
<Text selectable style={styles.statusLabel}>
{label}
</Text>
<Text selectable style={styles.statusValue}>
{value}
</Text>
</View>
))}
</View>
</View>

<Pressable
accessibilityLabel="Push React Navigation detail"
accessibilityRole="button"
onPress={pushDetail}
style={styles.primaryButton}
>
<Text style={styles.primaryButtonText}>Push Detail</Text>
</Pressable>

<Pressable
accessibilityLabel="Present React Navigation modal"
accessibilityRole="button"
onPress={presentModal}
style={styles.secondaryButton}
>
<Text style={styles.secondaryButtonText}>Present Modal Route</Text>
</Pressable>

<View style={styles.splitRow}>
<View style={styles.metricCard}>
<Text selectable style={styles.metricValue}>
{transition}
</Text>
<Text selectable style={styles.metricLabel}>
transition event
</Text>
</View>
<View style={styles.metricCard}>
<Text
accessibilityLabel={`React Navigation header ping count ${headerPing.count}`}
selectable
style={styles.metricValue}
>
{headerPing.count}
</Text>
<Text selectable style={styles.metricLabel}>
header pings
</Text>
</View>
<View style={styles.metricCard}>
<Text selectable style={styles.metricValue}>
26
</Text>
<Text selectable style={styles.metricLabel}>
iOS target
</Text>
</View>
<View style={styles.metricCard}>
<Text
accessibilityLabel={`React Navigation menu action count ${headerPing.menuCount}`}
selectable
style={styles.metricValue}
>
{headerPing.menuCount}
</Text>
<Text selectable style={styles.metricLabel}>
menu actions
</Text>
</View>
</View>

<View style={styles.card}>
<Text selectable style={styles.cardTitle}>
Scroll coverage
</Text>
<Text selectable style={styles.cardBody}>
This lower card is here to verify the route uses the full tab height.
The scroll view should move under the native navigation header and tab
bar instead of stopping halfway down the screen.
</Text>
</View>
</ScrollView>
);
}

function DetailScreen({ navigation, route }: DetailProps) {
const headerPing = useContext(HeaderPingContext);

useEffect(() => {
const start = navigation.addListener("transitionStart", (event) => {
logReactNavTiming(
`detail-transition-start-${event.data.closing ? "closing" : "opening"}`,
);
});
const end = navigation.addListener("transitionEnd", (event) => {
logReactNavTiming(
`detail-transition-end-${event.data.closing ? "closing" : "opening"}`,
);
dumpNativeScriptRNSGeometry(
`detail-transition-end-${event.data.closing ? "closing" : "opening"}`,
);
});

return () => {
start();
end();
};
}, [navigation]);

return (
<ScrollView
contentInsetAdjustmentBehavior="automatic"
scrollIndicatorInsets={{ bottom: 0 }}
style={styles.screen}
contentContainerStyle={styles.content}
>
<View style={styles.headerBlock}>
<Text selectable style={styles.title}>
Detail route
</Text>
<Text selectable style={styles.bodyText}>
Pushed with navigation.push. The visible back button is the system
UIKit button in minimal display mode, and the edge swipe should pop
this route.
</Text>
</View>

<View style={styles.card}>
<Text selectable style={styles.cardTitle}>
Route params
</Text>
<Text selectable style={styles.cardBody}>
serial = {route.params.serial}
</Text>
<View style={styles.pillRow}>
<Pill label="animated push" />
<Pill label="native pop" />
<Pill label="edge gesture" />
</View>
</View>

<View style={styles.card}>
<Text
accessibilityLabel={`React Navigation custom header action count ${headerPing.customCount}`}
selectable
style={styles.cardTitle}
>
custom header taps = {headerPing.customCount}
</Text>
<Text selectable style={styles.cardBody}>
This count is driven by a React Navigation headerRight React element
hosted in a UIKit UIBarButtonItem customView.
</Text>
</View>

<Pressable
accessibilityLabel="Pop React Navigation detail"
accessibilityRole="button"
onPress={() => {
logReactNavTiming("pop-onPress");
navigation.goBack();
scheduleTraceExport("pop", 1200);
}}
style={styles.primaryButton}
>
<Text style={styles.primaryButtonText}>Pop Detail</Text>
</Pressable>

<View style={styles.card}>
<Text selectable style={styles.cardTitle}>
Repeated tap guard
</Text>
<Text selectable style={styles.cardBody}>
UIKit owns the transition. React Navigation receives the completed
native stack after the push or pop animation settles.
</Text>
</View>
</ScrollView>
);
}

function DetailHeaderAction() {
const headerPing = useContext(HeaderPingContext);

return (
<Pressable
accessibilityLabel={`React Navigation custom header action ${headerPing.customCount}`}
accessibilityRole="button"
hitSlop={8}
onPress={() => {
logReactNavTiming("custom-header-onPress");
headerPing.incrementCustomHeader();
}}
style={styles.customHeaderButton}
>
<Text style={styles.customHeaderButtonText}>
{headerPing.customCount > 0 ? headerPing.customCount : "Tap"}
</Text>
</Pressable>
);
}

function DetailHeaderTitle() {
return (
<Text
accessibilityLabel="React Navigation custom header title"
numberOfLines={1}
style={styles.customHeaderTitle}
>
Native Detail
</Text>
);
}

function ModalScreen({ navigation }: ModalProps) {
useEffect(() => {
const start = navigation.addListener("transitionStart", (event) => {
logReactNavTiming(
`modal-transition-start-${event.data.closing ? "closing" : "opening"}`,
);
});
const end = navigation.addListener("transitionEnd", (event) => {
logReactNavTiming(
`modal-transition-end-${event.data.closing ? "closing" : "opening"}`,
);
});

return () => {
start();
end();
};
}, [navigation]);

const dismissModal = useCallback(() => {
logReactNavTiming("modal-dismiss-onPress");
navigation.goBack();
scheduleTraceExport("modal-dismiss", 1200);
}, [navigation]);

return (
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.modalScreen}
contentContainerStyle={styles.content}
>
<View style={styles.headerBlock}>
<Text selectable style={styles.title}>
Modal route
</Text>
<Text selectable style={styles.bodyText}>
This route uses React Navigation presentation options. It is included
to keep checking modal stack semantics in the NativeScript RNS port.
</Text>
</View>
<View style={styles.card}>
<Text selectable style={styles.cardTitle}>
UIKit presentation
</Text>
<Text selectable style={styles.cardBody}>
This screen is presented by UIKit with React Navigation state still
driving the route lifecycle. Dismissal should animate downward instead
of popping sideways.
</Text>
</View>
<Pressable
accessibilityLabel="Dismiss React Navigation modal"
accessibilityRole="button"
onPress={dismissModal}
style={styles.primaryButton}
>
<Text style={styles.primaryButtonText}>Dismiss Modal</Text>
</Pressable>
</ScrollView>
);
}

export default function ReactNavigationTab() {
const [headerPingCount, setHeaderPingCount] = useState(0);
const [customHeaderCount, setCustomHeaderCount] = useState(0);
const [headerMenuCount, setHeaderMenuCount] = useState(0);

const incrementHeaderPing = useCallback(() => {
logReactNavTiming("header-ping-onPress");
setHeaderPingCount((count) => count + 1);
}, []);

const incrementCustomHeader = useCallback(() => {
setCustomHeaderCount((count) => count + 1);
}, []);

const incrementHeaderMenu = useCallback(() => {
logReactNavTiming("header-menu-onPress");
setHeaderMenuCount((count) => count + 1);
}, []);

const headerPingContext = useMemo(
() => ({
count: headerPingCount,
customCount: customHeaderCount,
menuCount: headerMenuCount,
incrementCustomHeader,
}),
[customHeaderCount, headerMenuCount, headerPingCount, incrementCustomHeader],
);

return (
<NavigationIndependentTree>
<HeaderPingContext.Provider value={headerPingContext}>
<NavigationContainer>
<Stack.Navigator
screenOptions={{
contentStyle: { backgroundColor: "#f6f7fb" },
gestureEnabled: true,
headerBackButtonDisplayMode: "minimal",
headerShadowVisible: false,
headerTransparent: true,
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: "NS Port",
unstable_headerRightItems: () => [
{
type: "button",
label:
Loading