@gjsify/react-native 0.45.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/PROPS.md +525 -0
  2. package/README.md +45 -163
  3. package/SUPPORT.md +472 -0
  4. package/lib/esm/accessor.js +1 -0
  5. package/lib/esm/animated/brand.js +1 -0
  6. package/lib/esm/animated/easing.js +1 -0
  7. package/lib/esm/animated/index.js +1 -0
  8. package/lib/esm/animated/properties.js +1 -0
  9. package/lib/esm/animated/timing.js +1 -0
  10. package/lib/esm/animated/value.js +1 -0
  11. package/lib/esm/announce.js +1 -0
  12. package/lib/esm/app-registry.js +1 -1
  13. package/lib/esm/components.js +1 -1
  14. package/lib/esm/generated/own-exports.js +1 -1
  15. package/lib/esm/generated/unsupported-async-storage.js +0 -0
  16. package/lib/esm/generated/unsupported-expo-audio.js +1 -0
  17. package/lib/esm/generated/unsupported-expo-constants.js +1 -0
  18. package/lib/esm/generated/unsupported-expo-font.js +1 -0
  19. package/lib/esm/generated/unsupported-expo-image.js +1 -0
  20. package/lib/esm/generated/unsupported-expo-linking.js +1 -0
  21. package/lib/esm/generated/unsupported-expo-splash-screen.js +1 -0
  22. package/lib/esm/generated/unsupported-expo-status-bar.js +1 -0
  23. package/lib/esm/generated/unsupported-expo-system-ui.js +1 -0
  24. package/lib/esm/generated/unsupported-expo-video.js +1 -0
  25. package/lib/esm/generated/unsupported-expo-web-browser.js +1 -0
  26. package/lib/esm/generated/unsupported-nativewind.js +1 -0
  27. package/lib/esm/generated/unsupported-react-native-gesture-handler.js +1 -0
  28. package/lib/esm/generated/unsupported-react-native-safe-area-context.js +1 -0
  29. package/lib/esm/generated/unsupported-react-native-webview.js +1 -0
  30. package/lib/esm/generated/unsupported-react-native.js +1 -0
  31. package/lib/esm/generated/unsupported-router.js +1 -0
  32. package/lib/esm/generated/unsupported-vector-icons.js +1 -0
  33. package/lib/esm/index.js +1 -1
  34. package/lib/esm/lists/controller.js +1 -1
  35. package/lib/esm/primitives/answers.js +1 -0
  36. package/lib/esm/primitives/defaults.js +1 -0
  37. package/lib/esm/primitives/errors.js +1 -1
  38. package/lib/esm/primitives/handles.js +1 -0
  39. package/lib/esm/primitives/index.js +1 -1
  40. package/lib/esm/primitives/intents.js +1 -1
  41. package/lib/esm/primitives/resolve.js +1 -1
  42. package/lib/esm/primitives/style.js +1 -1
  43. package/lib/esm/primitives/table.js +1 -1
  44. package/lib/esm/prop-table.js +1 -0
  45. package/lib/esm/router/href.js +1 -0
  46. package/lib/esm/router/index.js +1 -1
  47. package/lib/esm/router/navigation.js +1 -1
  48. package/lib/esm/router/tabs.js +1 -1
  49. package/lib/esm/solid/index.js +1 -1
  50. package/lib/esm/stylesheet.js +1 -1
  51. package/lib/esm/support-table.js +1 -1
  52. package/lib/esm/surfaces/async-storage.js +1 -0
  53. package/lib/esm/surfaces/expo-audio.js +1 -0
  54. package/lib/esm/surfaces/expo-constants.js +1 -0
  55. package/lib/esm/surfaces/expo-font.js +1 -0
  56. package/lib/esm/surfaces/expo-image.js +1 -0
  57. package/lib/esm/surfaces/expo-linking.js +1 -0
  58. package/lib/esm/surfaces/expo-splash-screen.js +1 -0
  59. package/lib/esm/surfaces/expo-status-bar.js +1 -0
  60. package/lib/esm/surfaces/expo-system-ui.js +1 -0
  61. package/lib/esm/surfaces/expo-video.js +1 -0
  62. package/lib/esm/surfaces/expo-web-browser.js +1 -0
  63. package/lib/esm/surfaces/icon-map.js +1 -0
  64. package/lib/esm/surfaces/nativewind.js +1 -0
  65. package/lib/esm/surfaces/react-native-gesture-handler.js +1 -0
  66. package/lib/esm/surfaces/react-native-safe-area-context.js +1 -0
  67. package/lib/esm/surfaces/react-native-webview.js +1 -0
  68. package/lib/esm/surfaces/vector-icons.js +1 -0
  69. package/lib/esm/unsupported.js +1 -1
  70. package/lib/types/accessor.d.ts +10 -0
  71. package/lib/types/animated/animated.spec.d.ts +2 -0
  72. package/lib/types/animated/brand.d.ts +8 -0
  73. package/lib/types/animated/easing.d.ts +70 -0
  74. package/lib/types/animated/easing.spec.d.ts +2 -0
  75. package/lib/types/animated/index.d.ts +55 -0
  76. package/lib/types/animated/properties.d.ts +33 -0
  77. package/lib/types/animated/timing.d.ts +37 -0
  78. package/lib/types/animated/value.d.ts +103 -0
  79. package/lib/types/announce.d.ts +18 -0
  80. package/lib/types/components.d.ts +82 -3
  81. package/lib/types/generated/unsupported-async-storage.d.ts +1 -0
  82. package/lib/types/generated/unsupported-expo-audio.d.ts +4 -0
  83. package/lib/types/generated/unsupported-expo-constants.d.ts +2 -0
  84. package/lib/types/generated/unsupported-expo-font.d.ts +4 -0
  85. package/lib/types/generated/unsupported-expo-image.d.ts +3 -0
  86. package/lib/types/generated/unsupported-expo-linking.d.ts +4 -0
  87. package/lib/types/generated/unsupported-expo-splash-screen.d.ts +5 -0
  88. package/lib/types/generated/unsupported-expo-status-bar.d.ts +5 -0
  89. package/lib/types/generated/unsupported-expo-system-ui.d.ts +2 -0
  90. package/lib/types/generated/unsupported-expo-video.d.ts +3 -0
  91. package/lib/types/generated/unsupported-expo-web-browser.d.ts +6 -0
  92. package/lib/types/generated/unsupported-nativewind.d.ts +5 -0
  93. package/lib/types/generated/unsupported-react-native-gesture-handler.d.ts +10 -0
  94. package/lib/types/generated/unsupported-react-native-safe-area-context.d.ts +4 -0
  95. package/lib/types/generated/unsupported-react-native-webview.d.ts +1 -0
  96. package/lib/types/generated/{unsupported-exports.d.ts → unsupported-react-native.d.ts} +0 -2
  97. package/lib/types/generated/unsupported-vector-icons.d.ts +11 -0
  98. package/lib/types/index.d.ts +5 -1
  99. package/lib/types/primitives/answers.d.ts +69 -0
  100. package/lib/types/primitives/defaults.d.ts +52 -0
  101. package/lib/types/primitives/defaults.spec.d.ts +2 -0
  102. package/lib/types/primitives/errors.d.ts +9 -0
  103. package/lib/types/primitives/handles.d.ts +56 -0
  104. package/lib/types/primitives/index.d.ts +8 -2
  105. package/lib/types/primitives/intents.d.ts +36 -0
  106. package/lib/types/primitives/resolve.d.ts +25 -1
  107. package/lib/types/primitives/table.d.ts +63 -1
  108. package/lib/types/prop-table.d.ts +56 -0
  109. package/lib/types/prop-table.spec.d.ts +2 -0
  110. package/lib/types/router/href.d.ts +58 -0
  111. package/lib/types/router/href.spec.d.ts +2 -0
  112. package/lib/types/router/index.d.ts +3 -1
  113. package/lib/types/router/navigation.d.ts +47 -5
  114. package/lib/types/router/tabs.d.ts +35 -0
  115. package/lib/types/solid/index.d.ts +15 -1
  116. package/lib/types/support-table.d.ts +79 -10
  117. package/lib/types/surfaces/async-storage.d.ts +57 -0
  118. package/lib/types/surfaces/expo-audio.d.ts +1 -0
  119. package/lib/types/surfaces/expo-constants.d.ts +11 -0
  120. package/lib/types/surfaces/expo-font.d.ts +34 -0
  121. package/lib/types/surfaces/expo-image.d.ts +1 -0
  122. package/lib/types/surfaces/expo-linking.d.ts +36 -0
  123. package/lib/types/surfaces/expo-splash-screen.d.ts +1 -0
  124. package/lib/types/surfaces/expo-status-bar.d.ts +16 -0
  125. package/lib/types/surfaces/expo-system-ui.d.ts +1 -0
  126. package/lib/types/surfaces/expo-video.d.ts +1 -0
  127. package/lib/types/surfaces/expo-web-browser.d.ts +21 -0
  128. package/lib/types/surfaces/icon-map.d.ts +14 -0
  129. package/lib/types/surfaces/nativewind.d.ts +1 -0
  130. package/lib/types/surfaces/react-native-gesture-handler.d.ts +10 -0
  131. package/lib/types/surfaces/react-native-safe-area-context.d.ts +60 -0
  132. package/lib/types/surfaces/react-native-webview.d.ts +4 -0
  133. package/lib/types/surfaces/surfaces.spec.d.ts +2 -0
  134. package/lib/types/surfaces/vector-icons.d.ts +15 -0
  135. package/lib/types/unsupported.d.ts +12 -3
  136. package/package.json +85 -14
  137. package/lib/esm/generated/unsupported-exports.js +0 -1
  138. package/lib/esm/generated/unsupported-router-exports.js +0 -1
  139. /package/lib/types/generated/{unsupported-router-exports.d.ts → unsupported-router.d.ts} +0 -0
