react-native-gtkx 0.4.0-alpha.2 → 0.4.0-alpha.3
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.
- package/README.md +35 -96
- package/dist/adw/index.js +3 -2
- package/dist/adw/index.js.map +1 -1
- package/dist/dnd/gtk-controllers.js +1 -1
- package/dist/dnd/gtk-controllers.js.map +1 -1
- package/dist/gtk/index.js +4 -3
- package/dist/gtk/index.js.map +1 -1
- package/dist/gtkx/bridge/adw.js +1 -1
- package/dist/gtkx/bridge/adw.js.map +1 -1
- package/dist/gtkx/bridge/view-box.js +1 -1
- package/dist/gtkx/bridge/view-box.js.map +1 -1
- package/dist/mcp/bin.js +1 -1
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/data/generated.d.ts +811 -498
- package/dist/mcp/data/generated.js +926 -532
- package/dist/mcp/data/generated.js.map +1 -1
- package/dist/mcp/resolve.d.ts +2 -2
- package/dist/mcp/resolve.js +2 -2
- package/dist/mcp/resolve.js.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/sea/bundle.js +1 -1
- package/dist/sea/bundle.js.map +1 -1
- package/dist/sea/native-shim.js +3 -2
- package/dist/sea/native-shim.js.map +1 -1
- package/dist/vitest/index.d.ts +1 -1
- package/dist/vitest/index.js +1 -1
- package/dist/vitest/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
<h1 align="center">react-native-gtkx</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center"><b>React Native for the Linux desktop.</b><br/>
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
The <code>react-native</code> API, rendered as real GTK4/Adwaita widgets — no WebView,<br/>
|
|
9
|
+
no canvas, no bridge. Linux is a React Native out-of-tree platform here:<br/>
|
|
10
|
+
<code>npx react-native run-linux</code>, next to <code>run-ios</code> and <code>run-android</code>.</p>
|
|
10
11
|
|
|
11
12
|
<p align="center">
|
|
12
13
|
<a href="https://github.com/itsmepetrov/react-native-gtkx/actions/workflows/ci.yml"><img src="https://github.com/itsmepetrov/react-native-gtkx/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
@@ -14,110 +15,48 @@ applications on real GTK4/Adwaita widgets, with no WebView and no canvas renderi
|
|
|
14
15
|
<a href="https://github.com/itsmepetrov/react-native-gtkx/releases"><img src="https://img.shields.io/github/v/release/itsmepetrov/react-native-gtkx?label=deb%20packages" alt="releases" /></a>
|
|
15
16
|
</p>
|
|
16
17
|
|
|
17
|
-
Under the hood: [gtkx](https://github.com/gtkx-org/gtkx) (a React reconciler for GTK4
|
|
18
|
+
Under the hood: [gtkx](https://github.com/gtkx-org/gtkx) (a React reconciler for GTK4, with an in-process FFI into libgtk) and [Yoga](https://yogalayout.dev) — the same flexbox engine React Native itself uses. Navigation runs on real Adwaita widgets: react-navigation's stack and drawer are backed by an actual `Adw.NavigationView`/`Adw.NavigationSplitView`, so the back button, the slide transition, Escape, the back gesture and the back-history menu are the platform's, not a JS re-implementation. Past the portable surface, `react-native-gtkx/gtk` and `/adw` hand you every GTK/Adwaita widget directly — including a navigation stack that needs no router at all.
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
<table align="center">
|
|
21
|
+
<tr>
|
|
22
|
+
<td><img src="https://raw.githubusercontent.com/itsmepetrov/react-native-gtkx/main/docs/shots/hn-list.png" alt="Hacker News list — react-native-gtkx"/></td>
|
|
23
|
+
<td><img src="https://raw.githubusercontent.com/itsmepetrov/react-native-gtkx/main/docs/shots/hn-story.png" alt="story screen with comments"/></td>
|
|
24
|
+
</tr>
|
|
25
|
+
</table>
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
<p align="center"><i><code>examples/hn-app</code>, live in native GTK windows: a Hacker News reader on the standard React Native Metro toolchain. Tapping a card pushes a real <code>Adw.NavigationView</code> page — the back button, the slide and the preserved list position come from the platform, not from JS. The search field sits <b>inside</b> the HeaderBar (real RN content in native chrome) and queries the HN API; comments load as you scroll. The data layer is plain Node <code>fetch</code> — on this platform "native modules" are just Node.</i></p>
|
|
23
28
|
|
|
24
29
|
And the portability proof — `examples/profile` renders ONE source file with both renderers, not a single `@gtkx/*` import in it:
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- [x] Windowed lists: virtualization (10k rows), sticky headers, SectionList, scrollToIndex, viewability, inverted (RN chat semantics), refresh parity
|
|
43
|
-
- [x] Linux as an RN **out-of-tree platform**: the standard Metro/Babel toolchain, `react-native.config.js` declared by the dependency, `npx react-native run-linux`, compiled package distribution (attw-checked) — see `examples/rn-app` (a cli-init app with ios + android + linux)
|
|
44
|
-
- [x] **Fast Refresh on both toolchains**: `run-linux --dev` (Metro dev server + HMR in the GTK host, state preserved) and `gtkx dev` (vite)
|
|
45
|
-
- [x] **Navigation on real Adwaita widgets**: react-navigation navigators backed by `Adw.NavigationView` and `Adw.NavigationSplitView` — see below
|
|
46
|
-
|
|
47
|
-
Verified live: `examples/hn-app` (a Hacker News reader on the Metro path), `examples/gallery` (the whole surface, 33 sections), and `examples/tasks-app` (a full GNOME task manager — a port of the [gtkx tutorial](https://gtkx.dev/tutorial/)'s Tasks app, and the platform's most demanding app so far) — 1,800 tests (unit + component tests under headless Wayland).
|
|
48
|
-
|
|
49
|
-
## Navigation is native, not redrawn
|
|
50
|
-
|
|
51
|
-
```tsx
|
|
52
|
-
import { NavigationContainer } from "@react-navigation/native"
|
|
53
|
-
import { createStackNavigator } from "react-native-gtkx/navigation"
|
|
31
|
+
<table align="center">
|
|
32
|
+
<tr>
|
|
33
|
+
<th>react-native-gtkx (GTK4)</th>
|
|
34
|
+
<th>react-native-web (browser)</th>
|
|
35
|
+
</tr>
|
|
36
|
+
<tr>
|
|
37
|
+
<td><img src="https://raw.githubusercontent.com/itsmepetrov/react-native-gtkx/main/docs/shots/profile.png" width="400" alt="profile — GTK"/></td>
|
|
38
|
+
<td><img src="https://raw.githubusercontent.com/itsmepetrov/react-native-gtkx/main/docs/shots/profile-web.png" width="400" alt="profile — web"/></td>
|
|
39
|
+
</tr>
|
|
40
|
+
</table>
|
|
41
|
+
|
|
42
|
+
## Quickstart
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx degit itsmepetrov/react-native-gtkx/template my-app && cd my-app
|
|
46
|
+
npm install && npm run dev # a window, with Fast Refresh
|
|
54
47
|
```
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
react-navigation state stays the source of truth. The consequence: the back
|
|
58
|
-
button, the slide transition, Escape, the back gesture and the back-history
|
|
59
|
-
menu are the platform's, not a JS re-implementation — and a native pop is
|
|
60
|
-
reported back into react-navigation state instead of fighting it. Screen
|
|
61
|
-
options map onto the real chrome (`title`, `headerShown`, `gestureEnabled`
|
|
62
|
-
→ the page's `can-pop`, which is also what makes `usePreventRemove` work),
|
|
63
|
-
`headerLeft`/`headerRight` accept ordinary React Native content rendered
|
|
64
|
-
_inside_ the HeaderBar, and `createSidebarNavigator` gives the desktop
|
|
65
|
-
answer to a drawer: a persistent `Adw.NavigationSplitView` sidebar
|
|
66
|
-
(`examples/gallery` runs on it).
|
|
67
|
-
|
|
68
|
-
**No other out-of-tree React Native platform does this.** react-native-screens
|
|
69
|
-
lists Windows support, but it is an old-architecture stub that does not build
|
|
70
|
-
against modern react-native-windows — Microsoft's own showcase app falls back
|
|
71
|
-
to the JS drawer; react-native-macos is not supported by it at all, because
|
|
72
|
-
AppKit has no navigation-stack primitive to bind to. GTK4/libadwaita does have
|
|
73
|
-
one, so the model here is the iOS `native-stack` one:
|
|
74
|
-
[docs/research/navigation-extensibility.md](https://github.com/itsmepetrov/react-native-gtkx/blob/main/docs/research/navigation-extensibility.md)
|
|
75
|
-
lays out the split, what an app can reach, and what is meaningless on a
|
|
76
|
-
desktop.
|
|
77
|
-
|
|
78
|
-
Underneath it, [`react-native-gtkx/gtk` and `react-native-gtkx/adw`](https://github.com/itsmepetrov/react-native-gtkx/blob/main/docs/platform-layer.md) exposes the
|
|
79
|
-
widgets themselves — including a navigation stack that needs no router at
|
|
80
|
-
all, and GTK widgets that take a React Native `style` for position and
|
|
81
|
-
appearance. react-navigation is a convenience here, not the ceiling.
|
|
82
|
-
|
|
83
|
-
## Performance architecture
|
|
84
|
-
|
|
85
|
-
There is no "bridge tax" here. React Native's historic bottleneck — JSON
|
|
86
|
-
batches serialized between the JS and native threads — does not exist in this
|
|
87
|
-
architecture: gtkx binds GTK through an in-process FFI (NAPI-RS), so a widget
|
|
88
|
-
call is a synchronous C call on the same thread, with numbers and pointers
|
|
89
|
-
marshalled directly. That is the same direction React Native itself took with
|
|
90
|
-
JSI/Fabric, where Yoga and view commits run through direct synchronous calls.
|
|
91
|
-
|
|
92
|
-
Layout math runs in Yoga compiled to WASM (near-native speed): a 500-node
|
|
93
|
-
reflow measures at 0.13–0.17 ms. The GTK side is driven by our own
|
|
94
|
-
GtkLayoutManager subclass; a full measure+allocate pass over a 50-child
|
|
95
|
-
container costs ~0.21 ms including every FFI hop. Animation frames bypass
|
|
96
|
-
layout entirely — an Animated value write is a WeakMap store plus one queued
|
|
97
|
-
GTK allocation. Two orders of magnitude of headroom against a 60 fps frame
|
|
98
|
-
budget, measured, not estimated (see docs/research/yoga-gtk-spike.md and
|
|
99
|
-
docs/research/layout-manager.md).
|
|
100
|
-
|
|
101
|
-
Those are this layer's own costs, and a scrolling-list study measured what
|
|
102
|
-
share of a real frame they are: 0.6 ms of a 44.5 ms frame at full screen,
|
|
103
|
-
where the rest is software rasterization on a GPU-less test VM. Windowed,
|
|
104
|
-
a `FlatList` is indistinguishable from a native `GtkScrolledWindow`. Read
|
|
105
|
-
that as "the compatibility layer is not what costs frames on that rig"
|
|
106
|
-
rather than as an absolute — the same study retracted an earlier headline
|
|
107
|
-
number that had compared two different window sizes
|
|
108
|
-
(docs/research/scroll-performance.md).
|
|
49
|
+
Adding Linux to an app that already ships iOS/Android is `npm install react-native-gtkx`, a one-line Metro config wrap, and `npx react-native run-linux` — see [installation](https://github.com/itsmepetrov/react-native-gtkx/blob/main/docs/guide/installation.md).
|
|
109
50
|
|
|
110
51
|
## Documentation
|
|
111
52
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
- [
|
|
115
|
-
- [
|
|
116
|
-
- [
|
|
117
|
-
- [
|
|
118
|
-
- [
|
|
119
|
-
- [What we need from gtkx](https://github.com/itsmepetrov/react-native-gtkx/blob/main/docs/upstream-gtkx.md) — the standing upstream agenda (bugs with repros, API asks, workarounds we want to delete);
|
|
120
|
-
- [CONTRIBUTING](https://github.com/itsmepetrov/react-native-gtkx/blob/main/CONTRIBUTING.md) — developing the library (from macOS — via the UTM VM).
|
|
53
|
+
The full docs, including screenshots per component and a searchable reference, are published at [itsmepetrov.github.io/react-native-gtkx](https://itsmepetrov.github.io/react-native-gtkx/) (source in this repo's `docs/` tree):
|
|
54
|
+
|
|
55
|
+
- [Guide](https://itsmepetrov.github.io/react-native-gtkx/docs/guide/installation) — [installation](https://itsmepetrov.github.io/react-native-gtkx/docs/guide/installation), [your first app](https://itsmepetrov.github.io/react-native-gtkx/docs/guide/first-app), [Metro vs. vite toolchains](https://itsmepetrov.github.io/react-native-gtkx/docs/guide/toolchains), the [plain-GTK profile](https://itsmepetrov.github.io/react-native-gtkx/docs/guide/plain-gtk), [packaging](https://itsmepetrov.github.io/react-native-gtkx/docs/guide/packaging) (debs, standalone).
|
|
56
|
+
- [Reference](https://itsmepetrov.github.io/react-native-gtkx/docs/reference) — every component and API, each with its GTK/Adw badge and its differences from React Native.
|
|
57
|
+
- [Architecture](https://itsmepetrov.github.io/react-native-gtkx/docs/architecture/overview) — [overview](https://itsmepetrov.github.io/react-native-gtkx/docs/architecture/overview) (the reconciler-to-gtkx path, the widget surface), [layout and styling](https://itsmepetrov.github.io/react-native-gtkx/docs/architecture/layout-and-styling) (the Yoga shadow tree, the style split), [gestures](https://itsmepetrov.github.io/react-native-gtkx/docs/architecture/gestures), and [window/navigation/settings integration](https://itsmepetrov.github.io/react-native-gtkx/docs/architecture/integration).
|
|
58
|
+
- [gtkx upstream agenda](https://github.com/itsmepetrov/react-native-gtkx/blob/main/docs/upstream-gtkx.md) — the standing agenda for gtkx itself.
|
|
59
|
+
- [CONTRIBUTING](https://github.com/itsmepetrov/react-native-gtkx/blob/main/CONTRIBUTING.md) — developing the library from macOS, via a Linux VM.
|
|
121
60
|
|
|
122
61
|
## Requirements
|
|
123
62
|
|
package/dist/adw/index.js
CHANGED
|
@@ -49,8 +49,9 @@ export { Adw } from "../gtkx/bridge/adw-namespace";
|
|
|
49
49
|
// (the `breakpoints` prop of AdwApplicationWindow/AdwBreakpointBin/AdwDialog
|
|
50
50
|
// takes one of these as a child) and the two leaf elements a
|
|
51
51
|
// AdwShortcutsDialog's AdwShortcutsSection is built from. See
|
|
52
|
-
// docs/
|
|
53
|
-
//
|
|
52
|
+
// docs/architecture/overview.md, "The widget surface: wrapped, raw, and
|
|
53
|
+
// auxiliary", and docs/architecture/layout-and-styling.md, "Two ways to
|
|
54
|
+
// react to size" — createSidebarNavigator's own collapse
|
|
54
55
|
// (src/navigation/sidebar.tsx) pairs AdwBreakpoint with AdwBreakpointBin
|
|
55
56
|
// (a real widget, wrapped above) to scope a breakpoint to a subtree.
|
|
56
57
|
const { AdwBreakpoint, AdwShortcutsItem, AdwShortcutsSection, AdwToggle } = requireAdwJsx("react-native-gtkx/adw");
|
package/dist/adw/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adw/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,iEAAiE;AACjE,8DAA8D;AAC9D,yFAAyF;AACzF,4BAA4B;AAC5B,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,EAAE;AACF,wEAAwE;AACxE,6EAA6E;AAC7E,yEAAyE;AACzE,4EAA4E;AAC5E,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,2EAA2E;AAC3E,4DAA4D;AAC5D,EAAE;AACF,wEAAwE;AACxE,6EAA6E;AAC7E,yEAAyE;AACzE,mEAAmE;AACnE,6EAA6E;AAC7E,6EAA6E;AAC7E,oEAAoE;AACpE,0DAA0D;AAC1D,cAAc,qBAAqB,CAAA;AAEnC,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,2EAA2E;AAC3E,0EAA0E;AAC1E,yEAAyE;AACzE,0EAA0E;AAC1E,qEAAqE;AACrE,0EAA0E;AAC1E,sEAAsE;AACtE,2EAA2E;AAC3E,0EAA0E;AAC1E,sEAAsE;AACtE,sEAAsE;AACtE,2EAA2E;AAC3E,wEAAwE;AACxE,oCAAoC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,8BAA8B,CAAA;AAElD,oEAAoE;AACpE,0EAA0E;AAC1E,6EAA6E;AAC7E,6DAA6D;AAC7D,8DAA8D;AAC9D,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adw/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,iEAAiE;AACjE,8DAA8D;AAC9D,yFAAyF;AACzF,4BAA4B;AAC5B,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,EAAE;AACF,wEAAwE;AACxE,6EAA6E;AAC7E,yEAAyE;AACzE,4EAA4E;AAC5E,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,2EAA2E;AAC3E,4DAA4D;AAC5D,EAAE;AACF,wEAAwE;AACxE,6EAA6E;AAC7E,yEAAyE;AACzE,mEAAmE;AACnE,6EAA6E;AAC7E,6EAA6E;AAC7E,oEAAoE;AACpE,0DAA0D;AAC1D,cAAc,qBAAqB,CAAA;AAEnC,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,2EAA2E;AAC3E,0EAA0E;AAC1E,yEAAyE;AACzE,0EAA0E;AAC1E,qEAAqE;AACrE,0EAA0E;AAC1E,sEAAsE;AACtE,2EAA2E;AAC3E,0EAA0E;AAC1E,sEAAsE;AACtE,sEAAsE;AACtE,2EAA2E;AAC3E,wEAAwE;AACxE,oCAAoC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,8BAA8B,CAAA;AAElD,oEAAoE;AACpE,0EAA0E;AAC1E,6EAA6E;AAC7E,6DAA6D;AAC7D,8DAA8D;AAC9D,wEAAwE;AACxE,wEAAwE;AACxE,yDAAyD;AACzD,yEAAyE;AACzE,qEAAqE;AACrE,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,SAAS,EAAE,GACvE,aAAa,CAAC,uBAAuB,CAAC,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,SAAS,EAAE,CAAA","sourcesContent":["// react-native-gtkx/adw — libadwaita widgets as React components.\n//\n// The Adwaita half of the platform layer; its GTK counterpart is\n// react-native-gtkx/gtk, and what we wrote ourselves lives in\n// react-native-gtkx/common (NavigationStack, SlotContent, wrapReactNative). Nothing here\n// imports react-navigation.\n//\n// NAMING, one rule across both subpaths: a name carrying a `Gtk` or `Adw`\n// prefix IS that widget, as gtkx binds it. A name without a prefix is ours.\n//\n// The layering mirrors the React Native ecosystem: react-native-screens\n// exposes primitives, @react-navigation/native-stack binds them to a router.\n// Here, this subpath exposes primitives and react-native-gtkx/navigation\n// binds them to react-navigation. You can skip the binding entirely — drive\n// NavigationStack from useState, from your own router, from anything.\nimport { requireAdwJsx } from \"../gtkx/bridge/adw\"\n\n// The raw widgets, exactly as gtkx binds them — every GObject property and\n// signal, including ones added after this file was written.\n//\n// AdwNavigationView and AdwNavigationPage are the imperative originals:\n// NavigationStack above is a declarative alternative, NOT a replacement, and\n// a standard widget must never become unreachable because we wrapped it.\n// The full Adwaita widget surface lives in a generated file: every\n// Adw.Widget subclass gtkx binds, wrapped so React Native drives it. The raw\n// AdwNavigationView and AdwNavigationPage are in there too — NavigationStack\n// in react-native-gtkx/common is a declarative alternative, never a\n// replacement, and a standard widget must stay reachable.\nexport * from \"./widgets.generated\"\n\n// This whole subpath REQUIRES Adw-1 (see .claude/epics/adw-optional/001.md\n// and docs/api.md) — a bare re-export of an actual namespace import (see\n// gtkx/bridge/adw-namespace.ts), so `Adw` keeps working exactly as it did\n// before this epic: both a value (`Adw.Toast.new(title)`, `Adw.ColorScheme\n// .FORCE_DARK`) and a namespace in type position (`Ref<Adw.ToastOverlay |\n// null>`), in ONE import, from real apps (examples/tasks-app/tasks-nav's\n// toast.tsx and window.tsx, examples/gallery's adwaita-stack.tsx) as well\n// as ours. That duality does not survive being synthesized through a\n// function call (tried: adw.ts's requireAdwGi() — the value comes through\n// fine, but \"Cannot find namespace 'Adw'\" everywhere it was used as a\n// type), which is why this is a re-export of a plain, eager, static import\n// rather than routed through the lazy probe every other Adw value in this\n// package goes through. Importing react-native-gtkx/adw without Adw-1\n// throws at import time regardless — just as a build failure one line\n// down (adw-namespace.ts's own `@gtkx/gi/adw` import, unresolvable without\n// it) instead of a thrown Error, which is an equally loud refusal for a\n// subpath that always requires Adw.\nexport { Adw } from \"../gtkx/bridge/adw-namespace\"\n\n// Auxiliary JSX elements that are not Adw.Widget subclasses, so the\n// generated widget surface above never sees them: a responsive breakpoint\n// (the `breakpoints` prop of AdwApplicationWindow/AdwBreakpointBin/AdwDialog\n// takes one of these as a child) and the two leaf elements a\n// AdwShortcutsDialog's AdwShortcutsSection is built from. See\n// docs/architecture/overview.md, \"The widget surface: wrapped, raw, and\n// auxiliary\", and docs/architecture/layout-and-styling.md, \"Two ways to\n// react to size\" — createSidebarNavigator's own collapse\n// (src/navigation/sidebar.tsx) pairs AdwBreakpoint with AdwBreakpointBin\n// (a real widget, wrapped above) to scope a breakpoint to a subtree.\nconst { AdwBreakpoint, AdwShortcutsItem, AdwShortcutsSection, AdwToggle } =\n requireAdwJsx(\"react-native-gtkx/adw\")\nexport { AdwBreakpoint, AdwShortcutsItem, AdwShortcutsSection, AdwToggle }\n"]}
|
|
@@ -6,7 +6,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
// Both go through `Controllers` from react-native-gtkx/gtk — the same public
|
|
7
7
|
// door an app would use. Nothing here is reachable only from inside the
|
|
8
8
|
// platform, which is the property `List`/`ListRow` already established
|
|
9
|
-
// (docs/
|
|
9
|
+
// (docs/architecture/overview.md).
|
|
10
10
|
import { useRef } from "react";
|
|
11
11
|
import { Controllers } from "../gtk/controllers";
|
|
12
12
|
import { beginDragLayer, Gdk, GObject, Gtk, GtkDragSource, GtkDropTarget, } from "../gtkx/bridge/index";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gtk-controllers.js","sourceRoot":"","sources":["../../src/dnd/gtk-controllers.tsx"],"names":[],"mappings":"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","sourcesContent":["// The two GTK controllers everything in this module is built from, wrapped\n// once so `Draggable`, `Droppable` and `SortableItem` do not each re-derive\n// the drag-icon and payload details.\n//\n// Both go through `Controllers` from react-native-gtkx/gtk — the same public\n// door an app would use. Nothing here is reachable only from inside the\n// platform, which is the property `List`/`ListRow` already established\n// (docs/platform-layer.md).\nimport { useRef, type ReactNode } from \"react\"\nimport { Controllers } from \"../gtk/controllers\"\nimport {\n beginDragLayer,\n Gdk,\n GObject,\n Gtk,\n GtkDragSource,\n GtkDropTarget,\n type DragLayerHandle,\n} from \"../gtkx/bridge/index\"\nimport { decodePayload, encodePayload, type DragPayload } from \"./payload\"\n\nexport type DragSourceControllersProps = {\n payload: DragPayload\n /** Reports the grab point in the source widget's own coordinates, which is\n * where the drag icon's hotspot goes and where `tx`/`ty` start from. The\n * widget itself rides along too — `Sortable`/`SortableGrid` use it to\n * convert this point into their own container's coordinates with\n * `computePointIn` (see sortable.tsx/grid.tsx), the origin their reorder\n * tracking measures every subsequent motion event against. `null` only\n * when GDK could not resolve a widget for the drag source itself, which\n * should not happen in practice. */\n onGrab?: (x: number, y: number, widget: Gtk.Widget | null) => void\n onDragBegin?: () => void\n /** `dropped` is what GDK's own `drag-end` reports: whether a target took\n * it. `drag-cancel` reports the negative case separately, so both are\n * folded into one callback here. */\n onDragEnd?: (dropped: boolean) => void\n}\n\n/**\n * A `GtkDragSource` on the enclosing React Native component's widget.\n *\n * The drag icon is a `Gtk.WidgetPaintable` of that widget, offset by where\n * inside it the drag began — so the thing appears to lift off under the\n * cursor rather than jump to it. That is the visual no JS drag can produce,\n * and the reason this module is built on GDK at all.\n *\n * A second, window-level copy of the same picture rides alongside it for as\n * long as the drag stays over this window — `gtkx/bridge/drag-layer.ts` has\n * the reason: `setIcon`'s own icon is a compositor surface, unclipped by any\n * `overflow: hidden` ancestor but also outside this process's own widget\n * tree, so nothing in it can prove that escape happened. The window-level\n * copy is the same escape, provable.\n */\nexport const DragSourceControllers = ({\n payload,\n onGrab,\n onDragBegin,\n onDragEnd,\n}: DragSourceControllersProps): ReactNode => {\n // GDK emits `drag-cancel` AND then `drag-end` for a refused drop, so the\n // cancel is recorded and read by the end handler rather than reported\n // twice.\n const cancelled = useRef(false)\n // Set in `onPrepare`, consumed in `onDragBegin` — the window-level layer\n // only starts once GDK confirms the drag is really happening, but the\n // widget and grab point it needs are only ever handed to `onPrepare`.\n const grab = useRef<{ widget: Gtk.Widget; x: number; y: number } | null>(null)\n const dragLayer = useRef<DragLayerHandle | null>(null)\n\n return (\n <Controllers>\n <GtkDragSource\n actions={Gdk.DragAction.MOVE}\n onPrepare={(x, y, self) => {\n const widget = self.getWidget()\n if (widget) {\n self.setIcon(\n Gtk.WidgetPaintable.new(widget),\n Math.round(x),\n Math.round(y),\n )\n grab.current = { widget, x, y }\n }\n onGrab?.(x, y, widget)\n return Gdk.ContentProvider.newForValue(\n GObject.buildValue(GObject.TYPE_STRING, (value) =>\n value.setString(encodePayload(payload)),\n ),\n )\n }}\n onDragBegin={() => {\n cancelled.current = false\n if (grab.current) {\n dragLayer.current = beginDragLayer(\n grab.current.widget,\n grab.current.x,\n grab.current.y,\n )\n }\n onDragBegin?.()\n }}\n onDragCancel={() => {\n cancelled.current = true\n // false: let GTK play its own \"snap back\" animation, which is the\n // platform's way of saying the drop was refused.\n return false\n }}\n onDragEnd={() => {\n dragLayer.current?.end()\n dragLayer.current = null\n onDragEnd?.(!cancelled.current)\n }}\n />\n </Controllers>\n )\n}\n\nexport type DropTargetControllersProps = {\n /** Return false to refuse — GDK then shows the no-drop cursor, which is\n * better feedback than upstream's silent skip. */\n accepts: (payload: DragPayload) => boolean\n onDrop: (payload: DragPayload, x: number, y: number) => void\n onEnter?: (payload: DragPayload) => void\n onMotion?: (payload: DragPayload, x: number, y: number) => void\n onLeave?: () => void\n}\n\n/**\n * A `GtkDropTarget` on the enclosing React Native component's widget,\n * accepting the string payload this module encodes.\n *\n * The payload is decoded before `accepts` is consulted, so a string dragged\n * in from a text editor is refused rather than mistaken for a draggable.\n */\nexport const DropTargetControllers = ({\n accepts,\n onDrop,\n onEnter,\n onMotion,\n onLeave,\n}: DropTargetControllersProps): ReactNode => {\n // The payload of the drag currently overhead, sampled on `::enter` and kept\n // for `::motion` (which is not handed the target).\n const hovering = useRef<DragPayload | null>(null)\n\n return (\n <Controllers>\n <GtkDropTarget\n actions={Gdk.DragAction.MOVE}\n types={[GObject.TYPE_STRING]}\n // Without this `gtk_drop_target_get_value()` returns NULL until the\n // drop itself, so `::enter` could not tell one drag from another and\n // every zone would light up for every payload. Preloading is exactly\n // the property GTK provides for reading the data during the drag; the\n // cost it warns about (fetching data from another process on hover)\n // does not apply, because the payload is a short string this process\n // wrote.\n preload\n onEnter={(_x, _y, self) => {\n const payload = payloadOf(self)\n hovering.current = payload\n // A payload that is not readable yet is NOT refused: refusing in\n // `::enter` ends the drag for this target permanently, while\n // accepting and re-checking at drop time is recoverable. Only a\n // payload we can read AND reject is turned away.\n if (payload && !accepts(payload)) {\n return Gdk.DragAction.NONE\n }\n if (payload) {\n onEnter?.(payload)\n }\n return Gdk.DragAction.MOVE\n }}\n onMotion={(x, y) => {\n const payload = hovering.current\n if (payload && !accepts(payload)) {\n return Gdk.DragAction.NONE\n }\n if (payload) {\n onMotion?.(payload, x, y)\n }\n return Gdk.DragAction.MOVE\n }}\n onLeave={() => {\n hovering.current = null\n onLeave?.()\n }}\n onDrop={(value, x, y) => {\n hovering.current = null\n const payload = decodePayload(value.getString())\n if (!payload || !accepts(payload)) {\n return false\n }\n onDrop(payload, x, y)\n return true\n }}\n />\n </Controllers>\n )\n}\n\n/**\n * The payload of the drag currently over a drop target, readable during the\n * drag because the target above sets `preload`.\n */\nconst payloadOf = (target: Gtk.DropTarget): DragPayload | null => {\n const value = target.getValue()\n if (!value) {\n return null\n }\n return decodePayload(value.getString())\n}\n"]}
|
|
1
|
+
{"version":3,"file":"gtk-controllers.js","sourceRoot":"","sources":["../../src/dnd/gtk-controllers.tsx"],"names":[],"mappings":"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","sourcesContent":["// The two GTK controllers everything in this module is built from, wrapped\n// once so `Draggable`, `Droppable` and `SortableItem` do not each re-derive\n// the drag-icon and payload details.\n//\n// Both go through `Controllers` from react-native-gtkx/gtk — the same public\n// door an app would use. Nothing here is reachable only from inside the\n// platform, which is the property `List`/`ListRow` already established\n// (docs/architecture/overview.md).\nimport { useRef, type ReactNode } from \"react\"\nimport { Controllers } from \"../gtk/controllers\"\nimport {\n beginDragLayer,\n Gdk,\n GObject,\n Gtk,\n GtkDragSource,\n GtkDropTarget,\n type DragLayerHandle,\n} from \"../gtkx/bridge/index\"\nimport { decodePayload, encodePayload, type DragPayload } from \"./payload\"\n\nexport type DragSourceControllersProps = {\n payload: DragPayload\n /** Reports the grab point in the source widget's own coordinates, which is\n * where the drag icon's hotspot goes and where `tx`/`ty` start from. The\n * widget itself rides along too — `Sortable`/`SortableGrid` use it to\n * convert this point into their own container's coordinates with\n * `computePointIn` (see sortable.tsx/grid.tsx), the origin their reorder\n * tracking measures every subsequent motion event against. `null` only\n * when GDK could not resolve a widget for the drag source itself, which\n * should not happen in practice. */\n onGrab?: (x: number, y: number, widget: Gtk.Widget | null) => void\n onDragBegin?: () => void\n /** `dropped` is what GDK's own `drag-end` reports: whether a target took\n * it. `drag-cancel` reports the negative case separately, so both are\n * folded into one callback here. */\n onDragEnd?: (dropped: boolean) => void\n}\n\n/**\n * A `GtkDragSource` on the enclosing React Native component's widget.\n *\n * The drag icon is a `Gtk.WidgetPaintable` of that widget, offset by where\n * inside it the drag began — so the thing appears to lift off under the\n * cursor rather than jump to it. That is the visual no JS drag can produce,\n * and the reason this module is built on GDK at all.\n *\n * A second, window-level copy of the same picture rides alongside it for as\n * long as the drag stays over this window — `gtkx/bridge/drag-layer.ts` has\n * the reason: `setIcon`'s own icon is a compositor surface, unclipped by any\n * `overflow: hidden` ancestor but also outside this process's own widget\n * tree, so nothing in it can prove that escape happened. The window-level\n * copy is the same escape, provable.\n */\nexport const DragSourceControllers = ({\n payload,\n onGrab,\n onDragBegin,\n onDragEnd,\n}: DragSourceControllersProps): ReactNode => {\n // GDK emits `drag-cancel` AND then `drag-end` for a refused drop, so the\n // cancel is recorded and read by the end handler rather than reported\n // twice.\n const cancelled = useRef(false)\n // Set in `onPrepare`, consumed in `onDragBegin` — the window-level layer\n // only starts once GDK confirms the drag is really happening, but the\n // widget and grab point it needs are only ever handed to `onPrepare`.\n const grab = useRef<{ widget: Gtk.Widget; x: number; y: number } | null>(null)\n const dragLayer = useRef<DragLayerHandle | null>(null)\n\n return (\n <Controllers>\n <GtkDragSource\n actions={Gdk.DragAction.MOVE}\n onPrepare={(x, y, self) => {\n const widget = self.getWidget()\n if (widget) {\n self.setIcon(\n Gtk.WidgetPaintable.new(widget),\n Math.round(x),\n Math.round(y),\n )\n grab.current = { widget, x, y }\n }\n onGrab?.(x, y, widget)\n return Gdk.ContentProvider.newForValue(\n GObject.buildValue(GObject.TYPE_STRING, (value) =>\n value.setString(encodePayload(payload)),\n ),\n )\n }}\n onDragBegin={() => {\n cancelled.current = false\n if (grab.current) {\n dragLayer.current = beginDragLayer(\n grab.current.widget,\n grab.current.x,\n grab.current.y,\n )\n }\n onDragBegin?.()\n }}\n onDragCancel={() => {\n cancelled.current = true\n // false: let GTK play its own \"snap back\" animation, which is the\n // platform's way of saying the drop was refused.\n return false\n }}\n onDragEnd={() => {\n dragLayer.current?.end()\n dragLayer.current = null\n onDragEnd?.(!cancelled.current)\n }}\n />\n </Controllers>\n )\n}\n\nexport type DropTargetControllersProps = {\n /** Return false to refuse — GDK then shows the no-drop cursor, which is\n * better feedback than upstream's silent skip. */\n accepts: (payload: DragPayload) => boolean\n onDrop: (payload: DragPayload, x: number, y: number) => void\n onEnter?: (payload: DragPayload) => void\n onMotion?: (payload: DragPayload, x: number, y: number) => void\n onLeave?: () => void\n}\n\n/**\n * A `GtkDropTarget` on the enclosing React Native component's widget,\n * accepting the string payload this module encodes.\n *\n * The payload is decoded before `accepts` is consulted, so a string dragged\n * in from a text editor is refused rather than mistaken for a draggable.\n */\nexport const DropTargetControllers = ({\n accepts,\n onDrop,\n onEnter,\n onMotion,\n onLeave,\n}: DropTargetControllersProps): ReactNode => {\n // The payload of the drag currently overhead, sampled on `::enter` and kept\n // for `::motion` (which is not handed the target).\n const hovering = useRef<DragPayload | null>(null)\n\n return (\n <Controllers>\n <GtkDropTarget\n actions={Gdk.DragAction.MOVE}\n types={[GObject.TYPE_STRING]}\n // Without this `gtk_drop_target_get_value()` returns NULL until the\n // drop itself, so `::enter` could not tell one drag from another and\n // every zone would light up for every payload. Preloading is exactly\n // the property GTK provides for reading the data during the drag; the\n // cost it warns about (fetching data from another process on hover)\n // does not apply, because the payload is a short string this process\n // wrote.\n preload\n onEnter={(_x, _y, self) => {\n const payload = payloadOf(self)\n hovering.current = payload\n // A payload that is not readable yet is NOT refused: refusing in\n // `::enter` ends the drag for this target permanently, while\n // accepting and re-checking at drop time is recoverable. Only a\n // payload we can read AND reject is turned away.\n if (payload && !accepts(payload)) {\n return Gdk.DragAction.NONE\n }\n if (payload) {\n onEnter?.(payload)\n }\n return Gdk.DragAction.MOVE\n }}\n onMotion={(x, y) => {\n const payload = hovering.current\n if (payload && !accepts(payload)) {\n return Gdk.DragAction.NONE\n }\n if (payload) {\n onMotion?.(payload, x, y)\n }\n return Gdk.DragAction.MOVE\n }}\n onLeave={() => {\n hovering.current = null\n onLeave?.()\n }}\n onDrop={(value, x, y) => {\n hovering.current = null\n const payload = decodePayload(value.getString())\n if (!payload || !accepts(payload)) {\n return false\n }\n onDrop(payload, x, y)\n return true\n }}\n />\n </Controllers>\n )\n}\n\n/**\n * The payload of the drag currently over a drop target, readable during the\n * drag because the target above sets `preload`.\n */\nconst payloadOf = (target: Gtk.DropTarget): DragPayload | null => {\n const value = target.getValue()\n if (!value) {\n return null\n }\n return decodePayload(value.getString())\n}\n"]}
|
package/dist/gtk/index.js
CHANGED
|
@@ -13,7 +13,8 @@ export { Gdk, Gio, GLib, GObject, Gtk, Pango } from "../gtkx/bridge/index";
|
|
|
13
13
|
// `Gtk.Application`/`Gtk.ApplicationWindow`), a text buffer and an
|
|
14
14
|
// adjustment (the model objects `GtkTextView`/`GtkSpinRow`-style widgets
|
|
15
15
|
// bind to), keyboard shortcuts, and the two drag-and-drop controllers. See
|
|
16
|
-
// docs/
|
|
16
|
+
// docs/architecture/overview.md, "The widget surface: wrapped, raw, and
|
|
17
|
+
// auxiliary".
|
|
17
18
|
export { GMenu, GtkAdjustment, GtkDragSource, GtkDropControllerMotion, GtkDropTarget, GtkShortcut, GtkShortcutController, GtkTextBuffer, } from "../gtkx/bridge/index";
|
|
18
19
|
// Window and application actions declared inside the app tree instead of
|
|
19
20
|
// around it (the AppRegistry options they replace cannot see app context —
|
|
@@ -31,7 +32,7 @@ export { Controllers } from "./controllers";
|
|
|
31
32
|
// GSettings: reads and writes backed by a compiled `.gschema.xml` schema.
|
|
32
33
|
// `useSetting`/`useBindSetting` come straight from @gtkx/react; loading a
|
|
33
34
|
// `.gschema.xml` file into the `SettingsSchema` object they expect is a
|
|
34
|
-
// build-time concern (see docs/
|
|
35
|
+
// build-time concern (see docs/architecture/integration.md, "GSettings").
|
|
35
36
|
export { useBindSetting, useSetting, } from "../gtkx/bridge/index";
|
|
36
37
|
// @gtkx/css — a real GTK CSS class from a tagged template, the same
|
|
37
38
|
// mechanism the style prop's visual half uses under the hood. Re-exported
|
|
@@ -40,7 +41,7 @@ export { useBindSetting, useSetting, } from "../gtkx/bridge/index";
|
|
|
40
41
|
// surface, not just Gtk.Widget subclasses. `GObject` above is exported
|
|
41
42
|
// mainly for `GObject.Value` — constructing a boxed value is required by
|
|
42
43
|
// APIs like `Adw.Breakpoint.addSetter`, which reject a bare JS primitive
|
|
43
|
-
// (see docs/
|
|
44
|
+
// (see docs/architecture/layout-and-styling.md, "Two ways to react to size").
|
|
44
45
|
export { css, cx, injectGlobal } from "../gtkx/bridge/index";
|
|
45
46
|
// The window and application AppRegistry itself sits on: useParentWindow
|
|
46
47
|
// reaches the Gtk.Window ancestor (for anything not modeled by a prop —
|
package/dist/gtk/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gtk/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8DAA8D;AAC9D,yCAAyC;AACzC,0EAA0E;AAC1E,cAAc,qBAAqB,CAAA;AAEnC,4EAA4E;AAC5E,8EAA8E;AAC9E,mCAAmC;AACnC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAE1E,oEAAoE;AACpE,0EAA0E;AAC1E,oEAAoE;AACpE,mEAAmE;AACnE,yEAAyE;AACzE,2EAA2E;AAC3E,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gtk/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8DAA8D;AAC9D,yCAAyC;AACzC,0EAA0E;AAC1E,cAAc,qBAAqB,CAAA;AAEnC,4EAA4E;AAC5E,8EAA8E;AAC9E,mCAAmC;AACnC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAE1E,oEAAoE;AACpE,0EAA0E;AAC1E,oEAAoE;AACpE,mEAAmE;AACnE,yEAAyE;AACzE,2EAA2E;AAC3E,wEAAwE;AACxE,cAAc;AACd,OAAO,EACL,KAAK,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,aAAa,EACb,WAAW,EACX,qBAAqB,EACrB,aAAa,GACd,MAAM,sBAAsB,CAAA;AAE7B,yEAAyE;AACzE,2EAA2E;AAC3E,qEAAqE;AACrE,yEAAyE;AACzE,oEAAoE;AACpE,aAAa;AACb,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,iBAAiB,GAKlB,MAAM,kBAAkB,CAAA;AAEzB,4EAA4E;AAC5E,2EAA2E;AAC3E,4EAA4E;AAC5E,yEAAyE;AACzE,uCAAuC;AACvC,OAAO,EAAE,WAAW,EAAyB,MAAM,eAAe,CAAA;AAElE,0EAA0E;AAC1E,0EAA0E;AAC1E,wEAAwE;AACxE,0EAA0E;AAC1E,OAAO,EACL,cAAc,EACd,UAAU,GAIX,MAAM,sBAAsB,CAAA;AAE7B,oEAAoE;AACpE,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAC1E,uEAAuE;AACvE,yEAAyE;AACzE,yEAAyE;AACzE,8EAA8E;AAC9E,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAE5D,yEAAyE;AACzE,wEAAwE;AACxE,uEAAuE;AACvE,6DAA6D;AAC7D,yEAAyE;AACzE,mEAAmE;AACnE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA","sourcesContent":["// The full GTK widget surface lives in a generated file: every Gtk.Widget\n// subclass gtkx binds, wrapped so React Native drives it. See\n// scripts/generate-widget-surface.ts and\n// scripts/widget-surface/classification.json for how the list is derived.\nexport * from \"./widgets.generated\"\n\n// The GTK namespaces themselves, exported as values because they carry both\n// the enums you need at runtime — `hscrollbarPolicy={Gtk.PolicyType.NEVER}` —\n// and the types you need for refs.\nexport { Gdk, Gio, GLib, GObject, Gtk, Pango } from \"../gtkx/bridge/index\"\n\n// Auxiliary JSX elements that are not Gtk.Widget subclasses, so the\n// generated widget surface above never sees them — real building blocks a\n// non-trivial app still needs: actions and menus (Gio, used through\n// `Gtk.Application`/`Gtk.ApplicationWindow`), a text buffer and an\n// adjustment (the model objects `GtkTextView`/`GtkSpinRow`-style widgets\n// bind to), keyboard shortcuts, and the two drag-and-drop controllers. See\n// docs/architecture/overview.md, \"The widget surface: wrapped, raw, and\n// auxiliary\".\nexport {\n GMenu,\n GtkAdjustment,\n GtkDragSource,\n GtkDropControllerMotion,\n GtkDropTarget,\n GtkShortcut,\n GtkShortcutController,\n GtkTextBuffer,\n} from \"../gtkx/bridge/index\"\n\n// Window and application actions declared inside the app tree instead of\n// around it (the AppRegistry options they replace cannot see app context —\n// see window-actions.tsx). GSimpleAction comes from here rather than\n// straight from the bridge because inside these components it arbitrates\n// duplicate action names; on every other path it is gtkx's element,\n// unchanged.\nexport {\n ApplicationActions,\n GSimpleAction,\n WindowActions,\n WindowControllers,\n type ApplicationActionsProps,\n type GSimpleActionProps,\n type WindowActionsProps,\n type WindowControllersProps,\n} from \"./window-actions\"\n\n// The same idea one level down: event controllers attached to the widget of\n// the enclosing React Native component, so a row written in View/Pressable\n// can still carry GTK drag-and-drop. The door onto GTK behaviour that no RN\n// prop expresses — deliberately an element in THIS subpath rather than a\n// prop on `View`, see controllers.tsx.\nexport { Controllers, type ControllersProps } from \"./controllers\"\n\n// GSettings: reads and writes backed by a compiled `.gschema.xml` schema.\n// `useSetting`/`useBindSetting` come straight from @gtkx/react; loading a\n// `.gschema.xml` file into the `SettingsSchema` object they expect is a\n// build-time concern (see docs/architecture/integration.md, \"GSettings\").\nexport {\n useBindSetting,\n useSetting,\n type SettingsSchema,\n type SettingsSchemaKeys,\n type SettingValue,\n} from \"../gtkx/bridge/index\"\n\n// @gtkx/css — a real GTK CSS class from a tagged template, the same\n// mechanism the style prop's visual half uses under the hood. Re-exported\n// here rather than left to a direct @gtkx/css dependency for the same\n// reason the namespaces above are: one subpath for the whole gtkx toolkit\n// surface, not just Gtk.Widget subclasses. `GObject` above is exported\n// mainly for `GObject.Value` — constructing a boxed value is required by\n// APIs like `Adw.Breakpoint.addSetter`, which reject a bare JS primitive\n// (see docs/architecture/layout-and-styling.md, \"Two ways to react to size\").\nexport { css, cx, injectGlobal } from \"../gtkx/bridge/index\"\n\n// The window and application AppRegistry itself sits on: useParentWindow\n// reaches the Gtk.Window ancestor (for anything not modeled by a prop —\n// e.g. binding a GSettings key to its own defaultWidth/defaultHeight),\n// useApplication reaches the Adw.Application (e.g. to send a\n// Gio.Notification), quit tears the whole app down programmatically (the\n// same function AppRegistry wires to a window's own close button).\nexport { quit, useApplication, useParentWindow } from \"../gtkx/bridge/index\"\n"]}
|
package/dist/gtkx/bridge/adw.js
CHANGED
|
@@ -61,7 +61,7 @@ else {
|
|
|
61
61
|
*/
|
|
62
62
|
export const adwAvailable = () => cached !== null && cached !== undefined;
|
|
63
63
|
const NOT_AVAILABLE = ' requires "Adw-1" in this app\'s gtkx.config.ts `libraries` — see ' +
|
|
64
|
-
"docs/
|
|
64
|
+
"docs/guide/plain-gtk.md for what needs Adw unconditionally " +
|
|
65
65
|
"and what falls back without it.";
|
|
66
66
|
/** The repo's loud named throw for a feature that reached for Adw and found
|
|
67
67
|
* none. Every Adw-dependent call site in the seam funnels through this, but
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adw.js","sourceRoot":"","sources":["../../../src/gtkx/bridge/adw.ts"],"names":[],"mappings":"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","sourcesContent":["// The ONLY module allowed to import @gtkx/gi/adw and @gtkx/jsx/adw — see\n// .claude/epics/adw-optional/001.md. Everything the RN core needs lives in\n// ./core instead, with zero Adw imports, so an app whose gtkx.config.ts\n// declares `libraries: [\"Gtk-4.0\"]` alone (no \"Adw-1\") never reaches either\n// specifier: a codegen store generated that way has no \"./adw\" entry in\n// either package's `exports` map AT ALL (empirically verified: neither\n// directory even exists on disk), so a STATIC import of either one fails\n// the whole build — `gtkx build`'s own \"gtkx:undeclared-library\" vite\n// plugin throws while resolving it, unconditionally, whether or not the\n// import is ever reached at runtime.\n//\n// __GTKX_ADW_AVAILABLE__ (declared ambient just below) is a build-time\n// constant the vite preset injects (src/vite/index.ts, see its own doc for\n// the full story — .claude/epics/adw-optional/006.md is the regression this\n// exists to fix): true only when THIS app's codegen store actually has an\n// \"adw\" entry. The probe below guards on it and, only inside that guard,\n// imports @gtkx/gi/adw and @gtkx/jsx/adw as LITERAL specifiers —\n// deliberately, unlike a runtime-assembled string. A hidden specifier is\n// invisible to Rollup's build graph, which sounds like the safer choice,\n// but it is ALSO invisible to everything that graph gives every OTHER gtkx\n// import for free: `resolve.dedupe` (RC4-WORKAROUND(runtime-dedupe) in\n// docs/gtkx-rc4-notes.md) and `gtkx build`'s own asset pipeline for the\n// native addon (`@gtkx/cli`'s `gtkx:native` plugin, which rewrites every\n// STATICALLY reachable `@gtkx/native` import onto the single `dist/gtkx.node`\n// it emits) — a hidden specifier resolves a SECOND, independent copy from\n// node_modules at runtime instead, and two distinct native addons\n// double-initialize the gtkx runtime and abort the process\n// (`g_log_set_writer_func() called multiple times`, proven with a core dump\n// showing both `.node` files mapped into one process). A literal specifier\n// gets the exact same static treatment as every other gtkx import; when the\n// build-time constant folds to `false` instead, dead-code elimination\n// removes the whole guarded body — literal specifiers included — before\n// Rollup's graph walk ever starts, so `gtkx:undeclared-library` never\n// throws on the plain-GTK profile either.\n//\n// No module-scope await, anywhere — the one thing that actually changed\n// here (.claude/epics/adw-optional/007-sea-tla.md): this file used to\n// resolve Adw with a TOP-LEVEL AWAIT (both the #132 guarded literal imports\n// and the fallback probe), so every call site below could stay synchronous\n// without an explicit wait of its own. That broke `react-native\n// build-linux` outright — reproduced empirically in the VM, WITH OR\n// WITHOUT --sea/--standalone (all three share the same Metro `bundle()`\n// call, `--dev false`): Metro's own minifier (metro-minify-terser, i.e.\n// terser) parses each module's compiled factory as a plain SCRIPT, not an\n// ES module — `await` is just an ordinary identifier there, not a keyword,\n// so \"await probeViaDynamicImport()\" is a hard syntax error (\"Unexpected\n// token: name (probeViaDynamicImport)\"), independent of the SEA/rolldown\n// CJS-format restriction the task file also names (CJS has no TLA either —\n// the same file would have failed a second time even past Metro).\n//\n// Tried and reverted: resolving gi through a synchronous `require()` (via\n// `createRequire(import.meta.url)`) instead of a dynamic import — it does\n// answer synchronously under vite build/dev and vitest, but\n// `import.meta.url` is ITSELF ESM-only syntax, exactly like top-level\n// await: Metro's minifier happened not to reject it at minify time (unlike\n// `await`), but Node's own parser does, the moment the Metro/SEA host\n// actually executes the bundle via `vm.runInThisContext` (which runs the\n// whole bundle as a plain SCRIPT, not a module) — \"SyntaxError: Cannot use\n// 'import.meta' outside a module\", reproduced building and running\n// examples/hn-app's SEA artifact. Same class of bug as the TLA one this\n// file exists to fix, so back to a dynamic import for both gi and jsx —\n// their own literal specifiers, unlike ours, are genuinely fine either way\n// since Metro/the SEA host never reach this branch at all (see\n// fromHostModules below) and every other toolchain is real ESM.\n//\n// So: a single, ordinary (non-async, non-top-level-await) function starts\n// BOTH imports together — Promise.all, exactly like the old probe — the\n// moment this module itself finishes evaluating, fire-and-forget (no\n// module-scope await to block on this time). No formal ordering guarantee\n// versus the old TLA probe's, but starting it as early as this module can\n// (not lazily, on the first actual `requireAdwJsx()`/`requireAdwGi()` call)\n// gives it a real, if informal, chance to have already settled — verified\n// against this package's own gtk test suite, including the one caller with\n// the least slack of all: react-native-gtkx/adw's own `adw/index.ts` calls\n// `requireAdwJsx()` eagerly, at ITS OWN module scope, the moment it is\n// imported (immediately after this file). Under Vite's SSR module runner\n// (dev and vitest both), every static import a transformed module has is\n// itself an awaited call in that runner, cached or not — so `adw/index.ts`\n// evaluating is always at least one module-boundary await after this\n// file's own module body, including the Promise.all it starts, finished\n// running. tests/gtk/bridge/auxiliary-elements.gtk.test.tsx (imports\n// react-native-gtkx/adw) and tests/gtk/adw/* are all green under this.\n//\n// The Metro/SEA host fast path (fromHostModules, below) takes priority over\n// all of this and never touches import() at all: `global.__hostModules` is\n// already populated — both gi and jsx together, when present — before the\n// run-linux host or the SEA entry's own async wrapper (src/sea/bundle.ts's\n// `buildEntrySource`, itself already just an ordinary async FUNCTION, never\n// a module-scope await) ever executes the bundle that reaches this file.\nimport type * as AdwGi from \"@gtkx/gi/adw\"\nimport type * as AdwJsx from \"@gtkx/jsx/adw\"\n\n// Assembled rather than written as one literal: used only as a lookup key\n// into global.__hostModules (an object property read, not an import), which\n// the run-linux host populates keyed by these exact strings\n// (HOST_MODULE_EXTERNALS in src/metro/index.ts). Kept opaque to a plain text\n// search for consistency with the rest of this file, not because anything\n// would fail resolving it — fromHostModules never imports.\nconst GI_ADW = [\"@gtkx\", \"gi\", \"adw\"].join(\"/\")\nconst JSX_ADW = [\"@gtkx\", \"jsx\", \"adw\"].join(\"/\")\n\ntype AdwModules = {\n gi: typeof AdwGi\n jsx: typeof AdwJsx\n}\n\ntype HostModulesGlobal = typeof globalThis & {\n __hostModules?: Record<string, unknown>\n}\n\n// The run-linux (Metro) host already resolved every external — including\n// these two, when the app declared \"Adw-1\" — into global.__hostModules\n// BEFORE the bundle ever runs (see src/runner/host.ts) — synchronously, as\n// far as this module is concerned, and the authoritative answer on that\n// toolchain: reading it directly is both correct and avoids a second,\n// redundant resolution attempt Metro's bundler cannot serve anyway (no\n// \"virtual:gtkx-config\" loader hook outside Vite's own pipeline or the\n// host's own module.registerHooks).\n// Returns undefined (not false) when there is no host indirection in play\n// at all — the vite dev/build toolchain, where every spike and example in\n// this repo runs — so the caller knows to fall through to the real probe.\nconst fromHostModules = (): AdwModules | null | undefined => {\n const hostModules = (globalThis as HostModulesGlobal).__hostModules\n if (!hostModules) {\n return undefined\n }\n const gi = hostModules[GI_ADW]\n const jsx = hostModules[JSX_ADW]\n return gi && jsx\n ? { gi: gi as typeof AdwGi, jsx: jsx as typeof AdwJsx }\n : null\n}\n\nconst hostModulesResult = fromHostModules()\n\n// Skips the probe outright when the vite preset has POSITIVELY told us Adw\n// is not in this app's codegen store (see the module doc above for why a\n// literal specifier below needs this guard to exist at all). `typeof`, not\n// a direct reference: safe on any toolchain that never defines the constant\n// (a bare `vitest` \"unit\" project, or a consumer not using our preset) —\n// reads as \"undefined\", so the guard is skipped and the probe runs for\n// real. Only an explicit `false` short-circuits.\ndeclare const __GTKX_ADW_AVAILABLE__: boolean | undefined\n\nlet cached: AdwModules | null | undefined\n\nif (hostModulesResult !== undefined) {\n cached = hostModulesResult\n} else if (\n typeof __GTKX_ADW_AVAILABLE__ !== \"undefined\" &&\n !__GTKX_ADW_AVAILABLE__\n) {\n cached = null\n} else {\n // Fire-and-forget — see the module doc above for why this can no longer\n // be a module-scope `await` and why starting it here, unconditionally,\n // still settles in time for every real caller.\n Promise.all([import(\"@gtkx/gi/adw\"), import(\"@gtkx/jsx/adw\")])\n .then(([gi, jsx]) => {\n cached = { gi: gi as typeof AdwGi, jsx: jsx as typeof AdwJsx }\n })\n .catch(() => {\n cached = null\n })\n}\n\n/**\n * True when this app's codegen store actually generated Adwaita bindings —\n * i.e. `\"Adw-1\"` is in this app's gtkx.config.ts `libraries`. Synchronous\n * from every caller's point of view on the Metro/SEA host and the\n * plain-GTK profile (both resolved above with nothing to await); on vite\n * build/dev and vitest this reads whatever the fire-and-forget probe above\n * has settled to by the time it is called — see the module doc for why\n * that is reliably \"already settled\" for every real call site in this\n * package, not a formal guarantee.\n */\nexport const adwAvailable = (): boolean =>\n cached !== null && cached !== undefined\n\nconst NOT_AVAILABLE =\n ' requires \"Adw-1\" in this app\\'s gtkx.config.ts `libraries` — see ' +\n \"docs/api.md (the plain-GTK profile) for what needs Adw unconditionally \" +\n \"and what falls back without it.\"\n\n/** The repo's loud named throw for a feature that reached for Adw and found\n * none. Every Adw-dependent call site in the seam funnels through this, but\n * most no longer reach it in practice: Alert, Appearance and chrome:\n * \"content\" all check `adwAvailable()` themselves first and take a\n * plain-GTK fallback instead (see .claude/epics/adw-optional/002.md,\n * 003.md, 004.md) — this throw is what is left for the features with no\n * fallback at all (NavigationStack, react-native-gtkx/adw's own\n * AdwBreakpoint family). */\nconst requireAdw = (feature: string): AdwModules => {\n if (!cached) {\n throw new Error(`[react-native-gtkx] ${feature}${NOT_AVAILABLE}`)\n }\n return cached\n}\n\n/** The real `@gtkx/gi/adw` namespace (enums, GObject classes — `Adw.StyleManager`,\n * `Adw.ColorScheme`, `Adw.ResponseAppearance`, ...), or the loud throw above. */\nexport const requireAdwGi = (feature: string): typeof AdwGi =>\n requireAdw(feature).gi\n\n/** The real `@gtkx/jsx/adw` namespace (raw JSX elements — `AdwApplicationWindow`,\n * `AdwNavigationView`, `AdwNavigationPage`, ...), or the loud throw above. */\nexport const requireAdwJsx = (feature: string): typeof AdwJsx =>\n requireAdw(feature).jsx\n\n// Type-only (erased at build — no runtime import, so this costs nothing on\n// the plain profile): re-exported so a consumer like common/navigation-stack.tsx\n// can spell `Ref<Adw.NavigationView | null>` without importing @gtkx/gi/adw\n// itself, which the eslint fence (no @gtkx/* outside src/gtkx/bridge/**)\n// would refuse anyway.\nexport type { AdwGi as Adw }\n\nexport type ColorScheme = \"light\" | \"dark\"\n\n// Folded in from the pre-seam ./theme.ts: both are pure Adw, both were only\n// ever called from apis/host.gtkx.ts, and keeping them as their own\n// (formerly eagerly-imported) file would just move the eager `import * as\n// Adw` problem one hop over instead of removing it.\nexport const styleManager = (): AdwGi.StyleManager =>\n requireAdwGi(\"Appearance\").StyleManager.getDefault()\n\n// The Appearance API subscribes to notify::dark on the style manager.\nexport const colorScheme = (): ColorScheme =>\n styleManager().getDark() ? \"dark\" : \"light\"\n"]}
|
|
1
|
+
{"version":3,"file":"adw.js","sourceRoot":"","sources":["../../../src/gtkx/bridge/adw.ts"],"names":[],"mappings":"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","sourcesContent":["// The ONLY module allowed to import @gtkx/gi/adw and @gtkx/jsx/adw — see\n// .claude/epics/adw-optional/001.md. Everything the RN core needs lives in\n// ./core instead, with zero Adw imports, so an app whose gtkx.config.ts\n// declares `libraries: [\"Gtk-4.0\"]` alone (no \"Adw-1\") never reaches either\n// specifier: a codegen store generated that way has no \"./adw\" entry in\n// either package's `exports` map AT ALL (empirically verified: neither\n// directory even exists on disk), so a STATIC import of either one fails\n// the whole build — `gtkx build`'s own \"gtkx:undeclared-library\" vite\n// plugin throws while resolving it, unconditionally, whether or not the\n// import is ever reached at runtime.\n//\n// __GTKX_ADW_AVAILABLE__ (declared ambient just below) is a build-time\n// constant the vite preset injects (src/vite/index.ts, see its own doc for\n// the full story — .claude/epics/adw-optional/006.md is the regression this\n// exists to fix): true only when THIS app's codegen store actually has an\n// \"adw\" entry. The probe below guards on it and, only inside that guard,\n// imports @gtkx/gi/adw and @gtkx/jsx/adw as LITERAL specifiers —\n// deliberately, unlike a runtime-assembled string. A hidden specifier is\n// invisible to Rollup's build graph, which sounds like the safer choice,\n// but it is ALSO invisible to everything that graph gives every OTHER gtkx\n// import for free: `resolve.dedupe` (RC4-WORKAROUND(runtime-dedupe) in\n// docs/gtkx-rc4-notes.md) and `gtkx build`'s own asset pipeline for the\n// native addon (`@gtkx/cli`'s `gtkx:native` plugin, which rewrites every\n// STATICALLY reachable `@gtkx/native` import onto the single `dist/gtkx.node`\n// it emits) — a hidden specifier resolves a SECOND, independent copy from\n// node_modules at runtime instead, and two distinct native addons\n// double-initialize the gtkx runtime and abort the process\n// (`g_log_set_writer_func() called multiple times`, proven with a core dump\n// showing both `.node` files mapped into one process). A literal specifier\n// gets the exact same static treatment as every other gtkx import; when the\n// build-time constant folds to `false` instead, dead-code elimination\n// removes the whole guarded body — literal specifiers included — before\n// Rollup's graph walk ever starts, so `gtkx:undeclared-library` never\n// throws on the plain-GTK profile either.\n//\n// No module-scope await, anywhere — the one thing that actually changed\n// here (.claude/epics/adw-optional/007-sea-tla.md): this file used to\n// resolve Adw with a TOP-LEVEL AWAIT (both the #132 guarded literal imports\n// and the fallback probe), so every call site below could stay synchronous\n// without an explicit wait of its own. That broke `react-native\n// build-linux` outright — reproduced empirically in the VM, WITH OR\n// WITHOUT --sea/--standalone (all three share the same Metro `bundle()`\n// call, `--dev false`): Metro's own minifier (metro-minify-terser, i.e.\n// terser) parses each module's compiled factory as a plain SCRIPT, not an\n// ES module — `await` is just an ordinary identifier there, not a keyword,\n// so \"await probeViaDynamicImport()\" is a hard syntax error (\"Unexpected\n// token: name (probeViaDynamicImport)\"), independent of the SEA/rolldown\n// CJS-format restriction the task file also names (CJS has no TLA either —\n// the same file would have failed a second time even past Metro).\n//\n// Tried and reverted: resolving gi through a synchronous `require()` (via\n// `createRequire(import.meta.url)`) instead of a dynamic import — it does\n// answer synchronously under vite build/dev and vitest, but\n// `import.meta.url` is ITSELF ESM-only syntax, exactly like top-level\n// await: Metro's minifier happened not to reject it at minify time (unlike\n// `await`), but Node's own parser does, the moment the Metro/SEA host\n// actually executes the bundle via `vm.runInThisContext` (which runs the\n// whole bundle as a plain SCRIPT, not a module) — \"SyntaxError: Cannot use\n// 'import.meta' outside a module\", reproduced building and running\n// examples/hn-app's SEA artifact. Same class of bug as the TLA one this\n// file exists to fix, so back to a dynamic import for both gi and jsx —\n// their own literal specifiers, unlike ours, are genuinely fine either way\n// since Metro/the SEA host never reach this branch at all (see\n// fromHostModules below) and every other toolchain is real ESM.\n//\n// So: a single, ordinary (non-async, non-top-level-await) function starts\n// BOTH imports together — Promise.all, exactly like the old probe — the\n// moment this module itself finishes evaluating, fire-and-forget (no\n// module-scope await to block on this time). No formal ordering guarantee\n// versus the old TLA probe's, but starting it as early as this module can\n// (not lazily, on the first actual `requireAdwJsx()`/`requireAdwGi()` call)\n// gives it a real, if informal, chance to have already settled — verified\n// against this package's own gtk test suite, including the one caller with\n// the least slack of all: react-native-gtkx/adw's own `adw/index.ts` calls\n// `requireAdwJsx()` eagerly, at ITS OWN module scope, the moment it is\n// imported (immediately after this file). Under Vite's SSR module runner\n// (dev and vitest both), every static import a transformed module has is\n// itself an awaited call in that runner, cached or not — so `adw/index.ts`\n// evaluating is always at least one module-boundary await after this\n// file's own module body, including the Promise.all it starts, finished\n// running. tests/gtk/bridge/auxiliary-elements.gtk.test.tsx (imports\n// react-native-gtkx/adw) and tests/gtk/adw/* are all green under this.\n//\n// The Metro/SEA host fast path (fromHostModules, below) takes priority over\n// all of this and never touches import() at all: `global.__hostModules` is\n// already populated — both gi and jsx together, when present — before the\n// run-linux host or the SEA entry's own async wrapper (src/sea/bundle.ts's\n// `buildEntrySource`, itself already just an ordinary async FUNCTION, never\n// a module-scope await) ever executes the bundle that reaches this file.\nimport type * as AdwGi from \"@gtkx/gi/adw\"\nimport type * as AdwJsx from \"@gtkx/jsx/adw\"\n\n// Assembled rather than written as one literal: used only as a lookup key\n// into global.__hostModules (an object property read, not an import), which\n// the run-linux host populates keyed by these exact strings\n// (HOST_MODULE_EXTERNALS in src/metro/index.ts). Kept opaque to a plain text\n// search for consistency with the rest of this file, not because anything\n// would fail resolving it — fromHostModules never imports.\nconst GI_ADW = [\"@gtkx\", \"gi\", \"adw\"].join(\"/\")\nconst JSX_ADW = [\"@gtkx\", \"jsx\", \"adw\"].join(\"/\")\n\ntype AdwModules = {\n gi: typeof AdwGi\n jsx: typeof AdwJsx\n}\n\ntype HostModulesGlobal = typeof globalThis & {\n __hostModules?: Record<string, unknown>\n}\n\n// The run-linux (Metro) host already resolved every external — including\n// these two, when the app declared \"Adw-1\" — into global.__hostModules\n// BEFORE the bundle ever runs (see src/runner/host.ts) — synchronously, as\n// far as this module is concerned, and the authoritative answer on that\n// toolchain: reading it directly is both correct and avoids a second,\n// redundant resolution attempt Metro's bundler cannot serve anyway (no\n// \"virtual:gtkx-config\" loader hook outside Vite's own pipeline or the\n// host's own module.registerHooks).\n// Returns undefined (not false) when there is no host indirection in play\n// at all — the vite dev/build toolchain, where every spike and example in\n// this repo runs — so the caller knows to fall through to the real probe.\nconst fromHostModules = (): AdwModules | null | undefined => {\n const hostModules = (globalThis as HostModulesGlobal).__hostModules\n if (!hostModules) {\n return undefined\n }\n const gi = hostModules[GI_ADW]\n const jsx = hostModules[JSX_ADW]\n return gi && jsx\n ? { gi: gi as typeof AdwGi, jsx: jsx as typeof AdwJsx }\n : null\n}\n\nconst hostModulesResult = fromHostModules()\n\n// Skips the probe outright when the vite preset has POSITIVELY told us Adw\n// is not in this app's codegen store (see the module doc above for why a\n// literal specifier below needs this guard to exist at all). `typeof`, not\n// a direct reference: safe on any toolchain that never defines the constant\n// (a bare `vitest` \"unit\" project, or a consumer not using our preset) —\n// reads as \"undefined\", so the guard is skipped and the probe runs for\n// real. Only an explicit `false` short-circuits.\ndeclare const __GTKX_ADW_AVAILABLE__: boolean | undefined\n\nlet cached: AdwModules | null | undefined\n\nif (hostModulesResult !== undefined) {\n cached = hostModulesResult\n} else if (\n typeof __GTKX_ADW_AVAILABLE__ !== \"undefined\" &&\n !__GTKX_ADW_AVAILABLE__\n) {\n cached = null\n} else {\n // Fire-and-forget — see the module doc above for why this can no longer\n // be a module-scope `await` and why starting it here, unconditionally,\n // still settles in time for every real caller.\n Promise.all([import(\"@gtkx/gi/adw\"), import(\"@gtkx/jsx/adw\")])\n .then(([gi, jsx]) => {\n cached = { gi: gi as typeof AdwGi, jsx: jsx as typeof AdwJsx }\n })\n .catch(() => {\n cached = null\n })\n}\n\n/**\n * True when this app's codegen store actually generated Adwaita bindings —\n * i.e. `\"Adw-1\"` is in this app's gtkx.config.ts `libraries`. Synchronous\n * from every caller's point of view on the Metro/SEA host and the\n * plain-GTK profile (both resolved above with nothing to await); on vite\n * build/dev and vitest this reads whatever the fire-and-forget probe above\n * has settled to by the time it is called — see the module doc for why\n * that is reliably \"already settled\" for every real call site in this\n * package, not a formal guarantee.\n */\nexport const adwAvailable = (): boolean =>\n cached !== null && cached !== undefined\n\nconst NOT_AVAILABLE =\n ' requires \"Adw-1\" in this app\\'s gtkx.config.ts `libraries` — see ' +\n \"docs/guide/plain-gtk.md for what needs Adw unconditionally \" +\n \"and what falls back without it.\"\n\n/** The repo's loud named throw for a feature that reached for Adw and found\n * none. Every Adw-dependent call site in the seam funnels through this, but\n * most no longer reach it in practice: Alert, Appearance and chrome:\n * \"content\" all check `adwAvailable()` themselves first and take a\n * plain-GTK fallback instead (see .claude/epics/adw-optional/002.md,\n * 003.md, 004.md) — this throw is what is left for the features with no\n * fallback at all (NavigationStack, react-native-gtkx/adw's own\n * AdwBreakpoint family). */\nconst requireAdw = (feature: string): AdwModules => {\n if (!cached) {\n throw new Error(`[react-native-gtkx] ${feature}${NOT_AVAILABLE}`)\n }\n return cached\n}\n\n/** The real `@gtkx/gi/adw` namespace (enums, GObject classes — `Adw.StyleManager`,\n * `Adw.ColorScheme`, `Adw.ResponseAppearance`, ...), or the loud throw above. */\nexport const requireAdwGi = (feature: string): typeof AdwGi =>\n requireAdw(feature).gi\n\n/** The real `@gtkx/jsx/adw` namespace (raw JSX elements — `AdwApplicationWindow`,\n * `AdwNavigationView`, `AdwNavigationPage`, ...), or the loud throw above. */\nexport const requireAdwJsx = (feature: string): typeof AdwJsx =>\n requireAdw(feature).jsx\n\n// Type-only (erased at build — no runtime import, so this costs nothing on\n// the plain profile): re-exported so a consumer like common/navigation-stack.tsx\n// can spell `Ref<Adw.NavigationView | null>` without importing @gtkx/gi/adw\n// itself, which the eslint fence (no @gtkx/* outside src/gtkx/bridge/**)\n// would refuse anyway.\nexport type { AdwGi as Adw }\n\nexport type ColorScheme = \"light\" | \"dark\"\n\n// Folded in from the pre-seam ./theme.ts: both are pure Adw, both were only\n// ever called from apis/host.gtkx.ts, and keeping them as their own\n// (formerly eagerly-imported) file would just move the eager `import * as\n// Adw` problem one hop over instead of removing it.\nexport const styleManager = (): AdwGi.StyleManager =>\n requireAdwGi(\"Appearance\").StyleManager.getDefault()\n\n// The Appearance API subscribes to notify::dark on the style manager.\nexport const colorScheme = (): ColorScheme =>\n styleManager().getDark() ? \"dark\" : \"light\"\n"]}
|
|
@@ -193,7 +193,7 @@ const zOrderedParents = new WeakSet();
|
|
|
193
193
|
* answer the occlusion question. Restored the moment nothing is raised there,
|
|
194
194
|
* because it is not free of consequence: `pointerEvents: "box-none"` on a View
|
|
195
195
|
* whose only child is a `Text` would otherwise fall through to whatever is
|
|
196
|
-
* behind it. Documented in docs/
|
|
196
|
+
* behind it. Documented in docs/reference/components/index.md.
|
|
197
197
|
*/
|
|
198
198
|
const paintOnlyLeaves = new WeakSet();
|
|
199
199
|
/**
|