@gjsify/react-native 0.43.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 (56) hide show
  1. package/README.md +253 -0
  2. package/lib/esm/_virtual/_rolldown/runtime.js +1 -0
  3. package/lib/esm/apis/color-scheme.js +1 -0
  4. package/lib/esm/apis/index.js +1 -0
  5. package/lib/esm/apis/linking.js +1 -0
  6. package/lib/esm/apis/platform.js +1 -0
  7. package/lib/esm/apis/share.js +2 -0
  8. package/lib/esm/app-registry.js +1 -0
  9. package/lib/esm/components.js +1 -0
  10. package/lib/esm/event-emitter.js +1 -0
  11. package/lib/esm/generated/unsupported-exports.js +1 -0
  12. package/lib/esm/hooks.js +1 -0
  13. package/lib/esm/index.js +1 -0
  14. package/lib/esm/primitives/classes.js +1 -0
  15. package/lib/esm/primitives/errors.js +1 -0
  16. package/lib/esm/primitives/index.js +1 -0
  17. package/lib/esm/primitives/intents.js +1 -0
  18. package/lib/esm/primitives/resolve.js +1 -0
  19. package/lib/esm/primitives/style.js +1 -0
  20. package/lib/esm/primitives/table.js +1 -0
  21. package/lib/esm/solid/index.js +1 -0
  22. package/lib/esm/style-config.js +1 -0
  23. package/lib/esm/support-table.js +1 -0
  24. package/lib/esm/unsupported.js +1 -0
  25. package/lib/types/apis/apis.spec.d.ts +2 -0
  26. package/lib/types/apis/color-scheme.d.ts +16 -0
  27. package/lib/types/apis/index.d.ts +7 -0
  28. package/lib/types/apis/linking.d.ts +35 -0
  29. package/lib/types/apis/platform.d.ts +28 -0
  30. package/lib/types/apis/share.d.ts +27 -0
  31. package/lib/types/app-registry.d.ts +50 -0
  32. package/lib/types/components.d.ts +77 -0
  33. package/lib/types/event-emitter.d.ts +29 -0
  34. package/lib/types/event-emitter.spec.d.ts +2 -0
  35. package/lib/types/generated/unsupported-exports.d.ts +78 -0
  36. package/lib/types/hooks.d.ts +13 -0
  37. package/lib/types/index.d.ts +22 -0
  38. package/lib/types/primitives/classes.d.ts +23 -0
  39. package/lib/types/primitives/classes.spec.d.ts +2 -0
  40. package/lib/types/primitives/errors.d.ts +9 -0
  41. package/lib/types/primitives/index.d.ts +11 -0
  42. package/lib/types/primitives/intents.d.ts +65 -0
  43. package/lib/types/primitives/primitives.spec.d.ts +2 -0
  44. package/lib/types/primitives/resolve.d.ts +71 -0
  45. package/lib/types/primitives/style.d.ts +73 -0
  46. package/lib/types/primitives/table.d.ts +122 -0
  47. package/lib/types/primitives/widgets.spec.d.ts +2 -0
  48. package/lib/types/solid/index.d.ts +101 -0
  49. package/lib/types/solid/solid.spec.d.ts +2 -0
  50. package/lib/types/style-config.d.ts +28 -0
  51. package/lib/types/support-table.d.ts +38 -0
  52. package/lib/types/support-table.spec.d.ts +2 -0
  53. package/lib/types/unsupported.d.ts +21 -0
  54. package/lib/types/unsupported.spec.d.ts +2 -0
  55. package/package.json +111 -0
  56. package/react-native-surface.json +108 -0