package/README.md CHANGED
@@ -32,6 +32,46 @@ a real `react-native` install when one is resolvable — and it prints which of
32
32
  it did, because a gate that silently degrades to the weaker half is worse than one
33
33
  that has only the weaker half.
34
34
 
35
+ ## The PROP surface is a contract too, and it is published
36
+
37
+ The support table answers "may this application import this name". One grain finer
38
+ sits `src/primitives/table.ts`, which decides what each PRIMITIVE does with each
39
+ PROP — and until [ADR 0039](../../../docs/adr/0039-react-native-prop-surface.md) it
40
+ was not an entry point, so a refusal could only be discovered by RENDERING. That cost
41
+ a whole tree once: a `<Text onPress>` in a tab stack that mounts every tab from the
42
+ start route threw out of a render, and React unmounts the root when a render throws
43
+ with no error boundary above it — 92 125 bytes of widget dump clean against 12 848
44
+ with the throw, same screen, same host.
45
+
46
+ The refusal is right and it still throws: a prop that silently does nothing is
47
+ indistinguishable from a bug in the application, forever. What was missing is a way to
48
+ ask FIRST, and that is `@gjsify/react-native/prop-table`:
49
+
50
+ ```ts
51
+ import { acceptsProp, explainProp } from '@gjsify/react-native/prop-table';
52
+
53
+ // in your own test suite, before a window exists
54
+ expect(acceptsProp('Text', 'onPress')).toBe(false);
55
+ expect(explainProp('Text', 'onPress')).toContain('Wrap it in a `<Pressable>`');
56
+ ```
57
+
58
+ `explainProp` returns the very sentence a render would have thrown — one classifier
59
+ (`src/primitives/answers.ts`) serves both, so the static answer cannot drift from the
60
+ runtime one. [PROPS.md](PROPS.md) is the generated document, one section per
61
+ primitive, held byte for byte by `check-rn-surface.mjs`.
62
+
63
+ ## `<TextInput>`'s ref is a handle, not the widget
64
+
65
+ React Native's `TextInput` is a class, so `useRef<TextInput>(null)` and
66
+ `ref.current?.focus()` are ordinary code. Here `TextInput` is a component function
67
+ merged with an instance interface, and the ref receives `focus`, `blur`, `clear`,
68
+ `isFocused` and `setSelection` over GTK, plus `widget` — the `Gtk.Entry` or
69
+ `Gtk.TextView` itself, which is where anything the handle does not answer lives.
70
+ `measure`, `measureInWindow`, `measureLayout` and `setNativeProps` are present and
71
+ **refuse by name**, because an absent method is `undefined is not a function`.
72
+
73
+ Every other primitive's ref is the `Gtk.Widget`, unchanged.
74
+
35
75
  ## Getting a window
