feat(expo-router): add Expo Router support for Screens and navigations and introduce Steps API

- Introduces trigger metadata for steps and edges to capture what fires a site (JS prop, on* option, or callback) to improve cross-boundary flow analysis.
- Extends parsing/analysis to detect triggers in JSX attributes, on* bindings, and late-bound callbacks; adds utilities (calleeText, lastSegment) to extract trigger sources.
- Ships new trigger structures (WireStepTrigger, trigger on WireStepSite/WireStep) and propagates trigger through built steps; updates step labeling to reflect trigger information.
- Adds triggerWords helper and uses it to render human-readable trigger descriptions in Steps UI, including edge labels and per-site visuals.
- Updates UI (ScreensView, StepsView) to display FIRES FROM information, with styling tweaks to highlight triggers and related elements; enhances tooltips and inline text wrapping for readability.
- Extends tests to cover trigger detection and rendering across various binding patterns (prop, option, callback) and inline RN listeners.
- Updates design/docs and changelog to reflect Expo Router integration, per-site trigger metadata, and the new Steps surface.
This commit is contained in:
Colby McHenry
2026-08-28 10:40:38 -05:00
parent e288d7645b
commit 5e06204deb
11 changed files with 245 additions and 38 deletions
+17
View File
@@ -710,6 +710,19 @@ export interface WireStepSite {
args?: string;
/** The conditions THIS site runs under (the whole chain's); '' when unconditional. */
when: string;
/** What fires THIS site, when it differs from the link's first. */
trigger?: WireStepTrigger;
}
/** What fires a step or a link: the event it is written under, and the function that writes it there. */
export interface WireStepTrigger {
kind: 'prop' | 'option' | 'callback';
/** `onPress`, `onSubmit`, `useEffect`, `addListener`. */
name: string;
/** `Button` for a prop, `useFormik` for an option, the first string argument for a callback; null when unknown. */
of: string | null;
/** The function the binding is written in. */
in: string;
}
export interface WireStep {
@@ -733,6 +746,8 @@ export interface WireStep {
event?: string;
/** Every event that lands on this step. */
events?: string[];
/** For a handler: what fires it. */
trigger?: WireStepTrigger;
screen?: { path: string; component: WireNodeRef | null };
/** The calls one function makes into one category, and the function. */
effect?: { api: string; apis: string[]; category: string; by: WireNodeRef; line: number };
@@ -752,6 +767,8 @@ export interface WireStepLink {
synthesized: boolean;
uncertain: boolean;
sites: WireStepSite[];
/** What fires the first site, when something binds it to an event. */
trigger?: WireStepTrigger;
}
export interface WireStepsPayload {