package/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # @gjsify/react-native
2
+
3
+ React Native's view vocabulary, rendered onto GTK4 and Adwaita.
4
+
5
+ This is the package a consumer's bundler aliases `react-native` to, so its export
6
+ surface mirrors React Native's own — all 92 public names. What is implemented is
7
+ exported normally; **what is not is exported as a value that refuses with a reason**,
8
+ because `MISSING_EXPORT` tells a reader the name is unknown while the support table
9
+ can tell them it is tier P2, maps onto `Gtk.ListView`, and is not built yet.
10
+
11
+ Architecture and the decisions behind it: [ADR 0032](../../../docs/adr/0032-react-native-on-the-gtk-host.md).
12
+
13
+ > **Status: the P1 surface.** All three layers the ADR describes exist — the style
14
+ > partition (`@gjsify/gtk-host/style`), the framework-agnostic primitive descriptors
15
+ > (`./primitives`), and the framework components, in **two** bindings: React at the
16
+ > package root and Solid at `@gjsify/react-native/solid`. Seven primitives and four
17
+ > APIs are implemented, each with its limits written out below. Everything else is a
18
+ > loud refusal. Read the table before pointing an application at this.
19
+
20
+ ## The support table is the contract
21
+
22
+ One file, `src/support-table.ts`, gives every React Native export a status and a
23
+ one-line reason. Three readers share it and none of them keeps a copy:
24
+
25
+ - the **bundler gate** fails a build on an import that is not supported,
26
+ - the **runtime** throws the same sentence for anything reached dynamically,
27
+ - the **section below is generated from it** — do not edit it by hand.
28
+
29
+ `scripts/check-rn-surface.mjs` holds the key set against react-native's own
30
+ `index.js`. It always compares against a committed snapshot, and additionally against
31
+ a real `react-native` install when one is resolvable — and it prints which of the two
32
+ it did, because a gate that silently degrades to the weaker half is worse than one
33
+ that has only the weaker half.
34
+
35
+ ## Getting a window
36
+
37
+ ```ts
38
+ import { registerRootComponent } from '@gjsify/react-native';
39
+ import App from './App.js';
40
+
41
+ await registerRootComponent(App, { applicationId: 'org.example.App', title: 'Example' });
42
+ ```
43
+
44
+ `applicationId` is required, and it is the one declared divergence from React
45
+ Native: `AppRegistry.runApplication` there is handed a root tag by a host that
46
+ already exists, while on a desktop **the application is the host**. That limit is in
47
+ the table rather than only here.
48
+
49
+ ## Three layers, and where each one lives
50
+
51
+ | layer | where | knows about |
52
+ |---|---|---|
53
+ | L1 — the style partition | `@gjsify/gtk-host/style` | GTK property names, GTK CSS, ParamSpec coercion. No framework, no React Native. |
54
+ | L2 — the primitive descriptors | `./primitives` (`primitives.resolvePrimitive`) | which widget a primitive becomes, and where each prop goes. **No React.** |
55
+ | L3 — the components | the package root (React), `./solid` (Solid) | `createElement` / signals, the parent-context carrier. Two lines each. |
56
+
57
+ L2 is exported (`import { primitives } from '@gjsify/react-native'`) so any binding
58
+ can render the same vocabulary without going through the React components.
59
+
60
+ ### The split is measured, not asserted
61
+
62
+ `@gjsify/react-native/solid` exports the same seven primitives as SolidJS components
63
+ over the **same** L2, and `src/solid/solid.spec.ts` renders one authored tree — held
64
+ in neither framework's spelling — through React's reconciler and through Solid's
65
+ non-reconciler, then asserts the two GTK widget trees are identical: widget types,
66
+ `css-classes` including the generated class name, and every probed property, at every
67
+ depth. Solid was chosen because it has no VDOM and no reconciler, so "L1 and L2
68
+ secretly depend on React" cannot survive it.
69
+
70
+ ```ts
71
+ import { mount, View, Text } from '@gjsify/react-native/solid';
72
+
73
+ const dispose = mount(() => <View className="p-2"><Text>hello</Text></View>, window);
74
+ ```
75
+
76
+ `solid-js` is an OPTIONAL peer: nothing in the React path imports it, and nothing in
77
+ the Solid path imports React.
78
+
79
+ Two things the Solid binding does differently, both consequences of a framework that
80
+ builds a tree bottom-up and never re-renders a subtree, and neither of them a change
81
+ to L2:
82
+
83
+ - **children must arrive lazily** — `get children() { … }`, which is what every Solid
84
+ JSX compiler emits. An eagerly built child resolves outside its parent's context
85
+ and would silently lose `flex-1` and any inherited alignment, so it is a named
86
+ refusal.
87
+ - **a reactive update may not change the WIDGET.** `multiline` swapping `Gtk.Entry`
88
+ for `Gtk.TextView` is fine on first render and refused as an update: a Solid
89
+ element is created once, and there is no commit that could replace it.
90
+
91
+ ## The token scales come from the project
92
+
93
+ ADR 0032 § 3: the class FAMILIES are declared in `@gjsify/gtk-host/style`, the VALUES
94
+ belong to the project. Nothing reads a Tailwind config at runtime, so hand them in
95
+ once, before the first render:
96
+
97
+ ```ts
98
+ import { configureStyle } from '@gjsify/react-native';
99
+ import tokens from './design-tokens.json' with { type: 'json' };
100
+
101
+ configureStyle({ tokens });
102
+ ```
103
+
104
+ Without it the default is `MINIMAL_TOKENS`, which is deliberately tiny — so the first
105
+ `className="mt-2xs"` is a named error listing what the scale does hold, rather than a
106
+ margin resolved against a value nobody chose.
107
+
108
+ ## What the style layer refuses, and why that is the feature
109
+
110
+ An unknown utility, an unmapped prop, a combination GTK cannot express: every one is
111
+ a named error saying what arrived, why GTK has no answer, and what to write instead.
112
+ The reason is not strictness for its own sake — GTK's failure mode is **exit 0**.
113
+ `box.orientation = 'vertical'` keeps HORIZONTAL with no diagnostic; a CSS property
114
+ GTK does not know is dropped by its parser in silence; a prop this layer ignored is
115
+ indistinguishable from a bug in the application, forever.
116
+
117
+ A few that are worth knowing before they surprise you:
118
+
119
+ - **`justify-between`** is refused. ADR 0032 § 6 maps it to `Gtk.CenterBox`, and
120
+ `Gtk.CenterBox` installs no `remove` method (measured), which the host's `slotted`
121
+ placement policy requires. Use a `flex-1` spacer or `gap-*` until the policy grows
122
+ a shape for it.
123
+ - **`active:`** is the only variant idiom that pays off, and it costs nothing: it
124
+ becomes a GTK CSS `:active` pseudo-class on the generated class, so GTK animates a
125
+ press with no re-render at all. A variant on a WIDGET property (`active:flex-1`) is
126
+ refused — GTK has no pseudo-class form of one.
127
+ - **`<Modal>`** is not implemented, and not for lack of a mapping. An `Adw.Dialog` is
128
+ PRESENTED against a parent, never parented by it: `box.append(dialog)` calls
129
+ `g_error()` — SIGABRT and a core dump, measured. It needs a portal seam in the
130
+ host, so it stays a refusing export instead of a `partial` that kills the process.
131
+
132
+ ## Support
133
+
134
+ <!-- BEGIN generated support table -->
135
+
136
+ ### Supported (3)
137
+
138
+ | export | tier | GTK | why |
139
+ |---|---|---|---|
140
+ | `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. |
141
+ | `EventEmitter` | — | — | Pure JavaScript; nothing in it touches a platform. |
142
+ | `unstable_batchedUpdates` | — | — | React 19 batches automatically; this is the identity call it already is upstream. |
143
+
144
+ ### Supported, with named limits (11)
145
+
146
+ | export | tier | GTK | why |
147
+ |---|---|---|---|
148
+ | `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. |
149
+ | `Text` | P1 | Gtk.Label | Wrapping is ON by default in React Native and OFF on a Gtk.Label, so the default is set explicitly. |
150
+ | `Pressable` | P1 | Gtk.Button (flat) | Press state is a GTK CSS :active pseudo-class; children-as-a-function is P2. |
151
+ | `ScrollView` | P1 | Gtk.ScrolledWindow + an implicit content box | contentContainerStyle styles the inner box, which is a second styleable node. |
152
+ | `ActivityIndicator` | P1 | Adw.Spinner | Direct counterpart. |
153
+ | `TextInput` | P1 | Gtk.Entry / Gtk.TextView | Single- versus multi-line is one prop in React Native and two different widgets in GTK. |
154
+ | `Linking` | P1 | Gtk.UriLauncher | openURL and canOpenURL only. |
155
+ | `Switch` | P1 | Gtk.Switch | Direct counterpart. |
156
+ | `Platform` | P1 | — | OS is "linux" \| "macos" \| "windows"; select() picks the default branch. |
157
+ | `Share` | P1 | Gdk.Clipboard | No desktop share sheet worth pretending about; copying the link is the honest mapping. |
158
+ | `AppRegistry` | P1 | Adw.Application + Adw.ApplicationWindow | The entry point. Nothing renders without a window, so this is P1 despite being a shim. |
159
+
160
+ ### Planned (43)
161
+
162
+ | export | tier | GTK | why |
163
+ |---|---|---|---|
164
+ | `Modal` | P1 | Adw.Dialog | An Adw.Dialog cannot be an ordinary element. MEASURED on libadwaita 1.10: 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. |
165
+ | `StyleSheet` | P1 | — | create/flatten/hairlineWidth/absoluteFill. Style objects go through the same partition as classes. |
166
+ | `FlatList` | P2 | Gtk.ListView + Gio.ListStore | GTK virtualises for real, so this fits better here than it does on the web. |
167
+ | `SectionList` | P2 | Gtk.ListView + a section model | Sections map onto GTK section models. |
168
+ | `VirtualizedList` | P2 | Gtk.ListView | Its public surface is wide and mostly not worth honouring literally; the useful subset backs FlatList. |
169
+ | `VirtualizedSectionList` | P2 | Gtk.ListView | The section-shaped sibling of VirtualizedList. |
170
+ | `Image` | P2 | Gtk.Picture / Gdk.Texture | resizeMode becomes content-fit. |
171
+ | `ImageBackground` | P2 | Gtk.Picture in a Gtk.Overlay | A picture with children over it. |
172
+ | `TouchableOpacity` | P2 | Gtk.Button (flat) | The same machinery as Pressable, and nearly free once it exists. |
173
+ | `TouchableHighlight` | P2 | Gtk.Button (flat) | As TouchableOpacity, with a different pressed style. |
174
+ | `TouchableWithoutFeedback` | P2 | Gtk.GestureClick | A gesture controller on the child, with no button chrome. |
175
+ | `Button` | P2 | Gtk.Button | The one component whose React Native styling story is "you cannot", which GTK agrees with. |
176
+ | `Dimensions` | P2 | Gdk.Surface | Window size, not screen size — a desktop app is not full-screen. |
177
+ | `useWindowDimensions` | P2 | Gdk.Surface | The hook form of Dimensions, re-rendering on resize. |
178
+ | `Alert` | P2 | Adw.AlertDialog | Direct counterpart. |
179
+ | `Appearance` | P2 | Adw.StyleManager | The imperative sibling of useColorScheme. |
180
+ | `AppState` | P3 | Gtk.Application / Gdk.Surface state | active/background from window focus and visibility. |
181
+ | `PixelRatio` | P3 | Gdk.Surface.scale-factor | The scale factor of the surface the widget is on. |
182
+ | `PlatformColor` | P3 | Adwaita named colours | Maps unusually well — GTK’s palette is exactly this idea. |
183
+ | `AccessibilityInfo` | P3 | Gtk.Accessible / AT-SPI | The highest-value P3 entry: GTK’s accessibility model is strong and the props map onto it well. |
184
+ | `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. |
185
+ | `Easing` | P3 | — | Pure maths; it lands with Animated or not at all. |
186
+ | `LayoutAnimation` | P3 | — | Needs an animated layout pass, which is the same subsystem as Animated. |
187
+ | `InteractionManager` | P3 | — | Deferring work until interactions settle; a main-loop idle source is the counterpart. |
188
+ | `useAnimatedValue` | P3 | — | Part of the Animated subsystem. |
189
+ | `useAnimatedValueXY` | P3 | — | Part of the Animated subsystem. |
190
+ | `useAnimatedColor` | P3 | — | Part of the Animated subsystem. |
191
+ | `PanResponder` | P3 | Gtk.Gesture* controllers | The controllers exist; the arbitration model is not React Native’s, so this is its own project. |
192
+ | `usePressability` | P3 | — | The hook behind the Touchable family; it lands with the gesture work. |
193
+ | `DrawerLayoutAndroid` | P3 | Adw.OverlaySplitView | The pattern survives on a desktop even though the component is Android-only. |
194
+ | `I18nManager` | P3 | Gtk.Widget.direction | RTL is a widget-direction question on GTK. |
195
+ | `ToastAndroid` | P3 | Adw.Toast | Android-only by name, and Adwaita has the exact widget. |
196
+ | `TouchableNativeFeedback` | P3 | Gtk.Button | Android-only ripple; shimmed to its portable sibling. |
197
+ | `ActionSheetIOS` | P3 | Adw.AlertDialog with responses | iOS-only by name; the pattern is a dialog with choices. |
198
+ | `Clipboard` | P3 | Gdk.Clipboard | Deprecated upstream in favour of a community package, but trivial here. |
199
+ | `BackHandler` | P3 | — | An Android hardware back button. Maps to the navigation view’s own back, so it lands with routing. |
200
+ | `DynamicColorIOS` | P3 | — | A light/dark colour pair; the Adwaita scheme already provides the switch. |
201
+ | `processColor` | P3 | — | Colour string to a platform value; a Gdk.RGBA on this side. |
202
+ | `UTFSequence` | P3 | — | A table of unicode constants. Pure data, no platform in it. |
203
+ | `ReactNativeVersion` | P3 | — | The version this layer targets, reported honestly rather than spoofed. |
204
+ | `ProgressBarAndroid` | P3 | Gtk.ProgressBar | Android-only by name; GTK has the widget. |
205
+ | `NativeEventEmitter` | P3 | — | It would construct and subscribe, but nothing native would ever emit into it — shipping that needs a decision, not a class. |
206
+ | `DeviceEventEmitter` | P3 | — | The global emitter. Lands with NativeEventEmitter, and for the same reason. |
207
+
208
+ ### No meaning on a desktop window (10)
209
+
210
+ | export | tier | GTK | why |
211
+ |---|---|---|---|
212
+ | `SafeAreaView` | P2 | — | Insets are zero on a desktop window, but it has to exist to be imported. |
213
+ | `StatusBar` | P2 | — | A desktop window has no status bar to configure. |
214
+ | `KeyboardAvoidingView` | P2 | — | No on-screen keyboard eats a desktop window layout. |
215
+ | `Keyboard` | P2 | — | Its events are on-screen-keyboard events, which do not occur. |
216
+ | `LogBox` | P3 | — | A development overlay for a phone; the console is the desktop equivalent. |
217
+ | `Systrace` | — | — | Android systrace has no desktop counterpart. |
218
+ | `Vibration` | — | — | A desktop machine does not vibrate. |
219
+ | `InputAccessoryView` | — | — | An iOS keyboard accessory bar; there is no keyboard to accessorise. |
220
+ | `DevMenu` | — | — | The shake-to-open developer menu. |
221
+ | `DevSettings` | — | — | Development-client settings for a phone runtime. |
222
+
223
+ ### Refused (25)
224
+
225
+ | export | tier | GTK | why |
226
+ |---|---|---|---|
227
+ | `RefreshControl` | — | — | GTK has no pull-to-refresh idiom and should not grow one. Give the desktop build a refresh action instead. |
228
+ | `PushNotificationIOS` | — | — | Platform notification plumbing. A desktop app uses Gio.Notification directly. |
229
+ | `PermissionsAndroid` | — | — | Android runtime permissions have no desktop counterpart; portals are asked for at use time. |
230
+ | `Settings` | — | — | An iOS user-defaults bridge. GSettings is the desktop answer and is not this API. |
231
+ | `experimental_LayoutConformance` | — | — | An experimental switch between two React Native layout implementations. Neither is used here. |
232
+ | `unstable_VirtualView` | — | — | Unstable React Native internal. |
233
+ | `VirtualViewMode` | — | — | Unstable React Native internal. |
234
+ | `unstable_NativeText` | — | — | Unstable React Native internal. |
235
+ | `unstable_NativeView` | — | — | Unstable React Native internal. |
236
+ | `unstable_TextAncestorContext` | — | — | Unstable React Native internal. |
237
+ | `DeviceInfo` | — | — | A native module surface describing a phone. |
238
+ | `NativeModules` | — | — | The native-module bridge. There is no bridge here; this layer renders in-process onto GTK. |
239
+ | `TurboModuleRegistry` | — | — | The TurboModule lookup. Same reason as NativeModules. |
240
+ | `NativeComponentRegistry` | — | — | Fabric component registration. The host owns widget creation. |
241
+ | `requireNativeComponent` | — | — | Looks up a native view manager. Write a GTK widget descriptor instead. |
242
+ | `codegenNativeComponent` | — | — | React Native codegen for Fabric components. |
243
+ | `codegenNativeCommands` | — | — | React Native codegen for Fabric commands. |
244
+ | `UIManager` | — | — | The legacy view-manager surface. The GTK host is the view manager here. |
245
+ | `findNodeHandle` | — | — | Returns a native view tag. A ref here is the Gtk.Widget itself, which is more useful. |
246
+ | `registerCallableModule` | — | — | Registers a module callable from the native side. There is no native side. |
247
+ | `Networking` | — | — | React Native’s XHR internals. Use fetch, which gjsify provides. |
248
+ | `NativeDialogManagerAndroid` | — | — | An Android dialog native module. Alert is the portable spelling. |
249
+ | `Touchable` | — | — | The legacy mixin behind the Touchable family, not a public component. |
250
+ | `NativeAppEventEmitter` | — | — | The legacy iOS app-event emitter. |
251
+ | `RootTagContext` | — | — | A React Native surface identifier. This layer has one root per Adw window. |
252
+
253
+ <!-- END generated support table -->
@@ -0,0 +1 @@
1
+ var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0}),__exportAll=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r};export{__exportAll,__name};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"../primitives/errors.js";import t from"gi://Adw?version=1";function manager(){let n=t.StyleManager.get_default();if(n===null)throw new e(`useColorScheme`,``,"needs `Adw.StyleManager.get_default()`, which answers null before libadwaita is initialised. Construct the application first — `runAdwaitaApp` and `AppRegistry.runApplication` both do it");return n}const currentColorScheme=()=>manager().dark?`dark`:`light`;function onColorSchemeChange(e){let t=manager(),n=t.connect(`notify::dark`,()=>{e(t.dark?`dark`:`light`)});return()=>t.disconnect(n)}export{currentColorScheme,onColorSchemeChange};
@@ -0,0 +1 @@
1
+ import{currentColorScheme as e,onColorSchemeChange as t}from"./color-scheme.js";import{Linking as n}from"./linking.js";import{Platform as r,resetPlatformCache as i}from"./platform.js";import{Share as a}from"./share.js";export{n as Linking,r as Platform,a as Share,e as currentColorScheme,t as onColorSchemeChange,i as resetPlatformCache};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"../primitives/errors.js";import t from"gi://Gtk?version=4.0";const n="delivers a URL to a running application, and on a desktop that path is `Gio.Application`’s `open` signal with `HANDLES_OPEN` in the application flags — the APPLICATION’s own wiring, above this layer, because the application object is what receives it. Connect to it where you construct the app",r={async openURL(n){let r=new t.UriLauncher({uri:n});if(!r.can_launch(null))throw new e(`Linking`,`openURL`,`has no application registered for "${n}". GTK’s own launch call does not report this — measured, the callback never fires for an unhandled scheme — so the check happens before it rather than after`);if(!await new Promise((e,t)=>{r.launch(null,null,(n,i)=>{try{e(r.launch_finish(i))}catch(e){t(e instanceof Error?e:Error(String(e)))}})}))throw new e(`Linking`,`openURL`,`GTK declined to launch "${n}" and gave no error`)},canOpenURL(e){return Promise.resolve(new t.UriLauncher({uri:e}).can_launch(null))},getInitialURL(){return Promise.resolve(null)},addEventListener(){throw new e(`Linking`,`addEventListener`,n)},addListener(){throw new e(`Linking`,`addListener`,n)},removeEventListener(){throw new e(`Linking`,`removeEventListener`,n)},openSettings(){throw new e(`Linking`,`openSettings`,`opens the per-app settings page of a phone OS. A desktop application has no such page — GNOME Settings has no per-app section a program can deep-link into — so there is nothing to open`)},sendIntent(){throw new e(`Linking`,`sendIntent`,"sends an Android Intent. The desktop counterpart of that idea is a D-Bus activation or a `Gio.AppInfo` launch, and neither takes an Intent’s shape")}};export{r as Linking};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"../primitives/errors.js";const t={linux:`linux`,darwin:`macos`,win32:`windows`};let n=null;function hostOs(){if(n!==null)return n;let r=typeof process>`u`?void 0:process.platform;if(typeof r!=`string`)throw new e(`Platform`,`OS`,"cannot be answered: there is no `process.platform` in this runtime. Under GJS it is supplied by gjsify’s injected globals, so a bundle built with `--globals none` has to declare `Platform.OS` itself");let i=t[r];if(i===void 0)throw new e(`Platform`,`OS`,`runs on "${r}", which is outside the three operating systems ADR 0018 declares as the target set (linux, darwin, win32). Reporting one of the three anyway would make every \`Platform.select\` in the application wrong in a way nothing can detect`);return n=i,i}const r={get OS(){return hostOs()},select(t){let n=hostOs();if(n in t)return t[n];if(`default`in t)return t.default;throw new e(`Platform`,`select`,`has no branch for "${n}" and no \`default\`. It was given: ${Object.keys(t).sort().join(`, `)||`(nothing)`}. A \`native\` branch is not consulted here — it is written for a React Native runtime and this is not one (ADR 0032 § 9) — so add a \`default\``)},isTV:!1,isTesting:!1,get Version(){throw new e(`Platform`,`Version`,"is React Native’s MOBILE OS version — an Android API level or an iOS release — and a desktop has no counterpart that means the same thing. The GTK and libadwaita versions are the numbers that actually gate behaviour here, and they are `Gtk.get_minor_version()` / `Adw.get_minor_version()`, not a platform version")},get constants(){throw new e(`Platform`,`constants`,`is the native bridge’s constants object. There is no bridge here — this layer renders in-process onto GTK — so there is nothing to read it from, and a shim would be lying about a native module being present`)}},resetPlatformCache=()=>{n=null};export{r as Platform,resetPlatformCache};
@@ -0,0 +1,2 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"../primitives/errors.js";import t from"gi://Gdk?version=4.0";const n={sharedAction:`sharedAction`,dismissedAction:`dismissedAction`,share(r){let i=[r.message,r.url].filter(e=>typeof e==`string`&&e!==``);if(i.length===0)throw new e(`Share`,`share`,"was given neither `message` nor `url`. There is nothing to put on the clipboard, and writing an empty string there would DISCARD whatever the user had copied");let a=t.Display.get_default();if(a===null)throw new e(`Share`,`share`,"needs a `Gdk.Display` to reach the clipboard, and there is none — this ran before `Gtk.init()` or outside a session");return a.get_clipboard().set(i.join(`
2
+ `)),Promise.resolve({action:n.sharedAction})}};export{n as Share};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{UnsupportedError as e}from"./unsupported.js";import t from"gi://Adw?version=1";import n from"gi://Gtk?version=4.0";import{runAdwaitaApp as r}from"@gjsify/adwaita-app";import{createRoot as i}from"@gjsify/gtk-host/react";import{createElement as a}from"react";const o=new Map;function buildWindow(e,r,i){let a=new t.ApplicationWindow({application:e,title:i.title??r,defaultWidth:i.defaultWidth??900,defaultHeight:i.defaultHeight??700}),o=new t.ToolbarView;o.add_top_bar(new t.HeaderBar);let s=new n.Box({orientation:n.Orientation.VERTICAL});return o.set_content(s),a.set_content(o),{window:a,content:s}}const s={registerComponent(e,t){return o.set(e,{provider:t}),e},getAppKeys(){return[...o.keys()]},getRunnable(e){return o.get(e)},async runApplication(e,t){let n=o.get(e);if(n===void 0){let t=[...o.keys()];throw Error(`@gjsify/react-native: no component is registered as "${e}". `+(t.length>0?`Registered: ${t.join(`, `)}.`:`Nothing is registered — call AppRegistry.registerComponent(key, () => Component) first.`))}let s={root:null},c=await r({applicationId:t.applicationId,css:t.css,createWindow:r=>{let{window:o,content:c}=buildWindow(r,e,t),l=n.provider();return s.root=i(c),s.root.render(a(l,t.initialProps??{})),o}});return s.root?.unmount(),c},unmountApplicationComponentAtRootTag(){throw new e(`AppRegistry`)}};function registerRootComponent(e,t){return s.registerComponent(`main`,()=>e),s.runApplication(`main`,t)}export{s as AppRegistry,registerRootComponent};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"./primitives/errors.js";import{declaresAbsolute as t,resolvePrimitive as n}from"./primitives/resolve.js";import{styleConfig as r}from"./style-config.js";import{Children as i,createContext as a,createElement as o,isValidElement as s,useContext as c,useMemo as l,useRef as u}from"react";const d=a(null),accessor=e=>e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase()),isTextNode=e=>typeof e==`string`||typeof e==`number`;function isAbsoluteChild(e,n){if(!s(e))return!1;try{return t(e.props,n)}catch{return!1}}function childFacts(e,t){let n=0,r=!1;for(let i of e)isTextNode(i)?r=!0:isAbsoluteChild(i,t)&&n++;return{absolute:n,count:e.length,text:r}}function useSignals(e,t){let n=u(null),r=u(t);return r.current=t,{props:l(()=>{let t={};for(let i of e)t[`on:${i.signal}`]=()=>{let e=r.current[i.prop];if(typeof e!=`function`)return;if(i.read===null){e();return}let t=n.current;e(t===null?void 0:t[accessor(i.read)])};return t},[e.map(e=>`${e.prop}>${e.signal}>${e.read??``}`).join(`|`)]),widgetRef:n}}function nodeProps(e,t,n){let r={...t,...e.props,...n};return e.cssClasses.length>0&&(r[`css-classes`]=[...e.cssClasses]),r}function usePlan(t,a){let o=a,s=c(d),u=r(),f=i.toArray(o.children),p=n(t,o,{tokens:u.tokens,sheet:u.sheet,...s===null?{}:{parent:s},children:childFacts(f,u.tokens)}),m=Object.keys(p.intent);if(m.length>0)throw new e(t,m.join(`, `),"carries layout that cannot be resolved at this position. These need a parent to resolve against — `flex-1` and `self-*` need the parent orientation, `absolute` needs the parent to be an overlay — and this element is the root of its tree, or its parent is not a box. Wrap it in a <View>, or move the utility to a child.");let h=useSignals(p.events,o),g=o.ref,_=l(()=>e=>{h.widgetRef.current=e,typeof g==`function`?g(e):g!=null&&(g.current=e)},[g,h.widgetRef]),v={...h.props,ref:_};p.slot!==null&&(v.slot=p.slot);let y=l(()=>p.childContext,[JSON.stringify(p.childContext),p.childContext]);return{plan:p,children:f,inherited:s?.props??{},extra:v,published:y,tokens:u.tokens}}function render(e){let{plan:t,children:n,inherited:r,extra:i,published:a,tokens:s}=e,wrap=e=>o(d.Provider,{value:a},...e);if(t.content===null){let e=n.some(isTextNode)?n:[wrap(n)];return o(t.node.tag,nodeProps(t.node,r,i),...e)}let c=t.absoluteSlot===null?[]:n.filter(e=>isAbsoluteChild(e,s)),l=t.absoluteSlot===null?n:n.filter(e=>!isAbsoluteChild(e,s)),u=o(t.content.tag,nodeProps(t.content,{},{}),wrap(l));return o(t.node.tag,nodeProps(t.node,r,i),u,...c.length===0?[]:[wrap(c)])}function View(e){return render(usePlan(`View`,e))}function Text(e){return render(usePlan(`Text`,e))}function Pressable(t){if(typeof t.children==`function`)throw new e(`Pressable`,`children`,'was given a function. Children-as-a-function-of-`{ pressed }` is not implemented (ADR 0032 § 7) — the press state is the GTK CSS `:active` pseudo-class, so write `className="active:opacity-70"` and GTK animates it with no re-render at all. A function child would otherwise render as nothing');return render(usePlan(`Pressable`,t))}function ScrollView(e){return render(usePlan(`ScrollView`,e))}function ActivityIndicator(e){return render(usePlan(`ActivityIndicator`,e))}function TextInput(e){return render(usePlan(`TextInput`,e))}function Switch(e){return render(usePlan(`Switch`,e))}export{ActivityIndicator,Pressable,ScrollView,Switch,Text,TextInput,View};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";var EventEmitter=class{#e=new Map;addListener(e,t,n){let r={listener:t,context:n,removed:!1},i=this.#e.get(e);return i===void 0?this.#e.set(e,[r]):i.push(r),{remove:()=>{if(r.removed)return;r.removed=!0;let t=this.#e.get(e);if(t===void 0)return;let n=t.indexOf(r);n!==-1&&t.splice(n,1),t.length===0&&this.#e.delete(e)}}}emit(e,...t){let n=this.#e.get(e);if(!(n===void 0||n.length===0))for(let e of n.slice())e.removed||e.listener.apply(e.context,[...t])}removeAllListeners(e){if(e===void 0){for(let e of this.#e.values())for(let t of e)t.removed=!0;this.#e.clear();return}let t=this.#e.get(e);if(t!==void 0){for(let e of t)e.removed=!0;this.#e.delete(e)}}listenerCount(e){return this.#e.get(e)?.length??0}};export{EventEmitter};
@@ -0,0 +1 @@
1
+ import{unsupported as e}from"../unsupported.js";const t=e(`Modal`),n=e(`StyleSheet`),r=e(`FlatList`),i=e(`SectionList`),a=e(`VirtualizedList`),o=e(`VirtualizedSectionList`),s=e(`Image`),c=e(`ImageBackground`),l=e(`TouchableOpacity`),u=e(`TouchableHighlight`),d=e(`TouchableWithoutFeedback`),f=e(`Button`),p=e(`Dimensions`),m=e(`useWindowDimensions`),h=e(`Alert`),g=e(`Appearance`),_=e(`SafeAreaView`),v=e(`StatusBar`),y=e(`KeyboardAvoidingView`),b=e(`Keyboard`),x=e(`RefreshControl`),S=e(`AppState`),C=e(`PixelRatio`),w=e(`PlatformColor`),T=e(`AccessibilityInfo`),E=e(`Animated`),D=e(`Easing`),O=e(`LayoutAnimation`),k=e(`InteractionManager`),A=e(`useAnimatedValue`),j=e(`useAnimatedValueXY`),M=e(`useAnimatedColor`),N=e(`PanResponder`),P=e(`usePressability`),F=e(`DrawerLayoutAndroid`),I=e(`I18nManager`),L=e(`LogBox`),R=e(`Systrace`),z=e(`Vibration`),B=e(`ToastAndroid`),V=e(`InputAccessoryView`),H=e(`TouchableNativeFeedback`),U=e(`ActionSheetIOS`),W=e(`PushNotificationIOS`),G=e(`PermissionsAndroid`),K=e(`Settings`),q=e(`Clipboard`),J=e(`BackHandler`),Y=e(`DynamicColorIOS`),X=e(`processColor`),Z=e(`UTFSequence`),Q=e(`experimental_LayoutConformance`),$=e(`unstable_VirtualView`),ee=e(`VirtualViewMode`),te=e(`unstable_NativeText`),ne=e(`unstable_NativeView`),re=e(`unstable_TextAncestorContext`),ie=e(`ReactNativeVersion`),ae=e(`DeviceInfo`),oe=e(`DevMenu`),se=e(`DevSettings`),ce=e(`NativeModules`),le=e(`TurboModuleRegistry`),ue=e(`NativeComponentRegistry`),de=e(`requireNativeComponent`),fe=e(`codegenNativeComponent`),pe=e(`codegenNativeCommands`),me=e(`UIManager`),he=e(`findNodeHandle`),ge=e(`registerCallableModule`),_e=e(`Networking`),ve=e(`NativeDialogManagerAndroid`),ye=e(`ProgressBarAndroid`),be=e(`Touchable`),xe=e(`NativeEventEmitter`),Se=e(`DeviceEventEmitter`),Ce=e(`NativeAppEventEmitter`),we=e(`RootTagContext`);export{T as AccessibilityInfo,U as ActionSheetIOS,h as Alert,E as Animated,S as AppState,g as Appearance,J as BackHandler,f as Button,q as Clipboard,oe as DevMenu,se as DevSettings,Se as DeviceEventEmitter,ae as DeviceInfo,p as Dimensions,F as DrawerLayoutAndroid,Y as DynamicColorIOS,D as Easing,r as FlatList,I as I18nManager,s as Image,c as ImageBackground,V as InputAccessoryView,k as InteractionManager,b as Keyboard,y as KeyboardAvoidingView,O as LayoutAnimation,L as LogBox,t as Modal,Ce as NativeAppEventEmitter,ue as NativeComponentRegistry,ve as NativeDialogManagerAndroid,xe as NativeEventEmitter,ce as NativeModules,_e as Networking,N as PanResponder,G as PermissionsAndroid,C as PixelRatio,w as PlatformColor,ye as ProgressBarAndroid,W as PushNotificationIOS,ie as ReactNativeVersion,x as RefreshControl,we as RootTagContext,_ as SafeAreaView,i as SectionList,K as Settings,v as StatusBar,n as StyleSheet,R as Systrace,B as ToastAndroid,be as Touchable,u as TouchableHighlight,H as TouchableNativeFeedback,l as TouchableOpacity,d as TouchableWithoutFeedback,le as TurboModuleRegistry,me as UIManager,Z as UTFSequence,z as Vibration,ee as VirtualViewMode,a as VirtualizedList,o as VirtualizedSectionList,pe as codegenNativeCommands,fe as codegenNativeComponent,Q as experimental_LayoutConformance,he as findNodeHandle,X as processColor,ge as registerCallableModule,de as requireNativeComponent,te as unstable_NativeText,ne as unstable_NativeView,re as unstable_TextAncestorContext,$ as unstable_VirtualView,M as useAnimatedColor,A as useAnimatedValue,j as useAnimatedValueXY,P as usePressability,m as useWindowDimensions};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{currentColorScheme as e,onColorSchemeChange as t}from"./apis/color-scheme.js";import{useSyncExternalStore as n}from"react";function useColorScheme(){return n(subscribe,e,e)}const subscribe=e=>t(()=>e());export{useColorScheme};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"./primitives/errors.js";import{Linking as t}from"./apis/linking.js";import{Platform as n}from"./apis/platform.js";import{Share as r}from"./apis/share.js";import"./apis/index.js";import{SUPPORTED_NAMES as i,SUPPORT_TABLE as a,explainUnsupported as o,isImportable as s}from"./support-table.js";import{UnsupportedError as c}from"./unsupported.js";import{AppRegistry as l,registerRootComponent as u}from"./app-registry.js";import{configureStyle as d,resetStyleConfig as f,styleConfig as p}from"./style-config.js";import{ActivityIndicator as m,Pressable as h,ScrollView as g,Switch as _,Text as v,TextInput as y,View as b}from"./components.js";import{EventEmitter as x}from"./event-emitter.js";import{AccessibilityInfo as S,ActionSheetIOS as C,Alert as w,Animated as T,AppState as E,Appearance as D,BackHandler as O,Button as k,Clipboard as A,DevMenu as j,DevSettings as M,DeviceEventEmitter as N,DeviceInfo as P,Dimensions as F,DrawerLayoutAndroid as I,DynamicColorIOS as L,Easing as R,FlatList as z,I18nManager as B,Image as V,ImageBackground as H,InputAccessoryView as U,InteractionManager as W,Keyboard as G,KeyboardAvoidingView as K,LayoutAnimation as q,LogBox as J,Modal as Y,NativeAppEventEmitter as X,NativeComponentRegistry as Z,NativeDialogManagerAndroid as Q,NativeEventEmitter as $,NativeModules as ee,Networking as te,PanResponder as ne,PermissionsAndroid as re,PixelRatio as ie,PlatformColor as ae,ProgressBarAndroid as oe,PushNotificationIOS as se,ReactNativeVersion as ce,RefreshControl as le,RootTagContext as ue,SafeAreaView as de,SectionList as fe,Settings as pe,StatusBar as me,StyleSheet as he,Systrace as ge,ToastAndroid as _e,Touchable as ve,TouchableHighlight as ye,TouchableNativeFeedback as be,TouchableOpacity as xe,TouchableWithoutFeedback as Se,TurboModuleRegistry as Ce,UIManager as we,UTFSequence as Te,Vibration as Ee,VirtualViewMode as De,VirtualizedList as Oe,VirtualizedSectionList as ke,codegenNativeCommands as Ae,codegenNativeComponent as je,experimental_LayoutConformance as Me,findNodeHandle as Ne,processColor as Pe,registerCallableModule as Fe,requireNativeComponent as Ie,unstable_NativeText as Le,unstable_NativeView as Re,unstable_TextAncestorContext as ze,unstable_VirtualView as Be,useAnimatedColor as Ve,useAnimatedValue as He,useAnimatedValueXY as Ue,usePressability as We,useWindowDimensions as Ge}from"./generated/unsupported-exports.js";import{useColorScheme as Ke}from"./hooks.js";import{primitives_exports as qe}from"./primitives/index.js";function unstable_batchedUpdates(e,t){return e(t)}export{S as AccessibilityInfo,C as ActionSheetIOS,m as ActivityIndicator,w as Alert,T as Animated,l as AppRegistry,E as AppState,D as Appearance,O as BackHandler,k as Button,A as Clipboard,j as DevMenu,M as DevSettings,N as DeviceEventEmitter,P as DeviceInfo,F as Dimensions,I as DrawerLayoutAndroid,L as DynamicColorIOS,R as Easing,x as EventEmitter,z as FlatList,B as I18nManager,V as Image,H as ImageBackground,U as InputAccessoryView,W as InteractionManager,G as Keyboard,K as KeyboardAvoidingView,q as LayoutAnimation,t as Linking,J as LogBox,Y as Modal,X as NativeAppEventEmitter,Z as NativeComponentRegistry,Q as NativeDialogManagerAndroid,$ as NativeEventEmitter,ee as NativeModules,te as Networking,ne as PanResponder,re as PermissionsAndroid,ie as PixelRatio,n as Platform,ae as PlatformColor,h as Pressable,e as PrimitiveError,oe as ProgressBarAndroid,se as PushNotificationIOS,ce as ReactNativeVersion,le as RefreshControl,ue as RootTagContext,i as SUPPORTED_NAMES,a as SUPPORT_TABLE,de as SafeAreaView,g as ScrollView,fe as SectionList,pe as Settings,r as Share,me as StatusBar,he as StyleSheet,_ as Switch,ge as Systrace,v as Text,y as TextInput,_e as ToastAndroid,ve as Touchable,ye as TouchableHighlight,be as TouchableNativeFeedback,xe as TouchableOpacity,Se as TouchableWithoutFeedback,Ce as TurboModuleRegistry,we as UIManager,Te as UTFSequence,c as UnsupportedError,Ee as Vibration,b as View,De as VirtualViewMode,Oe as VirtualizedList,ke as VirtualizedSectionList,Ae as codegenNativeCommands,je as codegenNativeComponent,d as configureStyle,Me as experimental_LayoutConformance,o as explainUnsupported,Ne as findNodeHandle,s as isImportable,qe as primitives,Pe as processColor,Fe as registerCallableModule,u as registerRootComponent,Ie as requireNativeComponent,f as resetStyleConfig,p as styleConfig,Le as unstable_NativeText,Re as unstable_NativeView,ze as unstable_TextAncestorContext,Be as unstable_VirtualView,unstable_batchedUpdates,Ve as useAnimatedColor,He as useAnimatedValue,Ue as useAnimatedValueXY,Ke as useColorScheme,We as usePressability,Ge as useWindowDimensions};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"./errors.js";function splitVariants(t,n){let r=[],i={};for(let a of tokenise(t)){let t=a.indexOf(`:`);if(t===-1){r.push(a);continue}let o=a.slice(0,t),s=a.slice(t+1);if(o===``||s===``)throw new e(n,`className "${a}"`,"is not a variant: the shape is `<variant>:<utility>`, and one half of this one is empty");if(s.includes(`:`))throw new e(n,`className "${a}"`,"stacks variants. A variant becomes ONE GTK CSS pseudo-class on the generated selector, and this layer does not compose them — the measured vocabulary it targets has a single variant and no `dark:` at all, so a stacking implementation would ship untested and a wrong selector is a style that silently does not apply");(i[o]??=[]).push(s)}return{base:r,variants:i}}const tokenise=e=>e==null?[]:(typeof e==`string`?e:e.filter(e=>typeof e==`string`).join(` `)).split(/\s+/).filter(e=>e!==``);export{splitVariants};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";var PrimitiveError=class extends Error{constructor(e,t,n){super(`@gjsify/react-native: <${e}>${t===``?``:` ${t}`} — ${n}`),this.name=`PrimitiveError`,this.primitive=e,this.subject=t}};export{PrimitiveError};
@@ -0,0 +1 @@
1
+ import{__exportAll as e}from"../_virtual/_rolldown/runtime.js";import{PrimitiveError as t}from"./errors.js";import{resolveIntent as n}from"./intents.js";import{splitVariants as r}from"./classes.js";import{flattenStyle as i,mintClass as a,normalise as o,variantDeclarations as s}from"./style.js";import{FRAMEWORK_PROPS as c,PRIMITIVES as l,PRIMITIVE_NAMES as u}from"./table.js";import{declaresAbsolute as d,resolvePrimitive as f}from"./resolve.js";var p=e({FRAMEWORK_PROPS:()=>c,PRIMITIVES:()=>l,PRIMITIVE_NAMES:()=>u,PrimitiveError:()=>t,declaresAbsolute:()=>d,flattenStyle:()=>i,mintClass:()=>a,normalise:()=>o,resolveIntent:()=>n,resolvePrimitive:()=>f,splitVariants:()=>r,variantDeclarations:()=>s});export{c as FRAMEWORK_PROPS,l as PRIMITIVES,u as PRIMITIVE_NAMES,t as PrimitiveError,d as declaresAbsolute,i as flattenStyle,a as mintClass,o as normalise,p as primitives_exports,n as resolveIntent,f as resolvePrimitive,r as splitVariants,s as variantDeclarations};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"./errors.js";const t={"flex-start":`start`,"flex-end":`end`,center:`center`,stretch:`fill`,baseline:`baseline`},n={"flex-start":`start`,"flex-end":`end`,center:`center`},r={left:{xalign:0,justify:`left`},center:{xalign:.5,justify:`center`},right:{xalign:1,justify:`right`},justify:{xalign:0,justify:`fill`}},cross=e=>e===`horizontal`?`valign`:`halign`,main=e=>e===`horizontal`?`halign`:`valign`;function resolveIntent(i){let{primitive:a,intent:o,orientation:s,widget:c,parent:l}=i,u={},d=[],f={},p={},m=null,h=l?.textAlign;if(o.alignChildren!==void 0){if(!c.box)throw new e(a,`items-*`,`aligns CHILDREN, and this primitive has none to align — the widget it becomes is not a box. Move the utility to the container`);f[cross(s)]=t[o.alignChildren]}if(o.distribute!==void 0){if(!c.box)throw new e(a,`justify-*`,`distributes CHILDREN along the main axis, and the widget this primitive becomes is not a box. Move the utility to the container`);let t=n[o.distribute];if(t===void 0)throw new e(a,`justify-${label(o.distribute)}`,"GTK's box has no main-axis justification, and ADR 0032 § 6's mapping for this one is `Gtk.CenterBox`. Measured on gtk 4.22.4, `Gtk.CenterBox` installs NO `remove` method — it clears a slot with `set_center_widget(null)` — and the host's `slotted` policy names a `remove` that `descriptorProblems()` checks exists, so the widget cannot be curated without changing the policy's shape. Until it is, spell the distribution with a spacer child (`flex-1`) or with `gap-*`");u[main(s)]=t}if(o.axisSpacing!==void 0){if(!c.box)throw new e(a,`gap-x-*/gap-y-*`,"is a `Gtk.Box:spacing`, and the widget this primitive becomes has none (measured, gtk-props.ts)");o.axisSpacing.axis===s&&(u.spacing=o.axisSpacing.pixels)}if(o.textAlign!==void 0&&(h=o.textAlign),h!==void 0&&c.alignsText){let e=r[h];u.xalign=e.xalign,u.justify=e.justify,h=void 0}if(o.expand!==void 0&&(l===void 0?p.expand=o.expand:u[l.orientation===`horizontal`?`hexpand`:`vexpand`]=!0),o.alignSelf!==void 0&&(l===void 0?p.alignSelf=o.alignSelf:u[cross(l.orientation)]=t[o.alignSelf]),o.overlay?.role===`child`)if(l===void 0)p.overlay=o.overlay;else if(l.overlay)m=`overlay`,placeAbsolute(a,o.overlay.edges,i.emittedProps,u,d);else throw new e(a,`absolute`,"positions this element on top of its parent, so the PARENT has to be a `Gtk.Overlay` — and it is not. A `View` becomes one as soon as one of its children is absolutely positioned, so the parent here is either not a `View` (a `ScrollView`, a `Pressable`, a `Text`) or the element is a root");return{props:u,css:d,childContext:{orientation:s,props:f,overlay:!1,...h===void 0?{}:{textAlign:h}},slot:m,remaining:p}}function placeAbsolute(t,n,r,i,a){let{top:o,right:s,bottom:c,left:l}=n;if((o!==void 0||c!==void 0)&&(i.valign=o!==void 0&&c!==void 0?`fill`:o===void 0?`end`:`start`,o!==void 0&&(i[`margin-top`]=o),c!==void 0&&(i[`margin-bottom`]=c)),!(l===void 0&&s===void 0)){if(r[`margin-start`]!==void 0||r[`margin-end`]!==void 0)throw new e(t,`absolute + ms-*/me-*`,"offsets a PHYSICAL edge (`left-*`/`right-*`/`inset-*`), which becomes GTK CSS, while `ms-*`/`me-*` become the widget properties `margin-start`/`margin-end`. GTK applies both and they ADD, where CSS would have let one win. Spell the horizontal margin one way");i.halign=l!==void 0&&s!==void 0?`fill`:l===void 0?`end`:`start`,l!==void 0&&a.push(`margin-left: ${l}px`),s!==void 0&&a.push(`margin-right: ${s}px`)}}const label=e=>e.replace(/^space-/,``);export{resolveIntent};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"./errors.js";import{resolveIntent as t}from"./intents.js";import{mintClass as n,normalise as r,partition as i,variantDeclarations as a}from"./style.js";import{FRAMEWORK_PROPS as o,PRIMITIVES as s}from"./table.js";const c=[`orientation`,`spacing`],withOrientationClass=(e,t)=>{if(t.length===0)return t;let n=e.orientation;return typeof n==`string`?[n,...t]:t};function declaresAbsolute(e,t,n=`View`){let{props:a}=r(e,t,n);return i(a).intent.overlay?.role===`child`}function resolvePrimitive(l,u,d){let f=s[l];if(f===void 0)throw new e(l,``,`is not a primitive this layer answers for. Known: ${Object.keys(s).sort().join(`, `)}`);let p=f.switchOn!==void 0&&u[f.switchOn.prop]===!0?f.switchOn.whenTrue:f,m=p.content,h={...p.widgetProps},g={...m?.widgetProps},_={},v=[],y=new Set([m?.styleProp,m?.classNameProp].filter(e=>typeof e==`string`));for(let t of Object.keys(u)){if(o.has(t)||y.has(t))continue;let n=u[t];if(n===void 0)continue;let r=p.props[t];if(r===void 0)throw new e(l,`prop "${t}"`,`is not a prop this primitive answers for. It takes: ${Object.keys(p.props).sort().join(`, `)}. An unlisted prop is refused rather than dropped: a prop that silently does nothing is indistinguishable from a bug in the application, forever`);for(let e of Array.isArray(r)?r:[r])applyRoute(e,t,n,{primitive:l,spec:p,outerProps:h,contentProps:g,styleExtra:_,events:v})}let b=r(u,d.tokens,l),x=i({...b.props,..._}),S=orientationOf(x.props.orientation??h.orientation,p.orientation),C=m===void 0?S:orientationOf(g.orientation,m.orientation),w=t({primitive:l,intent:x.intent,orientation:C,widget:p.widget,...d.parent===void 0?{}:{parent:d.parent},...d.children===void 0?{}:{children:d.children},emittedProps:x.props}),T=n(d.sheet,[...x.css,...w.css],a(b.groups,d.tokens,l));Object.assign(h,x.props,w.props),assertOneTextAuthority(l,p,h,d.children);let E=[...p.cssClasses,...T===null?[]:[T]],D=p.overlayOnAbsoluteChild;if(D!==void 0&&(d.children?.absolute??0)>0){let e={...p.widgetProps};for(let t of c)h[t]!==void 0&&(e[t]=h[t],delete h[t]);return{primitive:l,node:{tag:D.tag,props:h,cssClasses:withOrientationClass(h,E)},content:{tag:p.tag,props:e,cssClasses:[]},slot:w.slot,absoluteSlot:D.slot,events:v,textSink:p.textSink,childContext:{...w.childContext,orientation:C,overlay:!0},intent:w.remaining}}let O=m===void 0?null:resolveContent(m,u,g,d,l);return{primitive:l,node:{tag:p.tag,props:h,cssClasses:withOrientationClass(h,E)},content:O===null?null:O.node,slot:w.slot,absoluteSlot:null,events:v,textSink:p.textSink,childContext:O===null?{...w.childContext,overlay:!1}:{...O.childContext,...O.childContext.textAlign===void 0&&w.childContext.textAlign!==void 0?{textAlign:w.childContext.textAlign}:{},overlay:!1},intent:w.remaining}}function resolveContent(e,o,s,c,l){let u=`${l} ${e.styleProp??`content`}`,d=r({...e.classNameProp===null?{}:{className:o[e.classNameProp]},...e.styleProp===null?{}:{style:o[e.styleProp]}},c.tokens,u),f=i(d.props),p=orientationOf(f.props.orientation??s.orientation,e.orientation),m=t({primitive:u,intent:f.intent,orientation:p,widget:e.widget,parent:{orientation:p,props:{},overlay:!1},emittedProps:f.props}),h=n(c.sheet,[...f.css,...m.css],a(d.groups,c.tokens,u));return Object.assign(s,f.props,m.props),{node:{tag:e.tag,props:s,cssClasses:withOrientationClass(s,h===null?[]:[h])},childContext:{...m.childContext,orientation:p}}}function applyRoute(t,n,r,i){switch(t.to){case`refused`:throw new e(i.primitive,`prop "${n}"`,t.why);case`ignored`:return;case`style-property`:i.styleExtra[t.name]=r;return;case`event`:if(typeof r!=`function`)throw new e(i.primitive,`prop "${n}"`,`binds the GTK signal "${t.signal}" and needs a function; got ${describe(r)}`);i.events.push({prop:n,signal:t.signal,read:t.read??null});return;case`property`:{if(t.on===`content`&&i.spec.content===void 0)throw new e(i.primitive,`prop "${n}"`,`is routed to a content node this primitive does not declare — the table is wrong, not the call`);let a=t.on===`content`?i.contentProps:i.outerProps,o=coerce(t,n,r,i.primitive);for(let e of t.names)a[e]=o;t.also!==void 0&&Object.assign(a,t.also);return}}}function coerce(t,n,r,i){let bad=t=>{throw new e(i,`prop "${n}"`,`expects ${t}; got ${describe(r)}`)};switch(t.as){case`string`:return typeof r==`string`?r:typeof r==`number`||typeof r==`boolean`?String(r):bad(`a string`);case`boolean`:return typeof r==`boolean`?r:bad(`a boolean`);case`not`:return typeof r==`boolean`?!r:bad(`a boolean`);case`int`:return typeof r==`number`&&Number.isFinite(r)?Math.trunc(r):bad(`a number`);case`map`:return lookup(t,n,r,i);case`pixels-or-map`:return typeof r==`number`&&Number.isFinite(r)?Math.trunc(r):lookup(t,n,r,i)}}function lookup(t,n,r,i){let a=t.map??{},o=a[String(r)];if(o!==void 0)return o;throw new e(i,`prop "${n}"`,`has no GTK equivalent for ${describe(r)}. Known: ${Object.keys(a).sort().join(`, `)}. A value absent from that list is absent because GTK has no member for it, not because the table is short`)}function assertOneTextAuthority(t,n,r,i){if(!(n.textSink===null||i?.text!==!0)&&r[n.textSink]!==void 0)throw new e(t,`prop → "${n.textSink}"`,`is the same widget property a text CHILD writes, and both were given. Whichever the reconciler applied last would win, possibly differently on a first render and on an update — so it is refused. Keep one`)}const orientationOf=(e,t)=>e===`horizontal`||e===`vertical`?e:t,describe=e=>typeof e==`string`?`"${e}"`:typeof e==`object`&&e?Object.prototype.toString.call(e):String(e);export{declaresAbsolute,resolvePrimitive};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"./errors.js";import{splitVariants as t}from"./classes.js";import{partition as n,resolveUtilities as r}from"@gjsify/gtk-host/style";function flattenStyle(e){if(e==null||e===!1)return{};if(!Array.isArray(e))return e;let t={};for(let n of e)Object.assign(t,flattenStyle(n));return t}const i=new Set([`flexGrow`,`flexShrink`,`flex`,`opacity`,`fontWeight`,`zIndex`,`aspectRatio`]);function normalise(e,n,i){let a=t(e.className,i),o={...r(a.base,n)};for(let[t,n]of Object.entries(flattenStyle(e.style)))n!=null&&(o[t]=typeof n==`number`?stringify(t,n):n);return{props:o,groups:a}}function variantDeclarations(t,i,a){let o={};for(let[s,c]of Object.entries(t.variants)){let t=n(r(c,i)),l=Object.keys(t.props),u=Object.keys(t.intent);if(l.length>0||u.length>0)throw new e(a,`className "${s}:${c.join(` ${s}:`)}"`,`resolves to ${[...l,...u].join(`, `)}, which ${l.length>0?`is a GTK WIDGET PROPERTY`:`is a layout INTENT`} rather than a CSS declaration. A variant becomes a GTK CSS pseudo-class, and a widget property has no pseudo-class form — only the paint half of the vocabulary (colour, opacity, radius, border, font) can carry a variant`);o[s]=t.css}return o}const stringify=(e,t)=>i.has(e)?`${t}`:`${t}px`;function mintClass(e,t,n){let r=Object.values(n).some(e=>e.length>0);return t.length===0&&!r?null:e.classFor(t,n)}export{flattenStyle,mintClass,normalise,n as partition,variantDeclarations};
@@ -0,0 +1 @@
1
+ const e={box:!0,alignsText:!1},t={box:!1,alignsText:!1},n={box:!1,alignsText:!0},r="GTK carries accessibility through `Gtk.Accessible.update_property()`, an imperative call, not through a widget property — so there is nothing for this layer to set as data. `AccessibilityInfo` (tier P3) is the entry that owns this, and GTK’s model maps onto the props well once it exists",i="would write `Gtk.Widget:name`, and so does `testID`. Two props for one property is the silent-drop shape the host refuses by name (`signalTaken`), so this layer picks one: use `testID`",a={testID:{to:`property`,names:[`name`],as:`string`},id:{to:`refused`,why:i},nativeID:{to:`refused`,why:i},onLayout:{to:`refused`,why:"GTK reports its allocation through `Gtk.Widget.vfunc_size_allocate`, a SUBCLASS override rather than a signal, so there is no handler to bind. `useWindowDimensions` (tier P2) is the window-level answer"},accessible:{to:`refused`,why:r},accessibilityLabel:{to:`refused`,why:r},accessibilityRole:{to:`refused`,why:r},accessibilityHint:{to:`refused`,why:r},accessibilityState:{to:`refused`,why:r}},o={to:`property`,names:[`can-target`],as:`map`,map:{auto:!0,none:!1}},s={...a,multiline:{to:`ignored`,why:`it chose the widget; it is not also a property`},editable:{to:`property`,names:[`editable`],as:`boolean`},keyboardType:{to:`property`,names:[`input-purpose`],as:`map`,map:{default:`free-form`,"email-address":`email`,"phone-pad":`phone`,"number-pad":`digits`,numeric:`number`,"decimal-pad":`number`,url:`url`}},autoFocus:{to:`refused`,why:"focus is `Gtk.Widget.grab_focus()`, which only works once the widget is mapped — an imperative call at a moment this layer does not own. Call it from a ref in an effect"},onFocus:{to:`refused`,why:"focus arrives through a `Gtk.EventControllerFocus`, a controller rather than a signal on the widget, so it is not a prop this layer can route"},onBlur:{to:`refused`,why:"see `onFocus` — the same controller"},returnKeyType:{to:`ignored`,why:`a desktop keyboard has one Return key and no label to change`},autoCapitalize:{to:`ignored`,why:`an on-screen keyboard behaviour; a hardware keyboard has no shift state to preset`},autoCorrect:{to:`ignored`,why:`an on-screen keyboard behaviour`},keyboardAppearance:{to:`ignored`,why:`there is no on-screen keyboard to theme`}},c="`Gtk.TextView` keeps its content in a `Gtk.TextBuffer` rather than in a property (measured: 61 properties, no `text`), so there is nothing for this layer to set as data. Drop `multiline` for a `Gtk.Entry`, or reach the buffer through a ref",l={tag:`GtkTextView`,widgetProps:{"wrap-mode":`word-char`},cssClasses:[],orientation:`vertical`,widget:t,textSink:null,props:{...s,value:{to:`refused`,why:c},defaultValue:{to:`refused`,why:c},onChangeText:{to:`refused`,why:c},placeholder:{to:`refused`,why:"`Gtk.TextView` installs no `placeholder-text` (measured); the Adwaita idiom is a label above the field"},maxLength:{to:`refused`,why:"`Gtk.TextView` installs no `max-length` (measured) — the limit belongs to the buffer"},secureTextEntry:{to:`refused`,why:"`Gtk.TextView` installs no `visibility` (measured), and a multiline password field is not a thing a desktop offers"},onSubmitEditing:{to:`refused`,why:`Return inserts a newline in a multiline field; there is nothing to submit`}}},u={View:{tag:`GtkBox`,widgetProps:{orientation:`vertical`},cssClasses:[],orientation:`vertical`,widget:e,textSink:null,overlayOnAbsoluteChild:{tag:`GtkOverlay`,slot:`overlay`},props:{...a,pointerEvents:o}},Text:{tag:`GtkLabel`,widgetProps:{wrap:!0},cssClasses:[],orientation:`vertical`,widget:n,textSink:`label`,props:{...a,numberOfLines:{to:`property`,names:[`lines`],as:`int`,also:{ellipsize:`end`,wrap:!0}},ellipsizeMode:{to:`property`,names:[`ellipsize`],as:`map`,map:{head:`start`,middle:`middle`,tail:`end`}},selectable:{to:`property`,names:[`selectable`],as:`boolean`},onPress:{to:`refused`,why:"a `Gtk.Label` emits no `clicked` (measured: `activate-current-link`, `activate-link`, `copy-clipboard`, `move-cursor` and nothing else). Wrap it in a `<Pressable>`, which is a real `Gtk.Button`"},allowFontScaling:{to:`ignored`,why:`text scaling is a desktop-wide GNOME setting, not a per-label opt-in`},maxFontSizeMultiplier:{to:`ignored`,why:"see `allowFontScaling`"},adjustsFontSizeToFit:{to:`refused`,why:"GTK has no shrink-to-fit text; a label ellipsizes or wraps. Use `numberOfLines` with `ellipsizeMode`"}}},Pressable:{tag:`GtkButton`,widgetProps:{},cssClasses:[`flat`],orientation:`vertical`,widget:t,textSink:`label`,props:{...a,pointerEvents:o,onPress:{to:`event`,signal:`clicked`},onPressIn:{to:`refused`,why:"press state is the GTK CSS `:active` pseudo-class, not React state (ADR 0032 § 7) — write `active:opacity-70` and GTK animates it with no re-render at all"},onPressOut:{to:`refused`,why:"see `onPressIn` — `active:` is the mechanism"},onLongPress:{to:`refused`,why:"a long press is a `Gtk.GestureLongPress` controller added to the widget, not a property or a signal on it, so it is not something this layer can route as data"},delayLongPress:{to:`refused`,why:"see `onLongPress`"},hitSlop:{to:`refused`,why:"GTK hit-tests the allocation and has no way to grow it past the widget. Pad the button (`p-*`), which enlarges the real target"},android_ripple:{to:`ignored`,why:`an Android-only ripple; Adwaita has its own press feedback`},disabled:{to:`property`,names:[`sensitive`],as:`not`}}},ScrollView:{tag:`GtkScrolledWindow`,widgetProps:{"hscrollbar-policy":`never`},cssClasses:[],orientation:`vertical`,widget:t,textSink:null,content:{tag:`GtkBox`,widgetProps:{orientation:`vertical`},orientation:`vertical`,widget:e,styleProp:`contentContainerStyle`,classNameProp:`contentContainerClassName`},props:{...a,horizontal:[{to:`property`,on:`content`,names:[`orientation`],as:`map`,map:{true:`horizontal`,false:`vertical`}},{to:`property`,on:`outer`,names:[`hscrollbar-policy`],as:`map`,map:{true:`automatic`,false:`never`}},{to:`property`,on:`outer`,names:[`vscrollbar-policy`],as:`map`,map:{true:`never`,false:`automatic`}}],showsVerticalScrollIndicator:{to:`property`,names:[`vscrollbar-policy`],as:`map`,map:{true:`automatic`,false:`external`}},showsHorizontalScrollIndicator:{to:`property`,names:[`hscrollbar-policy`],as:`map`,map:{true:`automatic`,false:`external`}},scrollEnabled:{to:`refused`,why:"a `Gtk.ScrolledWindow` has no switch that stops scrolling — setting both policies to `never` hides the bars AND clamps the child, which is a different thing. Render the content without the ScrollView when it must not scroll"},onScroll:{to:`refused`,why:"GTK reports scroll position through the `Gtk.Adjustment` objects behind `hadjustment`/`vadjustment` — `notify::value` on an adjustment, not a signal on the scrolled window — so there is no prop to route. Reach the adjustment through a ref"},scrollEventThrottle:{to:`refused`,why:"see `onScroll`"},refreshControl:{to:`refused`,why:"GTK has no pull-to-refresh idiom and `RefreshControl` is `refused` in the support table for that reason. Give the desktop build a refresh action"},keyboardShouldPersistTaps:{to:`ignored`,why:`there is no on-screen keyboard to dismiss`},keyboardDismissMode:{to:`ignored`,why:"see `keyboardShouldPersistTaps`"},contentContainerStyle:{to:`ignored`,why:`read directly as the content node’s style set`},contentContainerClassName:{to:`ignored`,why:`read directly as the content node’s class list`}}},ActivityIndicator:{tag:`AdwSpinner`,widgetProps:{},cssClasses:[],orientation:`vertical`,widget:t,textSink:null,props:{...a,animating:{to:`property`,names:[`visible`],as:`boolean`},hidesWhenStopped:{to:`ignored`,why:"a stopped `Adw.Spinner` is a hidden one here — there is no property that stops it while it is on screen (measured), so this is already the behaviour"},size:{to:`property`,names:[`width-request`,`height-request`],as:`pixels-or-map`,map:{small:16,large:32}},color:{to:`style-property`,name:`color`}}},TextInput:{tag:`GtkEntry`,widgetProps:{},cssClasses:[],orientation:`vertical`,widget:t,textSink:`text`,switchOn:{prop:`multiline`,whenTrue:l},props:{...s,value:{to:`property`,names:[`text`],as:`string`},defaultValue:{to:`property`,names:[`text`],as:`string`},placeholder:{to:`property`,names:[`placeholder-text`],as:`string`},maxLength:{to:`property`,names:[`max-length`],as:`int`},secureTextEntry:{to:`property`,names:[`visibility`],as:`not`},onChangeText:{to:`event`,signal:`notify::text`,read:`text`},onSubmitEditing:{to:`event`,signal:`activate`}}},Switch:{tag:`GtkSwitch`,widgetProps:{},cssClasses:[],orientation:`vertical`,widget:t,textSink:null,props:{...a,value:{to:`property`,names:[`active`],as:`boolean`},onValueChange:{to:`event`,signal:`notify::active`,read:`active`},disabled:{to:`property`,names:[`sensitive`],as:`not`},trackColor:{to:`refused`,why:"Adwaita paints the switch from the theme’s accent colour, and its track is a CSS `slider`/`trough` subnode rather than a property. Style it from the application stylesheet"},thumbColor:{to:`refused`,why:"see `trackColor`"},ios_backgroundColor:{to:`ignored`,why:`an iOS-only fallback colour`}}}},d=Object.keys(u),f=new Set([`children`,`key`,`ref`,`className`,`style`]);export{f as FRAMEWORK_PROPS,u as PRIMITIVES,d as PRIMITIVE_NAMES};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{PrimitiveError as e}from"../primitives/errors.js";import{resolvePrimitive as t}from"../primitives/resolve.js";import{styleConfig as n}from"../style-config.js";import{createContext as r,createMemo as i,createSignal as a,onMount as o,untrack as s,useContext as c}from"solid-js";import{createComponent as l,createElement as u,effect as d,insert as f,insertNode as p,mount as m,setProp as h,widgetOf as g}from"@gjsify/gtk-host/solid";const _=r(()=>null),v=new WeakSet,y=new WeakMap,b={absolute:1,count:1,text:!1},accessorName=e=>e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase()),sameContext=(e,t)=>JSON.stringify(e)===JSON.stringify(t),sameValue=(e,t)=>Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((e,n)=>e===t[n]):e===t;function element(e,r){let l=r,m=n(),x=c(_),[S,C]=a(null),w=i(()=>{let n=x();return t(e,l,{tokens:m.tokens,sheet:m.sheet,...n===null?{}:{parent:n},children:S()??b})}),T=s(w).childContext.overlay,E=i(()=>({...w().childContext,overlay:T}),void 0,{equals:sameContext}),D=childrenUnder(l,E);assertOwnChildren(e,D(),E),C(factsOf(e,D()));let O=s(w),k=u(O.node.tag),A=O.content===null?null:u(O.content.tag);O.slot!==null&&v.add(k),y.set(k,x);for(let[e,t]of Object.entries(dispatchers(O.events,l,k)))h(k,e,t);let j={},M={};d(()=>{let t=w();assertStableShape(e,O,t),writeProps(k,j,{...x()?.props,...t.node.props,...t.slot===null?{}:{slot:t.slot},...classProp(t.node)}),A!==null&&t.content!==null&&writeProps(A,M,{...t.content.props,...classProp(t.content)})});let N=l.ref;typeof N==`function`&&o(()=>N(g(k))),A!==null&&p(k,A);let P=A??k;if(O.absoluteSlot===null)f(P,D);else{f(P,()=>split(D()).ordinary);for(let e of split(s(D)).slotted)p(k,e)}return k}function childrenUnder(e,t){let n=_.Provider;return l(n,{value:t,get children(){return e.children}})}function assertOwnChildren(t,n,r){for(let i of Array.isArray(n)?n:[n]){if(typeof i!=`object`||!i)continue;let n=y.get(i);if(!(n===void 0||n===r))throw new e(t,`children`,"contains an element that was built BEFORE this one, so it resolved outside this element's context: it never learned this parent's orientation or its inherited alignment, and the loss is silent — `flex-1` stays unresolved and `items-center` never reaches it. Pass children lazily, `get children() { return … }`, which is what every Solid JSX compiler emits and the reason Solid's context works at all")}}function factsOf(t,n){let r=(Array.isArray(n)?n:[n]).filter(e=>e!=null&&typeof e!=`boolean`),i=0,a=!1;for(let n of r)if(typeof n==`string`||typeof n==`number`)a=!0;else if(typeof n==`function`)throw new e(t,`children`,'was given a function that takes an argument. Children-as-a-function-of-`{ pressed }` is not implemented (ADR 0032 § 7) — the press state is the GTK CSS `:active` pseudo-class, so write `className="active:opacity-70"` and GTK animates it with no reactive update at all. A zero-argument accessor is Solid\'s own dynamic child and never reaches this refusal');else typeof n==`object`&&n&&v.has(n)&&i++;return{absolute:i,count:r.length,text:a}}function split(e){let t=Array.isArray(e)?e:[e],n=[],r=[];for(let e of t)typeof e==`object`&&e&&v.has(e)?r.push(e):n.push(e);return{ordinary:n,slotted:r}}function dispatchers(e,t,n){let r={};for(let i of e)r[`on:${i.signal}`]=()=>{let e=t[i.prop];if(typeof e==`function`){if(i.read===null){e();return}e(g(n)[accessorName(i.read)])}};return r}function writeProps(e,t,n){for(let r of Object.keys(t))r in n||(h(e,r,void 0),delete t[r]);for(let[r,i]of Object.entries(n))sameValue(t[r],i)||(h(e,r,i),t[r]=i)}const classProp=e=>e.cssClasses.length===0?{}:{"css-classes":[...e.cssClasses]};function assertStableShape(t,n,r){let shape=e=>[e.node.tag,e.content?.tag??`-`,e.events.map(e=>`${e.prop}>${e.signal}`).join(`,`)].join(`|`),i=shape(n),a=shape(r);if(i!==a)throw new e(t,`reactive update`,`would change the element from ${i} to ${a}, and a Solid element is created once — there is no reconciler pass that could swap the widget. Split the branches into two elements under a <Show>, where each one is created for its own shape`)}function View(e){return element(`View`,e)}function Text(e){return element(`Text`,e)}function Pressable(e){return element(`Pressable`,e)}function ScrollView(e){return element(`ScrollView`,e)}function ActivityIndicator(e){return element(`ActivityIndicator`,e)}function TextInput(e){return element(`TextInput`,e)}function Switch(e){return element(`Switch`,e)}export{ActivityIndicator,Pressable,ScrollView,Switch,Text,TextInput,View,m as mount};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{MINIMAL_TOKENS as e,StyleSheet as t}from"@gjsify/gtk-host/style";let n=e,r=null;function configureStyle(e){e.tokens!==void 0&&(n=e.tokens),e.sheet!==void 0&&(r=e.sheet)}function styleConfig(){return r??=new t,{tokens:n,sheet:r}}function resetStyleConfig(){n=e,r=null}export{configureStyle,resetStyleConfig,styleConfig};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";const e={View:{status:`partial`,tier:`P1`,gtk:`Gtk.Box, or Gtk.Overlay when a child is absolutely positioned`,reason:`The container primitive. Which widget it becomes depends on its children, not on the element.`,limits:[`An absolutely positioned child is placed by alignment plus a margin, because Gtk.Overlay positions an overlay child by its halign/valign and has no coordinate pair. An offset on only ONE edge of an axis therefore leaves the other axis at GTK’s default (fill), where React Native would keep the child at its static position — a position GTK has no way to express for an overlay child.`,`onLayout is refused: GTK reports allocation through Gtk.Widget.vfunc_size_allocate, a subclass override rather than a signal.`,`pointerEvents answers auto and none only. box-none and box-only split hit-testing between a widget and its subtree, and Gtk.Widget:can-target is one boolean for both.`]},Text:{status:`partial`,tier:`P1`,gtk:`Gtk.Label`,reason:`Wrapping is ON by default in React Native and OFF on a Gtk.Label, so the default is set explicitly.`,limits:[`A nested <Text> is refused by the host naming the tag: Gtk.Label takes no children (measured), so React Native’s inline-styling idiom has no counterpart. Use Pango markup through a ref, or separate labels.`,`ellipsizeMode="clip" is refused: PangoEllipsizeMode is NONE, START, MIDDLE, END (measured) and has no clip member, so honouring it would add an ellipsis the author asked not to have.`,`onPress is refused: a Gtk.Label emits no clicked signal (measured). Wrap it in a <Pressable>.`]},Pressable:{status:`partial`,tier:`P1`,gtk:`Gtk.Button (flat)`,reason:`Press state is a GTK CSS :active pseudo-class; children-as-a-function is P2.`,limits:[`children-as-a-function-of-{ pressed } is a named refusal, at build time through the prop type and at runtime through a throw (ADR 0032 § 7). Write active:* instead — GTK animates :active itself with no re-render.`,`onPressIn/onPressOut are refused for the same reason: the press state never reaches the reconciler.`,`onLongPress is refused: a long press is a Gtk.GestureLongPress controller added to the widget, not a property or a signal on it.`,`hitSlop is refused: GTK hit-tests the allocation and cannot grow it past the widget. Pad the button instead, which enlarges the real target.`]},ScrollView:{status:`partial`,tier:`P1`,gtk:`Gtk.ScrolledWindow + an implicit content box`,reason:`contentContainerStyle styles the inner box, which is a second styleable node.`,limits:[`onScroll and scrollEventThrottle are refused: GTK reports scroll position as notify::value on the Gtk.Adjustment behind hadjustment/vadjustment, an object rather than a signal on the scrolled window. Reach the adjustment through a ref.`,`scrollEnabled is refused: a Gtk.ScrolledWindow has no switch that stops scrolling, and setting both policies to never clamps the child as well as hiding the bars.`,`refreshControl is refused, matching RefreshControl’s own entry: GTK has no pull-to-refresh idiom.`,`Layout utilities that need a box (items-*, gap-*, justify-*) are refused on style and belong on contentContainerStyle — which is React Native’s own rule, not a GTK one.`]},ActivityIndicator:{status:`partial`,tier:`P1`,gtk:`Adw.Spinner`,reason:`Direct counterpart.`,limits:[`animating={false} hides the widget. MEASURED: Adw.Spinner installs 36 properties and every one is Gtk.Widget’s — there is nothing that stops it while it is on screen, so "not animating" is "not shown". That is also exactly what hidesWhenStopped asks for, which is why hidesWhenStopped is a declared no-op.`,`size="small"/"large" are 16 and 32 px — Gtk.IconSize’s own two steps — not React Native’s 20/36, which are Android dp and land between GTK’s steps. A numeric size is used verbatim.`]},TextInput:{status:`partial`,tier:`P1`,gtk:`Gtk.Entry / Gtk.TextView`,reason:`Single- versus multi-line is one prop in React Native and two different widgets in GTK.`,limits:[`multiline={true} is a Gtk.TextView, whose content lives in a Gtk.TextBuffer rather than in a property — MEASURED: 61 properties, no text. So value, defaultValue and onChangeText are refused by name on a multiline input, as are placeholder, maxLength and secureTextEntry, none of which Gtk.TextView installs. Single-line is complete.`,`onFocus/onBlur are refused: focus arrives through a Gtk.EventControllerFocus, a controller rather than a signal on the widget.`,`autoFocus is refused: Gtk.Widget.grab_focus() only works once the widget is mapped, which is a moment this layer does not own. Call it from a ref in an effect.`,`keyboardType maps onto Gtk.Entry:input-purpose; returnKeyType, autoCapitalize, autoCorrect and keyboardAppearance are declared no-ops, because they describe an on-screen keyboard.`]},Linking:{status:`partial`,tier:`P1`,gtk:`Gtk.UriLauncher`,reason:`openURL and canOpenURL only.`,limits:[`openURL asks can_launch FIRST and rejects when the answer is no. MEASURED: Gtk.UriLauncher.launch never calls back for a scheme with no handler (3 000 ms, no callback, exit 0), and a promise that never settles is worse than a rejection.`,`getInitialURL always resolves null. A desktop deep link arrives as Gio.Application::open AFTER startup, so there is no value to read before it — which is also what React Native returns for a normal launch.`,`addEventListener/addListener are refused: URL delivery is the application object’s own wiring (HANDLES_OPEN plus the open signal), above this layer.`,`openSettings and sendIntent are refused: a per-app settings page and an Android Intent have no desktop counterpart.`]},Switch:{status:`partial`,tier:`P1`,gtk:`Gtk.Switch`,reason:`Direct counterpart.`,limits:[`onValueChange binds notify::active, not state-set: state-set runs BEFORE the state changes and must return false to let the default handler proceed, and a handler that forgets makes the switch stick at exit 0.`,`trackColor and thumbColor are refused: Adwaita paints the switch from the theme accent and its track is a CSS subnode, not a property. Style it from the application stylesheet.`]},Platform:{status:`partial`,tier:`P1`,reason:`OS is "linux" | "macos" | "windows"; select() picks the default branch.`,limits:[`OS reports "linux", which is not a member of React Native’s own PlatformOSType. Reporting "macos" on a Linux desktop would be a lie select() cannot recover from, and "web" implies a DOM.`,`select() does NOT consult a native branch, for ADR 0032 § 9’s reason: a native branch is written for a React Native runtime, and handing it to a GTK build is a failure that surfaces in a window. A spec with neither this OS nor default is a named refusal rather than undefined.`,`Version throws by name: it is a mobile OS version and a desktop has no counterpart meaning the same thing.`,`constants throws by name: it is the native bridge’s constants object, and there is no bridge here.`]},Modal:{status:`planned`,tier:`P1`,gtk:`Adw.Dialog`,reason:`An Adw.Dialog cannot be an ordinary element. MEASURED on libadwaita 1.10: 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.`},useColorScheme:{status:`supported`,tier:`P1`,gtk:`Adw.StyleManager.dark`,reason:`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.`},Share:{status:`partial`,tier:`P1`,gtk:`Gdk.Clipboard`,reason:`No desktop share sheet worth pretending about; copying the link is the honest mapping.`,limits:[`action is always sharedAction. dismissedAction means the user closed a share sheet without choosing, and nothing here asks the user anything — reporting a dismissal would be inventing an event. The constant is still exported, so a comparison against it resolves instead of failing to import.`,`activityType is always undefined: there is no activity to name.`,`Gtk.UriLauncher is NOT used here, although the planning entry named it. Launching a URI OPENS it in another application, which is a share sheet’s behavioural inverse — that call is Linking.openURL’s, and it is there.`]},AppRegistry:{status:`partial`,tier:`P1`,gtk:`Adw.Application + Adw.ApplicationWindow`,reason:`The entry point. Nothing renders without a window, so this is P1 despite being a shim.`,limits:[`runApplication takes gjsify options (applicationId is required) rather than React Native’s { rootTag, initialProps } — a phone host supplies the application identity, a desktop one IS the application.`,`unmountApplicationComponentAtRootTag throws: there is no root tag to address.`]},StyleSheet:{status:`planned`,tier:`P1`,reason:`create/flatten/hairlineWidth/absoluteFill. Style objects go through the same partition as classes.`},FlatList:{status:`planned`,tier:`P2`,gtk:`Gtk.ListView + Gio.ListStore`,reason:`GTK virtualises for real, so this fits better here than it does on the web.`},SectionList:{status:`planned`,tier:`P2`,gtk:`Gtk.ListView + a section model`,reason:`Sections map onto GTK section models.`},VirtualizedList:{status:`planned`,tier:`P2`,gtk:`Gtk.ListView`,reason:`Its public surface is wide and mostly not worth honouring literally; the useful subset backs FlatList.`},VirtualizedSectionList:{status:`planned`,tier:`P2`,gtk:`Gtk.ListView`,reason:`The section-shaped sibling of VirtualizedList.`},Image:{status:`planned`,tier:`P2`,gtk:`Gtk.Picture / Gdk.Texture`,reason:`resizeMode becomes content-fit.`},ImageBackground:{status:`planned`,tier:`P2`,gtk:`Gtk.Picture in a Gtk.Overlay`,reason:`A picture with children over it.`},TouchableOpacity:{status:`planned`,tier:`P2`,gtk:`Gtk.Button (flat)`,reason:`The same machinery as Pressable, and nearly free once it exists.`},TouchableHighlight:{status:`planned`,tier:`P2`,gtk:`Gtk.Button (flat)`,reason:`As TouchableOpacity, with a different pressed style.`},TouchableWithoutFeedback:{status:`planned`,tier:`P2`,gtk:`Gtk.GestureClick`,reason:`A gesture controller on the child, with no button chrome.`},Button:{status:`planned`,tier:`P2`,gtk:`Gtk.Button`,reason:`The one component whose React Native styling story is "you cannot", which GTK agrees with.`},Dimensions:{status:`planned`,tier:`P2`,gtk:`Gdk.Surface`,reason:`Window size, not screen size — a desktop app is not full-screen.`},useWindowDimensions:{status:`planned`,tier:`P2`,gtk:`Gdk.Surface`,reason:`The hook form of Dimensions, re-rendering on resize.`},Alert:{status:`planned`,tier:`P2`,gtk:`Adw.AlertDialog`,reason:`Direct counterpart.`},Appearance:{status:`planned`,tier:`P2`,gtk:`Adw.StyleManager`,reason:`The imperative sibling of useColorScheme.`},SafeAreaView:{status:`no-desktop-meaning`,tier:`P2`,reason:`Insets are zero on a desktop window, but it has to exist to be imported.`},StatusBar:{status:`no-desktop-meaning`,tier:`P2`,reason:`A desktop window has no status bar to configure.`},KeyboardAvoidingView:{status:`no-desktop-meaning`,tier:`P2`,reason:`No on-screen keyboard eats a desktop window layout.`},Keyboard:{status:`no-desktop-meaning`,tier:`P2`,reason:`Its events are on-screen-keyboard events, which do not occur.`},RefreshControl:{status:`refused`,reason:`GTK has no pull-to-refresh idiom and should not grow one. Give the desktop build a refresh action instead.`},AppState:{status:`planned`,tier:`P3`,gtk:`Gtk.Application / Gdk.Surface state`,reason:`active/background from window focus and visibility.`},PixelRatio:{status:`planned`,tier:`P3`,gtk:`Gdk.Surface.scale-factor`,reason:`The scale factor of the surface the widget is on.`},PlatformColor:{status:`planned`,tier:`P3`,gtk:`Adwaita named colours`,reason:`Maps unusually well — GTK’s palette is exactly this idea.`},AccessibilityInfo:{status:`planned`,tier:`P3`,gtk:`Gtk.Accessible / AT-SPI`,reason:`The highest-value P3 entry: GTK’s accessibility model is strong and the props map onto it well.`},Animated:{status:`planned`,tier:`P3`,gtk:`Adw.TimedAnimation / Adw.SpringAnimation`,reason:`Genuinely mappable, but it is a subsystem rather than a component. Doing it badly is worse than not doing it.`},Easing:{status:`planned`,tier:`P3`,reason:`Pure maths; it lands with Animated or not at all.`},LayoutAnimation:{status:`planned`,tier:`P3`,reason:`Needs an animated layout pass, which is the same subsystem as Animated.`},InteractionManager:{status:`planned`,tier:`P3`,reason:`Deferring work until interactions settle; a main-loop idle source is the counterpart.`},useAnimatedValue:{status:`planned`,tier:`P3`,reason:`Part of the Animated subsystem.`},useAnimatedValueXY:{status:`planned`,tier:`P3`,reason:`Part of the Animated subsystem.`},useAnimatedColor:{status:`planned`,tier:`P3`,reason:`Part of the Animated subsystem.`},PanResponder:{status:`planned`,tier:`P3`,gtk:`Gtk.Gesture* controllers`,reason:`The controllers exist; the arbitration model is not React Native’s, so this is its own project.`},usePressability:{status:`planned`,tier:`P3`,reason:`The hook behind the Touchable family; it lands with the gesture work.`},DrawerLayoutAndroid:{status:`planned`,tier:`P3`,gtk:`Adw.OverlaySplitView`,reason:`The pattern survives on a desktop even though the component is Android-only.`},I18nManager:{status:`planned`,tier:`P3`,gtk:`Gtk.Widget.direction`,reason:`RTL is a widget-direction question on GTK.`},LogBox:{status:`no-desktop-meaning`,tier:`P3`,reason:`A development overlay for a phone; the console is the desktop equivalent.`},Systrace:{status:`no-desktop-meaning`,reason:`Android systrace has no desktop counterpart.`},Vibration:{status:`no-desktop-meaning`,reason:`A desktop machine does not vibrate.`},ToastAndroid:{status:`planned`,tier:`P3`,gtk:`Adw.Toast`,reason:`Android-only by name, and Adwaita has the exact widget.`},InputAccessoryView:{status:`no-desktop-meaning`,reason:`An iOS keyboard accessory bar; there is no keyboard to accessorise.`},TouchableNativeFeedback:{status:`planned`,tier:`P3`,gtk:`Gtk.Button`,reason:`Android-only ripple; shimmed to its portable sibling.`},ActionSheetIOS:{status:`planned`,tier:`P3`,gtk:`Adw.AlertDialog with responses`,reason:`iOS-only by name; the pattern is a dialog with choices.`},PushNotificationIOS:{status:`refused`,reason:`Platform notification plumbing. A desktop app uses Gio.Notification directly.`},PermissionsAndroid:{status:`refused`,reason:`Android runtime permissions have no desktop counterpart; portals are asked for at use time.`},Settings:{status:`refused`,reason:`An iOS user-defaults bridge. GSettings is the desktop answer and is not this API.`},Clipboard:{status:`planned`,tier:`P3`,gtk:`Gdk.Clipboard`,reason:`Deprecated upstream in favour of a community package, but trivial here.`},BackHandler:{status:`planned`,tier:`P3`,reason:`An Android hardware back button. Maps to the navigation view’s own back, so it lands with routing.`},DynamicColorIOS:{status:`planned`,tier:`P3`,reason:`A light/dark colour pair; the Adwaita scheme already provides the switch.`},processColor:{status:`planned`,tier:`P3`,reason:`Colour string to a platform value; a Gdk.RGBA on this side.`},UTFSequence:{status:`planned`,tier:`P3`,reason:`A table of unicode constants. Pure data, no platform in it.`},experimental_LayoutConformance:{status:`refused`,reason:`An experimental switch between two React Native layout implementations. Neither is used here.`},unstable_VirtualView:{status:`refused`,reason:`Unstable React Native internal.`},VirtualViewMode:{status:`refused`,reason:`Unstable React Native internal.`},unstable_NativeText:{status:`refused`,reason:`Unstable React Native internal.`},unstable_NativeView:{status:`refused`,reason:`Unstable React Native internal.`},unstable_TextAncestorContext:{status:`refused`,reason:`Unstable React Native internal.`},ReactNativeVersion:{status:`planned`,tier:`P3`,reason:`The version this layer targets, reported honestly rather than spoofed.`},DeviceInfo:{status:`refused`,reason:`A native module surface describing a phone.`},DevMenu:{status:`no-desktop-meaning`,reason:`The shake-to-open developer menu.`},DevSettings:{status:`no-desktop-meaning`,reason:`Development-client settings for a phone runtime.`},NativeModules:{status:`refused`,reason:`The native-module bridge. There is no bridge here; this layer renders in-process onto GTK.`},TurboModuleRegistry:{status:`refused`,reason:`The TurboModule lookup. Same reason as NativeModules.`},NativeComponentRegistry:{status:`refused`,reason:`Fabric component registration. The host owns widget creation.`},requireNativeComponent:{status:`refused`,reason:`Looks up a native view manager. Write a GTK widget descriptor instead.`},codegenNativeComponent:{status:`refused`,reason:`React Native codegen for Fabric components.`},codegenNativeCommands:{status:`refused`,reason:`React Native codegen for Fabric commands.`},UIManager:{status:`refused`,reason:`The legacy view-manager surface. The GTK host is the view manager here.`},findNodeHandle:{status:`refused`,reason:`Returns a native view tag. A ref here is the Gtk.Widget itself, which is more useful.`},registerCallableModule:{status:`refused`,reason:`Registers a module callable from the native side. There is no native side.`},Networking:{status:`refused`,reason:`React Native’s XHR internals. Use fetch, which gjsify provides.`},NativeDialogManagerAndroid:{status:`refused`,reason:`An Android dialog native module. Alert is the portable spelling.`},ProgressBarAndroid:{status:`planned`,tier:`P3`,gtk:`Gtk.ProgressBar`,reason:`Android-only by name; GTK has the widget.`},Touchable:{status:`refused`,reason:`The legacy mixin behind the Touchable family, not a public component.`},EventEmitter:{status:`supported`,reason:`Pure JavaScript; nothing in it touches a platform.`},NativeEventEmitter:{status:`planned`,tier:`P3`,reason:`It would construct and subscribe, but nothing native would ever emit into it — shipping that needs a decision, not a class.`},DeviceEventEmitter:{status:`planned`,tier:`P3`,reason:`The global emitter. Lands with NativeEventEmitter, and for the same reason.`},NativeAppEventEmitter:{status:`refused`,reason:`The legacy iOS app-event emitter.`},RootTagContext:{status:`refused`,reason:`A React Native surface identifier. This layer has one root per Adw window.`},unstable_batchedUpdates:{status:`supported`,reason:`React 19 batches automatically; this is the identity call it already is upstream.`}},t=Object.keys(e),n=new Set([`supported`,`partial`]),isImportable=t=>{let r=e[t];return r!==void 0&&n.has(r.status)};function explainUnsupported(t){let n=e[t];if(n===void 0)return`@gjsify/react-native: "${t}" is not a React Native export this layer knows about. If the installed react-native really exports it, the support table is out of date — run scripts/check-rn-surface.mjs, which compares the two.`;let r=n.tier?` (tier ${n.tier})`:``,i=n.gtk?` The GTK counterpart is ${n.gtk}.`:``;switch(n.status){case`supported`:case`partial`:return`@gjsify/react-native: "${t}" is available.`;case`planned`:return`@gjsify/react-native: "${t}" is not implemented yet${r}. ${n.reason}${i}`;case`refused`:return`@gjsify/react-native: "${t}" will not be implemented. ${n.reason}`;case`no-desktop-meaning`:return`@gjsify/react-native: "${t}" has no meaning on a desktop window${r}. ${n.reason}`;case`not-reachable`:return`@gjsify/react-native: "${t}" cannot be implemented in this build chain. ${n.reason}`}}export{t as SUPPORTED_NAMES,e as SUPPORT_TABLE,explainUnsupported,isImportable};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{explainUnsupported as e}from"./support-table.js";var UnsupportedError=class extends Error{constructor(t){super(e(t)),this.name=`UnsupportedError`,this.export=t}};function unsupported(e){let refuse=()=>{throw new UnsupportedError(e)};function constructible(){return refuse()}return new Proxy(constructible,{apply:refuse,construct:refuse,get(t,n){if(n===`name`||n===`displayName`||n===Symbol.toStringTag)return e;if(n!==`$$typeof`&&n!==`then`){if(n===`prototype`)return Reflect.get(t,n);throw new UnsupportedError(e)}},set(){throw new UnsupportedError(e)}})}export{UnsupportedError,unsupported};
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -0,0 +1,16 @@
1
+ /** React Native's own type. `null` is its "unknown", which does not occur here. */
2
+ export type ColorSchemeName = 'light' | 'dark';
3
+ /** What the user is looking at right now. */
4
+ export declare const currentColorScheme: () => ColorSchemeName;
5
+ /**
6
+ * Call `listener` whenever the scheme changes; returns the unsubscribe.
7
+ *
8
+ * `notify::dark` and not `notify::color-scheme`: the desktop switching from light
9
+ * to dark does not change what the application asked for, so a subscriber on
10
+ * `color-scheme` would never fire for the one event this API exists to report.
11
+ *
12
+ * The disposer disconnects rather than tracking a flag, because GJS blocks JS
13
+ * callbacks during GC — a handler that is not disconnected stays connected for the
14
+ * life of the process, which is the leak `gtk-host`'s own lifetime rules exist for.
15
+ */
16
+ export declare function onColorSchemeChange(listener: (scheme: ColorSchemeName) => void): () => void;
@@ -0,0 +1,7 @@
1
+ export { currentColorScheme, onColorSchemeChange } from './color-scheme.js';
2
+ export type { ColorSchemeName } from './color-scheme.js';
3
+ export { Linking } from './linking.js';
4
+ export { Platform, resetPlatformCache } from './platform.js';
5
+ export type { PlatformOS, PlatformSelectSpec } from './platform.js';
6
+ export { Share } from './share.js';
7
+ export type { ShareAction, ShareContent } from './share.js';
@@ -0,0 +1,35 @@
1
+ export declare const Linking: {
2
+ /**
3
+ * Hand a URI to the desktop's own handler.
4
+ *
5
+ * Resolves when GTK reports success and rejects with the reason otherwise —
6
+ * React Native's own contract. `parent` is null on purpose: a modal app chooser
7
+ * anchored to a window is what a parent buys, and this layer does not know which
8
+ * window the call came from. GTK falls back to an unanchored chooser.
9
+ */
10
+ readonly openURL: (url: string) => Promise<void>;
11
+ /**
12
+ * Is there an application for this URI?
13
+ *
14
+ * `Gtk.UriLauncher.can_launch` is SYNCHRONOUS and React Native's `canOpenURL`
15
+ * is a promise, so this is a resolved one. Measured: `false` for
16
+ * `x-gjsify-probe://`, `true` for `https:` and `mailto:`.
17
+ */
18
+ readonly canOpenURL: (url: string) => Promise<boolean>;
19
+ /**
20
+ * Always `null`, and that is an answer rather than a stub.
21
+ *
22
+ * React Native's `getInitialURL` returns the deep link an app was COLD-STARTED
23
+ * with. On a desktop the equivalent arrives as `Gio.Application::open` after
24
+ * startup, not as a value readable before it — so there is nothing for this to
25
+ * read, in any application, ever. Returning `null` is what React Native itself
26
+ * returns when an app was launched normally, so ported code takes the branch it
27
+ * already has.
28
+ */
29
+ readonly getInitialURL: () => Promise<string | null>;
30
+ readonly addEventListener: () => never;
31
+ readonly addListener: () => never;
32
+ readonly removeEventListener: () => never;
33
+ readonly openSettings: () => never;
34
+ readonly sendIntent: () => never;
35
+ };
@@ -0,0 +1,28 @@
1
+ /** What this layer reports. `'linux'` is not one of React Native's own five. */
2
+ export type PlatformOS = 'linux' | 'macos' | 'windows';
3
+ /** A `Platform.select` argument: one branch per OS, plus `default`. */
4
+ export type PlatformSelectSpec<T> = Partial<Record<PlatformOS | 'default', T>> & Readonly<Record<string, T>>;
5
+ export declare const Platform: {
6
+ /** `'linux' | 'macos' | 'windows'`. See the file header for why `'linux'` exists. */
7
+ readonly OS: PlatformOS;
8
+ /**
9
+ * Pick the branch for this OS, falling back to `default`.
10
+ *
11
+ * `native` IS DELIBERATELY NOT CONSULTED, and it is the same decision as ADR
12
+ * 0032 § 9's for `.native.tsx`: a `native` branch is by definition written for a
13
+ * React Native runtime, and reaching for it would hand the GTK build code that
14
+ * expects `NativeModules` — a failure that surfaces in a window rather than at
15
+ * build time. Falling through to `default` is the honest outcome, and a spec
16
+ * with neither this OS nor `default` is a named refusal that says so, rather
17
+ * than React Native's own `undefined`.
18
+ */
19
+ readonly select: <T>(spec: PlatformSelectSpec<T>) => T;
20
+ /** A desktop is not a television. Reported rather than refused, because it is a fact. */
21
+ readonly isTV: false;
22
+ /** Likewise: this layer never runs React Native's own test harness. */
23
+ readonly isTesting: false;
24
+ readonly Version: never;
25
+ readonly constants: never;
26
+ };
27
+ /** Test seam: forget the cached OS so a spec can exercise the read more than once. */
28
+ export declare const resetPlatformCache: () => void;
@@ -0,0 +1,27 @@
1
+ /** React Native's `ShareContent`, as much of it as a clipboard can carry. */
2
+ export interface ShareContent {
3
+ readonly message?: string;
4
+ readonly url?: string;
5
+ /** Carried for parity and unused: a clipboard has no title. */
6
+ readonly title?: string;
7
+ }
8
+ export interface ShareAction {
9
+ readonly action: 'sharedAction' | 'dismissedAction';
10
+ /** Always undefined: there is no activity to name. */
11
+ readonly activityType?: string;
12
+ }
13
+ export declare const Share: {
14
+ /** React Native's own two constants. */
15
+ readonly sharedAction: "sharedAction";
16
+ readonly dismissedAction: "dismissedAction";
17
+ /**
18
+ * Put the shared text on the clipboard.
19
+ *
20
+ * `message` and `url` are joined with a newline when both are given, which is
21
+ * what every desktop "copy link" affordance produces and what a user pasting
22
+ * into a message expects. Neither given is a named refusal rather than an empty
23
+ * clipboard: clearing the user's clipboard because a call site forgot its
24
+ * payload is a destructive no-op.
25
+ */
26
+ readonly share: (content: ShareContent) => Promise<ShareAction>;
27
+ };