36
76
 
37
77
  ```ts
@@ -184,166 +224,8 @@ refusals. The plugin walks a directory and emits what it found.
184
224
 
185
225
  ## Support
186
226
 
187
- <!-- BEGIN generated support table -->
188
-
189
- ### Supported (4)
190
-
191
- | export | tier | GTK | why |
192
- |---|---|---|---|
193
- | `useColorScheme` | P1 | Adw.StyleManager.dark | Follows the Adwaita colour scheme — the dark property, which is what the user is looking at, not color-scheme, which is what the application asked for. |
194
- | `Appearance` | P2 | Adw.StyleManager | The imperative sibling of useColorScheme, over the SAME reader — getColorScheme reads Adw.StyleManager:dark (what the user is looking at) and setColorScheme writes :color-scheme (what the application asked for), which is exactly the split React Native’s getter and setter have. |
195
- | `EventEmitter` | — | — | Pure JavaScript; nothing in it touches a platform. |
196
- | `unstable_batchedUpdates` | — | — | React 19 batches automatically; this is the identity call it already is upstream. |
197
-
198
- ### Supported, with named limits (29)
199
-
200
- | export | tier | GTK | why |
201
- |---|---|---|---|
202
- | `View` | P1 | Gtk.Box, or Gtk.Overlay when a child is absolutely positioned | The container primitive. Which widget it becomes depends on its children, not on the element. |
203
- | `Text` | P1 | Gtk.Label | Wrapping is ON by default in React Native and OFF on a Gtk.Label, so the default is set explicitly. |
204
- | `Pressable` | P1 | Gtk.Button (flat) | Press state is a GTK CSS :active pseudo-class; children-as-a-function is implemented over the state flag, and costs nothing when it is unused. |
205
- | `ScrollView` | P1 | Gtk.ScrolledWindow + an implicit content box | contentContainerStyle styles the inner box, which is a second styleable node. |
206
- | `ActivityIndicator` | P1 | Adw.Spinner | Direct counterpart. |
207
- | `TextInput` | P1 | Gtk.Entry / Gtk.TextView | Single- versus multi-line is one prop in React Native and two different widgets in GTK. |
208
- | `Linking` | P1 | Gtk.UriLauncher | openURL and canOpenURL only. |
209
- | `Switch` | P1 | Gtk.Switch | Direct counterpart. |
210
- | `Platform` | P1 | — | OS is "linux" \| "macos" \| "windows"; select() picks the default branch. |
211
- | `Share` | P1 | Gdk.Clipboard | No desktop share sheet worth pretending about; copying the link is the honest mapping. |
212
- | `AppRegistry` | P1 | Adw.Application + Adw.ApplicationWindow | The entry point. Nothing renders without a window, so this is P1 despite being a shim. |
213
- | `StyleSheet` | P1 | Gdk.Monitor.scale for hairlineWidth | create/flatten/compose/hairlineWidth/absoluteFill. Style objects go through the same partition as classes (ADR 0032 § 4), which is why create can be identity. |
214
- | `FlatList` | P2 | Gtk.ListView + Gio.ListStore, owned by the component | GTK virtualises for real. The list is NOT an ordinary element: a Gtk.ListView takes no children (measured — no append, add, insert, prepend, remove or set_child), so the component owns the view and drives the model from data, with React only inside the item factory. |
215
- | `SectionList` | P2 | Gtk.ListView + one flattened Gio.ListStore | The same component as FlatList, handed sections instead of data. |
216
- | `VirtualizedList` | P2 | Gtk.ListView | Its public surface is wide and mostly not worth honouring literally; the useful subset backs FlatList, and this name is that subset plus getItem/getItemCount. |
217
- | `VirtualizedSectionList` | P2 | Gtk.ListView | The section-shaped sibling of VirtualizedList, which is SectionList here. |
218
- | `Image` | P2 | Gtk.Picture | resizeMode becomes content-fit, and the default is inverted: React Native defaults to cover, a Gtk.Picture to contain (measured). |
219
- | `ImageBackground` | P2 | Gtk.Picture in a Gtk.Overlay | A picture with the children stacked over it. The picture is the overlay’s MAIN child, because a Gtk.Overlay paints every overlay child ABOVE it. |
220
- | `TouchableOpacity` | P2 | Gtk.Button (flat) | The same machinery as Pressable, written over it: one shared record of routes in the primitive table, one line of component. |
221
- | `TouchableHighlight` | P2 | Gtk.Button (flat) | As TouchableOpacity. The pressed style is Adwaita’s own unless a variant says otherwise. |
222
- | `TouchableWithoutFeedback` | P2 | Gtk.Box + Gtk.GestureClick | No chrome, so no button: a vertical Gtk.Box like a View, with a Gtk.GestureClick added to it. Measured: Gtk.Button emits activate and clicked, a Gtk.Box emits neither, and Gtk.GestureClick emits pressed/released/stopped/unpaired-release. |
223
- | `Button` | P2 | Gtk.Button | The one component whose React Native styling story is "you cannot", which GTK agrees with. title, onPress and disabled. |
224
- | `Dimensions` | P2 | Gtk.Window allocation, Gdk.Monitor geometry | get("window") is the window, not the screen — a desktop app is not full-screen, so the screen’s number would be wrong in the ordinary case. get("screen") is the monitor, because that is what it asks for. |
225
- | `useWindowDimensions` | P2 | Gdk.Surface notify::width/height, Gtk.Window allocation | The hook form of Dimensions, through useSyncExternalStore so a resize between render and commit cannot tear. |
226
- | `Alert` | P2 | Adw.AlertDialog | Direct counterpart, and buildable where Modal is not: Alert is a FUNCTION CALL, so no element is ever inserted into a widget. Measured on libadwaita 1.9.3 — present(null) from a plain function, with no parent and no window, returned with no diagnostic. |
227
- | `SafeAreaView` | P2 | Gtk.Box | The INSET has no desktop meaning; the layout does. It is a View in every other respect, and it has to be a real export to be imported. |
228
- | `StatusBar` | P2 | — | A desktop window has no status bar to configure, and <StatusBar/> is in the first ten lines of most React Native screens — so it renders NOTHING and says so, rather than failing to import. |
229
- | `KeyboardAvoidingView` | P2 | Gtk.Box | No on-screen keyboard eats a desktop window layout, so the AVOIDING is the no-op. React Native’s KeyboardAvoidingView is a View that changes its own height; what is left here is the View. |
230
- | `Keyboard` | P2 | — | Its events are on-screen-keyboard events, which do not occur — so the questions with a correct answer get it and the ones whose answer would have to be invented refuse. |
231
-
232
- ### Planned (28)
233
-
234
- | export | tier | GTK | why |
235
- |---|---|---|---|
236
- | `Modal` | P1 | Adw.Dialog | An Adw.Dialog cannot be an ordinary element. MEASURED on libadwaita 1.9.3: box.append(dialog) calls g_error() — SIGABRT and a core dump, not a catchable exception — but ONLY when the box is rooted in a window. A detached box accepts the append in silence, so a re-test on a bare box appears to disprove this and puts the primitive back. A dialog is PRESENTED against a parent, never parented by it, so this is a PORTAL and needs a host seam that does not exist yet. |
237
- | `AppState` | P3 | Gtk.Application / Gdk.Surface state | active/background from window focus and visibility. |
238
- | `PixelRatio` | P3 | Gdk.Surface.scale-factor | The scale factor of the surface the widget is on. |
239
- | `PlatformColor` | P3 | Adwaita named colours | Maps unusually well — GTK’s palette is exactly this idea. |
240
- | `AccessibilityInfo` | P3 | Gtk.Accessible / AT-SPI | The highest-value P3 entry: GTK’s accessibility model is strong and the props map onto it well. |
241
- | `Animated` | P3 | Adw.TimedAnimation / Adw.SpringAnimation | Genuinely mappable, but it is a subsystem rather than a component. Doing it badly is worse than not doing it. |
242
- | `Easing` | P3 | — | Pure maths; it lands with Animated or not at all. |
243
- | `LayoutAnimation` | P3 | — | Needs an animated layout pass, which is the same subsystem as Animated. |
244
- | `InteractionManager` | P3 | — | Deferring work until interactions settle; a main-loop idle source is the counterpart. |
245
- | `useAnimatedValue` | P3 | — | Part of the Animated subsystem. |
246
- | `useAnimatedValueXY` | P3 | — | Part of the Animated subsystem. |
247
- | `useAnimatedColor` | P3 | — | Part of the Animated subsystem. |
248
- | `PanResponder` | P3 | Gtk.Gesture* controllers | The controllers exist; the arbitration model is not React Native’s, so this is its own project. |
249
- | `usePressability` | P3 | — | The hook behind the Touchable family; it lands with the gesture work. |
250
- | `DrawerLayoutAndroid` | P3 | Adw.OverlaySplitView | The pattern survives on a desktop even though the component is Android-only. |
251
- | `I18nManager` | P3 | Gtk.Widget.direction | RTL is a widget-direction question on GTK. |
252
- | `ToastAndroid` | P3 | Adw.Toast | Android-only by name, and Adwaita has the exact widget. |
253
- | `TouchableNativeFeedback` | P3 | Gtk.Button | Android-only ripple; shimmed to its portable sibling. |
254
- | `ActionSheetIOS` | P3 | Adw.AlertDialog with responses | iOS-only by name; the pattern is a dialog with choices. |
255
- | `Clipboard` | P3 | Gdk.Clipboard | Deprecated upstream in favour of a community package, but trivial here. |
256
- | `BackHandler` | P3 | — | An Android hardware back button. Routing has landed and this did NOT arrive with it, which the earlier reason assumed it would: BackHandler INTERCEPTS a back press and consumes it, and MEASURED on libadwaita 1.9.3, Adw.NavigationView emits `popped` AFTER the fact and has no vetoable "about to pop" signal at all — its only prevention is Adw.NavigationPage:can-pop, a property rather than an event. The honest counterpart is usePreventRemove, which the routing layer does honour through its popped bridge; this name needs a key controller of its own on the window. |
257
- | `DynamicColorIOS` | P3 | — | A light/dark colour pair; the Adwaita scheme already provides the switch. |
258
- | `processColor` | P3 | — | Colour string to a platform value; a Gdk.RGBA on this side. |
259
- | `UTFSequence` | P3 | — | A table of unicode constants. Pure data, no platform in it. |
260
- | `ReactNativeVersion` | P3 | — | The version this layer targets, reported honestly rather than spoofed. |
261
- | `ProgressBarAndroid` | P3 | Gtk.ProgressBar | Android-only by name; GTK has the widget. |
262
- | `NativeEventEmitter` | P3 | — | It would construct and subscribe, but nothing native would ever emit into it — shipping that needs a decision, not a class. |
263
- | `DeviceEventEmitter` | P3 | — | The global emitter. Lands with NativeEventEmitter, and for the same reason. |
264
-
265
- ### No meaning on a desktop window (6)
266
-
267
- | export | tier | GTK | why |
268
- |---|---|---|---|
269
- | `LogBox` | P3 | — | A development overlay for a phone; the console is the desktop equivalent. |
270
- | `Systrace` | — | — | Android systrace has no desktop counterpart. |
271
- | `Vibration` | — | — | A desktop machine does not vibrate. |
272
- | `InputAccessoryView` | — | — | An iOS keyboard accessory bar; there is no keyboard to accessorise. |
273
- | `DevMenu` | — | — | The shake-to-open developer menu. |
274
- | `DevSettings` | — | — | Development-client settings for a phone runtime. |
275
-
276
- ### Refused (25)
277
-
278
- | export | tier | GTK | why |
279
- |---|---|---|---|
280
- | `RefreshControl` | — | — | GTK has no pull-to-refresh idiom and should not grow one. Give the desktop build a refresh action instead. |
281
- | `PushNotificationIOS` | — | — | Platform notification plumbing. A desktop app uses Gio.Notification directly. |
282
- | `PermissionsAndroid` | — | — | Android runtime permissions have no desktop counterpart; portals are asked for at use time. |
283
- | `Settings` | — | — | An iOS user-defaults bridge. GSettings is the desktop answer and is not this API. |
284
- | `experimental_LayoutConformance` | — | — | An experimental switch between two React Native layout implementations. Neither is used here. |
285
- | `unstable_VirtualView` | — | — | Unstable React Native internal. |
286
- | `VirtualViewMode` | — | — | Unstable React Native internal. |
287
- | `unstable_NativeText` | — | — | Unstable React Native internal. |
288
- | `unstable_NativeView` | — | — | Unstable React Native internal. |
289
- | `unstable_TextAncestorContext` | — | — | Unstable React Native internal. |
290
- | `DeviceInfo` | — | — | A native module surface describing a phone. |
291
- | `NativeModules` | — | — | The native-module bridge. There is no bridge here; this layer renders in-process onto GTK. |
292
- | `TurboModuleRegistry` | — | — | The TurboModule lookup. Same reason as NativeModules. |
293
- | `NativeComponentRegistry` | — | — | Fabric component registration. The host owns widget creation. |
294
- | `requireNativeComponent` | — | — | Looks up a native view manager. Write a GTK widget descriptor instead. |
295
- | `codegenNativeComponent` | — | — | React Native codegen for Fabric components. |
296
- | `codegenNativeCommands` | — | — | React Native codegen for Fabric commands. |
297
- | `UIManager` | — | — | The legacy view-manager surface. The GTK host is the view manager here. |
298
- | `findNodeHandle` | — | — | Returns a native view tag. A ref here is the Gtk.Widget itself, which is more useful. |
299
- | `registerCallableModule` | — | — | Registers a module callable from the native side. There is no native side. |
300
- | `Networking` | — | — | React Native’s XHR internals. Use fetch, which gjsify provides. |
301
- | `NativeDialogManagerAndroid` | — | — | An Android dialog native module. Alert is the portable spelling. |
302
- | `Touchable` | — | — | The legacy mixin behind the Touchable family, not a public component. |
303
- | `NativeAppEventEmitter` | — | — | The legacy iOS app-event emitter. |
304
- | `RootTagContext` | — | — | A React Native surface identifier. This layer has one root per Adw window. |
305
-
306
- <!-- END generated support table -->
307
-
308
- ### Routing surface
309
-
310
- <!-- BEGIN generated router support table -->
311
-
312
- ### Supported, with named limits (5)
313
-
314
- | export | tier | GTK | why |
315
- |---|---|---|---|
316
- | `router` | P1 | Adw.NavigationView (push/pop) via React Navigation’s StackActions | push, back, replace and navigate — the four methods the measured application calls, 19 of the 27 calls being push. |
317
- | `useLocalSearchParams` | P1 | — | The current route’s params — the [param] values and the query string — read through React Navigation’s own useRoute(). |
318
- | `usePathname` | P1 | — | The current URL without its query string, from React Navigation’s getPathFromState over the published root state. |
319
- | `Stack` | P1 | Adw.NavigationView + Adw.NavigationPage | The stack navigator: React declares which pages exist, the widget owns their order, and the route key is the tag that joins the two. |
320
- | `Tabs` | P1 | Adw.ViewStack + Adw.ViewSwitcher | The tab navigator. The switcher is driven by the stack’s own page model, so a route file adds a button with no tab-bar bookkeeping. |
321
-
322
- ### Planned (13)
323
-
324
- | export | tier | GTK | why |
325
- |---|---|---|---|
326
- | `Link` | P2 | Gtk.Button (flat) or Gtk.LinkButton | An href as an element rather than a call. Cheap once `router` exists, and the honest widget question — button or link — is worth measuring first. |
327
- | `Redirect` | P2 | — | A declarative navigate-on-render. It needs a rule for what happens when it redirects during the first commit, which is the commit that must not be empty. |
328
- | `Slot` | P2 | Adw.Bin | A layout that renders its child route with no navigator around it. It is the one layout shape that has no widget of its own. |
329
- | `useRouter` | P2 | — | The hook form of `router`. Identical behaviour, and it exists so a test can substitute the object — which is worth having once there is something to substitute. |
330
- | `useSegments` | P2 | — | The current route split into segments. Derivable from the published root state, and unused in the measured application. |
331
- | `useGlobalSearchParams` | P2 | — | The params of the focused route anywhere in the tree, rather than of the calling screen. It re-renders on every navigation by design, which is why expo-router documents preferring the local form. |
332
- | `useNavigation` | P2 | — | React Navigation’s own hook, re-exported by expo-router. It works already through @react-navigation/core; exporting it from here is a decision about what this surface promises, not a build. |
333
- | `useFocusEffect` | P2 | — | As useNavigation: it is core’s, and it works. The open question is the same one. |
334
- | `useRootNavigationState` | P3 | — | The root state as a hook. The store `usePathname` reads is already there; this is a second selector over it. |
335
- | `Drawer` | P3 | Adw.OverlaySplitView | A sidebar navigator. The pattern survives on a desktop better than it does on a phone, and Adwaita has the exact widget — it is a third navigator, not a variation on these two. |
336
- | `withLayoutContext` | P3 | — | The escape hatch that lets a third-party navigator take its screens from the file tree. It is exactly `useRouteNode` plus screen synthesis, made public — worth doing once a third navigator exists to prove the shape. |
337
- | `Navigator` | P3 | — | expo-router’s low-level navigator primitive. It belongs with withLayoutContext and for the same reason. |
338
- | `ErrorBoundary` | P3 | Adw.StatusPage | A per-route error screen. React 19 routes an uncaught error to the root’s handler and @gjsify/gtk-host/react rethrows it from render() — deliberately, so a refusal is not swallowed — and a boundary here has to be reconciled with that rather than bolted beside it. |
339
-
340
- ### Refused (4)
341
-
342
- | export | tier | GTK | why |
343
- |---|---|---|---|
344
- | `ExpoRoot` | — | — | It takes a Metro `require.context`, which does not exist in this build chain. `RouterRoot` takes the manifest a bundler plugin emits instead — the same job, with the one input that is available. |
345
- | `useUnstableGlobalHref` | — | — | Unstable by its own name, and it answers the question usePathname already answers for the only surface this layer has. |
346
- | `useNavigationContainerRef` | — | — | The container ref is this layer’s own (one process routes one tree), and handing it out would let a consumer dispatch around the refusals `router` exists to give. |
347
- | `SplashScreen` | — | — | A native splash screen belongs to a phone launcher. A GTK application maps its window when it is ready, which is the desktop equivalent and is Gio.Application’s job, not the router’s. |
348
-
349
- <!-- END generated router support table -->
227
+ See **[SUPPORT.md](SUPPORT.md)** — one section per declared surface, generated from
228
+ `src/support-table.ts` in registry order. It is a separate document because
229
+ `react-native`'s section alone is about a hundred table rows and the eighteen surfaces
230
+ together are several hundred; putting them here would bury everything above.
231
+