react-native-gtkx 0.4.0-alpha.3 → 0.4.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.
- package/dist/apis/host.gtkx.js.map +1 -1
- package/dist/components/modal.d.ts +1 -1
- package/dist/components/modal.js +16 -8
- package/dist/components/modal.js.map +1 -1
- package/dist/gtkx/bridge/adw.js.map +1 -1
- package/dist/gtkx/bridge/core.d.ts +1 -2
- package/dist/gtkx/bridge/core.js +2 -5
- package/dist/gtkx/bridge/core.js.map +1 -1
- package/dist/gtkx/bridge/geometry.js +1 -1
- package/dist/gtkx/bridge/geometry.js.map +1 -1
- package/dist/gtkx/bridge/layout-manager.js +18 -5
- package/dist/gtkx/bridge/layout-manager.js.map +1 -1
- package/dist/gtkx/bridge/slot-portal.js.map +1 -1
- package/dist/gtkx/bridge/svg-node.js +13 -6
- package/dist/gtkx/bridge/svg-node.js.map +1 -1
- package/dist/gtkx/bridge/view-box.js +18 -9
- package/dist/gtkx/bridge/view-box.js.map +1 -1
- package/dist/gtkx/bridge/widgets.generated.adw.js +1 -1
- package/dist/gtkx/bridge/widgets.generated.adw.js.map +1 -1
- package/dist/mcp/data/generated.d.ts +58 -42
- package/dist/mcp/data/generated.js +63 -43
- package/dist/mcp/data/generated.js.map +1 -1
- package/dist/runner/host-dev.js +5 -0
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +15 -0
- package/dist/runner/host.js.map +1 -1
- package/dist/runner/index.d.ts +27 -0
- package/dist/runner/index.js +206 -1
- package/dist/runner/index.js.map +1 -1
- package/dist/sea/assemble.d.ts +9 -0
- package/dist/sea/assemble.js +16 -3
- package/dist/sea/assemble.js.map +1 -1
- package/dist/sea/bundle.d.ts +37 -2
- package/dist/sea/bundle.js +76 -4
- package/dist/sea/bundle.js.map +1 -1
- package/dist/sea/native-shim.js +1 -1
- package/dist/sea/native-shim.js.map +1 -1
- package/dist/testing/index.js +28 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/vite/index.js +3 -3
- package/dist/vite/index.js.map +1 -1
- package/dist/vitest/index.d.ts +1 -1
- package/dist/vitest/index.js.map +1 -1
- package/package.json +9 -9
- package/dist/gtkx/bridge/use-signal.d.ts +0 -2
- package/dist/gtkx/bridge/use-signal.js +0 -41
- package/dist/gtkx/bridge/use-signal.js.map +0 -1
|
@@ -1451,7 +1451,7 @@ export declare const DOC_CHUNKS: readonly [{
|
|
|
1451
1451
|
}, {
|
|
1452
1452
|
readonly doc: "docs/architecture/overview.md";
|
|
1453
1453
|
readonly heading: "The escape hatch";
|
|
1454
|
-
readonly text: "If something is still missing, reach the widget directly — every wrapper\nhere forwards its `ref` to the real GObject:\n\n```tsx\nconst viewRef = useRef<Adw.NavigationView | null>(null)\n<NavigationStack ref={viewRef} stack={stack}>…</NavigationStack>\n// viewRef.current is the real Adw.NavigationView\n```\n\nThere is deliberately no wall. A missing convenience should cost one line,\nnot a fork.\n\n---\n\nMeasured numbers behind these decisions (the Yoga/GTK feasibility spike,\nframe-budget studies, the navigation research) live in `docs/research/` —\nrepo-only working notes, not published here. The standing gtkx upstream\nagenda is `docs/upstream-gtkx.md`, and every
|
|
1454
|
+
readonly text: "If something is still missing, reach the widget directly — every wrapper\nhere forwards its `ref` to the real GObject:\n\n```tsx\nconst viewRef = useRef<Adw.NavigationView | null>(null)\n<NavigationStack ref={viewRef} stack={stack}>…</NavigationStack>\n// viewRef.current is the real Adw.NavigationView\n```\n\nThere is deliberately no wall. A missing convenience should cost one line,\nnot a fork.\n\n---\n\nMeasured numbers behind these decisions (the Yoga/GTK feasibility spike,\nframe-budget studies, the navigation research) live in `docs/research/` —\nrepo-only working notes, not published here. The standing gtkx upstream\nagenda is `docs/upstream-gtkx.md`, and every workaround the bridge carries\nis cataloged in `docs/gtkx-1.2-notes.md`.";
|
|
1455
1455
|
}, {
|
|
1456
1456
|
readonly doc: "docs/architecture/overview.md";
|
|
1457
1457
|
readonly heading: "Related";
|
|
@@ -1559,7 +1559,7 @@ export declare const DOC_CHUNKS: readonly [{
|
|
|
1559
1559
|
}, {
|
|
1560
1560
|
readonly doc: "docs/architecture/glossary.md";
|
|
1561
1561
|
readonly heading: "Bridge";
|
|
1562
|
-
readonly text: "`src/gtkx/bridge/` — the one place in this package's source that imports\n`@gtkx/*` (eslint-enforced). gtkx is a
|
|
1562
|
+
readonly text: "`src/gtkx/bridge/` — the one place in this package's source that imports\n`@gtkx/*` (eslint-enforced). gtkx is a young dependency, so its API drift\nis absorbed here instead of at every call site; each workaround this forces\ncarries a `1.2-WORKAROUND` tag, cataloged in `docs/gtkx-1.2-notes.md`. See\n[Overview](overview).";
|
|
1563
1563
|
}, {
|
|
1564
1564
|
readonly doc: "docs/architecture/glossary.md";
|
|
1565
1565
|
readonly heading: "Profile";
|
|
@@ -1587,7 +1587,7 @@ export declare const DOC_CHUNKS: readonly [{
|
|
|
1587
1587
|
}, {
|
|
1588
1588
|
readonly doc: "docs/guide/installation.md";
|
|
1589
1589
|
readonly heading: "New project from the template";
|
|
1590
|
-
readonly text: "```bash\nnpx degit itsmepetrov/react-native-gtkx/template my-app\ncd my-app\nnpm install\nnpm run dev # a window opens, Fast Refresh applies edits live\n```\n\nProduction build:\n\n```bash\nnpm run build # single bundle: dist/bundle.
|
|
1590
|
+
readonly text: "```bash\nnpx degit itsmepetrov/react-native-gtkx/template my-app\ncd my-app\nnpm install\nnpm run dev # a window opens, Fast Refresh applies edits live\n```\n\nProduction build:\n\n```bash\nnpm run build # single bundle: dist/bundle.mjs\nnpm start # node dist/bundle.mjs\n```\n\nMeasured in a clean Ubuntu 26.04 container, system dependencies\npreinstalled: 63 seconds from `npm install` to a window on screen.\n\nThe template's `vite.config.ts` wires the `react-native-gtkx/vite` preset\n(the `react-native` → `react-native-gtkx` alias, Metro-style platform\nextensions); `gtkx dev`/`gtkx build` pick it up automatically. Its\n`tsconfig.json` maps the `\"react-native\"` specifier through `paths` so\neditor types resolve too. The default entry is `src/index.tsx`, and\n`Comp.tsx` next to `Comp.linux.tsx` builds the Linux variant for an\nextensionless `import { Comp } from \"./Comp\"` — `Platform.select({ linux:\n…, native: …, default: … })` works exactly as it does in React Native and\nis tree-shaken out of the production build.";
|
|
1591
1591
|
}, {
|
|
1592
1592
|
readonly doc: "docs/guide/installation.md";
|
|
1593
1593
|
readonly heading: "Add Linux to an existing React Native app";
|
|
@@ -1623,7 +1623,7 @@ export declare const DOC_CHUNKS: readonly [{
|
|
|
1623
1623
|
}, {
|
|
1624
1624
|
readonly doc: "docs/guide/toolchains.md";
|
|
1625
1625
|
readonly heading: "The Metro path";
|
|
1626
|
-
readonly text: "`run-linux` and `
|
|
1626
|
+
readonly text: "`run-linux`, `build-linux` and `deploy-linux` are contributed to the React\nNative CLI by `react-native-gtkx`'s own `react-native.config.js` — no\nseparate install, they come with the package.\n\n```bash\nnpx react-native run-linux [--entry-file <path>] [--bundle-output <path>]\n [--skip-bundling] [--dev] [--port <number>]\n\nnpx react-native build-linux [--entry-file <path>] [--bundle-output <path>]\n [--standalone] [--sea] [--sea-output <path>]\n\nnpx react-native deploy-linux [--entry-file <path>] [--target <formats>]\n [--out <path>] [--print-manifests] [--skip-build]\n```\n\n`run-linux` bundles with Metro and opens the window; `--dev` starts (or\nreuses) the Metro dev server on `--port` (default `8081`) instead, for\nFast Refresh. `build-linux` bundles for distribution and stops short of\nrunning it — see [Packaging](packaging.md) for `--standalone`/`--sea`,\nthe two flags that turn the Metro bundle into something shippable.\n`deploy-linux` goes one step further and builds an installable `.deb`/\n`.rpm`/`.AppImage` from that same Metro build — also covered on the\n[Packaging](packaging.md) page, which is where its vite-path counterpart\nlives too (the same command name works for either toolchain).";
|
|
1627
1627
|
}, {
|
|
1628
1628
|
readonly doc: "docs/guide/toolchains.md";
|
|
1629
1629
|
readonly heading: "The React Compiler (vite path only)";
|
|
@@ -1659,7 +1659,7 @@ export declare const DOC_CHUNKS: readonly [{
|
|
|
1659
1659
|
}, {
|
|
1660
1660
|
readonly doc: "docs/guide/packaging.md";
|
|
1661
1661
|
readonly heading: "The vite path: one bundle";
|
|
1662
|
-
readonly text: "```bash\ngtkx build\n```\n\nproduces `dist/bundle.
|
|
1662
|
+
readonly text: "```bash\ngtkx build\n```\n\nproduces `dist/bundle.mjs` — everything except the native GTK addon\ninlined into one file — plus `dist/gtkx.node` (and\n`dist/gschemas.compiled` alongside it, if the app declares a GSettings\nschema; the bundle's own banner points `GSETTINGS_SCHEMA_DIR` at its own\ndirectory). That pair is the whole runtime: copy it anywhere with Node\n≥ 24, GTK4 ≥ 4.20 and libadwaita ≥ 1.8 (or just GTK4, on the [plain-GTK\nprofile](plain-gtk.md)) and `node bundle.mjs` runs it — no `node_modules`\ninvolved.";
|
|
1663
1663
|
}, {
|
|
1664
1664
|
readonly doc: "docs/guide/packaging.md";
|
|
1665
1665
|
readonly heading: "The Metro path: `build-linux`";
|
|
@@ -1667,55 +1667,71 @@ export declare const DOC_CHUNKS: readonly [{
|
|
|
1667
1667
|
}, {
|
|
1668
1668
|
readonly doc: "docs/guide/packaging.md";
|
|
1669
1669
|
readonly heading: "Choosing an artifact";
|
|
1670
|
-
readonly text: "`build-linux` produces three shapes from the same Metro step; the choice\nbetween them is a distribution question, not a different build:\n\n| Flag | Artifact | Needs installed | Size (`hn-app`, linux-arm64) |\n| -------------- | -------------------------- | ---------------------------------- | ---------------------------- |\n| _(none)_ | `dist/main.jsbundle` | a `node_modules` tree **and** Node | 0.4 MB + the tree |\n| `--standalone` | `dist/<name>.cjs` | Node only | 6.9 MB |\n| `--sea` | `dist/<name>` (executable) | nothing at all | 104 MB (30 MB compressed) |\n\n```bash\nnpx react-native build-linux --standalone # in the app root\nnode ./dist/<your-package-name>.cjs # one script, system node\n\nnpx react-native build-linux --sea\n./dist/<your-package-name> # one executable, nothing else\n```\n\nBoth flags produce the jsbundle exactly as before, then one additional\nfile next to it. `--sea-output <path>` overrides where that file goes;\nthe default is `dist/<package name>` with any npm scope stripped (plus\n`.cjs` for `--standalone`).\n\
|
|
1670
|
+
readonly text: "`build-linux` produces three shapes from the same Metro step; the choice\nbetween them is a distribution question, not a different build:\n\n| Flag | Artifact | Needs installed | Size (`hn-app`, linux-arm64) |\n| -------------- | -------------------------- | ---------------------------------- | ---------------------------- |\n| _(none)_ | `dist/main.jsbundle` | a `node_modules` tree **and** Node | 0.4 MB + the tree |\n| `--standalone` | `dist/<name>.cjs` | Node only | 6.9 MB |\n| `--sea` | `dist/<name>` (executable) | nothing at all | 104 MB (30 MB compressed) |\n\n```bash\nnpx react-native build-linux --standalone # in the app root\nnode ./dist/<your-package-name>.cjs # one script, system node\n\nnpx react-native build-linux --sea\n./dist/<your-package-name> # one executable, nothing else\n```\n\nBoth flags produce the jsbundle exactly as before, then one additional\nfile next to it. `--sea-output <path>` overrides where that file goes;\nthe default is `dist/<package name>` with any npm scope stripped (plus\n`.cjs` for `--standalone`).\n\n`--standalone` is what `deploy-linux` (below) builds a `.deb`/`.rpm`/\n`.AppImage` from — it is not really a competing choice, it is that\npackaging step's own input. Reach for it directly only when you want the\nbundle without any packaging around it (a container image, a CI artifact\npassed to another step). `--sea` stays the odd one out: \"download this\none file and run it,\" where nothing — not even a package manager — can\nbe assumed. It's `--standalone` with a copy of Node wrapped around it,\nand that copy is the entire ~97 MB difference between the two.";
|
|
1671
1671
|
}, {
|
|
1672
1672
|
readonly doc: "docs/guide/packaging.md";
|
|
1673
1673
|
readonly heading: "What `--sea`/`--standalone` need that a plain build doesn't";
|
|
1674
1674
|
readonly text: "Both flags inline `virtual:gtkx-config` (which re-exports codegen\noutput), so — unlike a plain `build-linux`, which needs neither — they\nneed the gtkx codegen store already generated, and therefore GTK\ndevelopment headers on the build machine. The `--sea` build also fetches\n`postject` through `npx` the first time it runs, so that first build\nneeds network access.\n\nThe native addon (a real `dlopen`ed library) can't be plain bundled JS,\nso both artifacts carry it as bytes instead — a SEA asset in the\nexecutable, a base64 literal in the `.cjs` — and extract it to\n`$XDG_CACHE_HOME/react-native-gtkx-sea` on first run, keyed by content\nhash (falling back to a temp directory if `$HOME` is read-only). Repeat\nlaunches reuse the extracted file.\n\nThe `--sea` executable is large mostly because it carries a full copy of\nNode: on linux-arm64, `hn-app` measures 104 MB (30 MB zstd-compressed),\nof which roughly 98 MB is Node itself — the app code and native addon\ntogether are under 7 MB. The build strips Node's own debug symbols as\npart of assembling the executable (best-effort: a build machine without\n`binutils` gets a larger executable and a warning, not a failed build),\nwhich is most of what keeps that number from being worse — an\nunstripped `node` binary carries about 19 MB of debug information\nnothing in a shipped app can use.";
|
|
1675
1675
|
}, {
|
|
1676
1676
|
readonly doc: "docs/guide/packaging.md";
|
|
1677
|
-
readonly heading: "
|
|
1678
|
-
readonly text: "
|
|
1677
|
+
readonly heading: "Packaging: `npx react-native deploy-linux`";
|
|
1678
|
+
readonly text: "One command builds real `.deb`/`.rpm`/`.AppImage`/`.flatpak` packages —\nvalidated desktop entry and AppStream metadata, correct per-format\ndependencies, an icon installed into the system theme — from either\ntoolchain. It works from any react-native-gtkx app's own project\ndirectory; which half of it runs is decided for you:\n\n- a project with a `vite.config.*` at its root (the vite path — gallery,\n monitor and every app built with `gtkx dev`/`gtkx build`) proxies\n straight to `npx gtkx deploy`, since that project already looks\n exactly like what `gtkx deploy` expects;\n- everything else (the Metro path — an app with `ios`/`android` and\n `run-linux`/`build-linux`) runs a real `--standalone` build first (the\n same step described above), reshapes that output into the same shape a\n vite build would have produced, then hands off to `gtkx deploy --skip-build`\n over it. hn-app is this repo's own example of that path.\n\n```bash\nnpx react-native deploy-linux --target deb,rpm,appimage\nnpx react-native deploy-linux --target deb --print-manifests # metadata only, no packages built\nnpx react-native deploy-linux --skip-build --target rpm # package what was already built\n```\n\n| Flag | Meaning |\n| --------------------- | ---------------------------------------------------------------------- |\n| `--entry-file <path>` | Metro path only — same meaning as `build-linux`'s (default `index.js`) |\n| `--target <formats>` | Comma-separated: `deb`, `rpm`, `appimage`, `flatpak` |\n| `--out <path>` | Output directory, relative to the project root (default `build`) |\n| `--print-manifests` | Write the desktop-entry/AppStream files, then stop — no packages built |\n| `--skip-build` | Package the already-staged `dist/` instead of rebuilding (see below) |\n\n`--skip-build` means the same thing on both paths — package what's\nalready in `dist/`, don't rebuild — but on the Metro path it also skips\nthis command's own build/staging step, not just `gtkx build`'s; running\nit before anything has ever been staged is a clear error, not a\nconfusing one three layers down.";
|
|
1679
1679
|
}, {
|
|
1680
|
-
readonly doc: "docs/
|
|
1680
|
+
readonly doc: "docs/guide/packaging.md";
|
|
1681
|
+
readonly heading: "The `deploy` config";
|
|
1682
|
+
readonly text: "Both toolchains read the same block from the project's `gtkx.config.ts`:\n\n```ts\nexport default defineConfig({\n applicationId: \"com.example.myapp\",\n libraries: [\"Gtk-4.0\", \"Adw-1\"],\n deploy: {\n name: \"My App\",\n summary: \"One line describing the app\",\n description: \"A longer paragraph or two.\",\n categories: [\"Utility\"],\n developer: { name: \"Your Name\", email: \"you@example.com\" },\n license: \"MIT\",\n icons: \"icon.svg\",\n },\n})\n```\n\nThere is no default: deploying without a `deploy` block is a thrown\nerror naming exactly which fields to add (derived from `package.json`\nwhere it can guess). `name`/`summary`/`categories` feed a real\n`.desktop` entry and AppStream `.metainfo.xml`, validated by\n`desktop-file-validate`/`appstreamcli` before anything is packaged — a\ncategory that isn't a real freedesktop one, or two main categories where\nonly one is allowed, fails the build rather than shipping quietly wrong\nmetadata. The full schema (screenshots, MIME types, per-target\ndependencies, signing, `targets`/`binaryName`/`applicationId` overrides)\nis [gtkx's own reference](https://gtkx.dev/guide/deploying); this page\ncovers what's specific to running it through `deploy-linux`.";
|
|
1683
|
+
}, {
|
|
1684
|
+
readonly doc: "docs/guide/packaging.md";
|
|
1685
|
+
readonly heading: "What ships";
|
|
1686
|
+
readonly text: "Every target bundles its own private copy of Node by default\n(`deploy.node.source: \"download\"`, verified against `SHASUMS256.txt`,\ncached under `~/.cache/gtkx/node/`) — no `Depends: nodejs` line, at the\ncost of roughly 97 MB per package. Measured on linux-arm64, both\ntoolchains land in the same range because both are dominated by that\nbundled runtime: `monitor` (vite) is a 40.3 MB `.deb`; `hn-app` (Metro)\nis a 40.7 MB `.deb`, a 40.5 MB `.rpm` and a 36.5 MB `.AppImage`. A `.deb`\ndeclares:\n\n```\nDepends: libgtk-4-1, libadwaita-1-0, hicolor-icon-theme, adwaita-icon-theme, gsettings-desktop-schemas, libc6 (>= 2.28)\n```\n\n— the glibc floor read directly off the bundled Node's own ELF notes.\nPackage a [plain-GTK](plain-gtk.md) app the same way and `libadwaita-1-0`\ndrops out on its own (it comes from the app's declared `libraries`, not\na fixed list). Prefer the old thin-package shape, where the system's own\n`nodejs` is a dependency instead of a bundled copy? `deploy.node.source:\n\"host\"` (embed the machine's own Node) or `\"path\"` (embed a specific\none) are the escape hatch — see the reference linked above.\n\n`deb`/`rpm`/`appimage` need nothing preinstalled beyond a handful of\nsmall system tools (`desktop-file-validate`, `appstreamcli`, `tar`,\n`file`, `binutils` optionally for a smaller bundled Node) — the actual\npackagers, [nfpm](https://github.com/goreleaser/nfpm) for deb/rpm and\n[appimagetool](https://github.com/AppImage/appimagetool), download and\ncache themselves under `~/.cache/gtkx` on first use. A missing tool\nfails with the exact `apt`/`dnf`/`pacman`/`zypper` command to install it,\ndetected from `/etc/os-release`. `flatpak` is the heavier target: it\nneeds `flatpak`/`flatpak-builder` installed and the GNOME `Platform`/\n`Sdk` runtime pulled from Flathub before it can build anything (a\none-time, network-bound, multi-hundred-MB fetch) — every example this\nproject ships deliberately leaves `flatpak` out of its own\n`deploy.targets`, proven separately as a build-only artifact instead of\nbeing part of the regular `deb,rpm,appimage` set.";
|
|
1687
|
+
}, {
|
|
1688
|
+
readonly doc: "docs/guide/packaging.md";
|
|
1689
|
+
readonly heading: "The vite path's own `--sea`";
|
|
1690
|
+
readonly text: "There isn't one, and `deploy-linux` is why that's no longer the gap it\nused to be: the vite bundle loads the native addon through a dynamically\nobtained `require` a bundler can't intercept the way it intercepts a\nstatic import, and the bundle needs top-level await, which the\nsingle-file SEA format can't run — both investigated, neither a drop-in\nfix. Ship a vite-path app as its `bundle.mjs`/`gtkx.node` pair for\nrunning from a checkout, or package it with `deploy-linux` for\neverything else; the gap this used to be (no way to turn a vite app into\nsomething a package manager installs) is what `deploy-linux` closes.";
|
|
1691
|
+
}, {
|
|
1692
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1681
1693
|
readonly heading: "Live workarounds";
|
|
1682
|
-
readonly text: "| Name
|
|
1694
|
+
readonly text: "| Name | What 1.2.2 does | Our workaround | Removal condition |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `runtime-dedupe` | Two bundled copies of the gtkx runtime still double-init GLib and abort; nothing guards against it across two DISTINCT `.node` files. Reproduced on 1.2.2 by actually building the duplicate: `gtkx: GLib-ERROR: g_log_set_writer_func() called multiple times`. The FAILURE MODE changed since 1.0 (see upstream-gtkx.md ask #2) — it is now a catchable, named Node `uncaughtException` instead of a SIGABRT/core dump — but the underlying defect has not: the init is still not idempotent across distinct binaries, and the error still does not name the duplicate package | `src/vite/index.ts` puts `resolve.dedupe` over `@gtkx/*` + `react` (+ `@react-navigation/*` for its context) into the preset every app inherits | Idempotent runtime init upstream across distinct native-addon files, or an error that names the duplicate |\n| `prop-portal` | `createPortal(children, container, key?)` is still byte-for-byte the rc.3/rc.4 signature and can still only target a container's DEFAULT slot (\"children\"). `@gtkx/react`'s public entry and its `/internal` subpath both still withhold the `\"gtkx:prop\"` element — `/internal` still re-exports `createElementComponent` (the function that BUILDS an intrinsic element by GType name) but not the `Prop` literal itself, which stays a sibling export inside `element.js` that no public or `/internal` path reaches | `gtkx/bridge/slot-portal.ts` restates the `\"gtkx:prop\"` element name and wraps it in `createSlotPortal(children, target, slot)` — the one line that would move if gtkx renames it. `WindowActions`/`ApplicationActions`/`WindowControllers` are built on it | gtkx exports a slot-aware portal (or the prop element) from a public entry point |\n| `renderhook-no-window` | `renderHook` still mounts into a bare `Gtk.Box` — 1.2.2's `render-hook.js` still passes `container: new Gtk.Box()` unconditionally, and `RenderHookOptions` still carries only `wrapper` and `initialProps` — so window-dependent APIs have no toplevel to read | Hook tests create a window with `render()` first (`tests/gtk/apis/dimensions.test.tsx`); packaged for consumers as `renderHookWithWindow` (`react-native-gtkx/testing`) | `renderHook` mounts into the same harness window `render` uses |\n| `gtk-application-argv` | `@gtkx/react`'s `<GtkApplication>` bootstrap still builds the GApplication's own command line as `[applicationId.split(\".\").at(-1), ...process.argv.slice(2)]` and hands it to `runApplication(application, commandLine)` — confirmed unchanged by reading the installed 1.2.2 source (`components/application.tsx`) directly, no `argv` prop or options object anywhere on `ApplicationComponentProps`. Our runner hosts are invoked as `node dist/runner/host.js <bundle-path>` / `node dist/runner/host-dev.js <bundle-url>`, so `process.argv[2]` is our OWN internal plumbing, not a user-facing argument — left in place it reaches GLib's local command-line handling as a stray positional it tries to open as a file (`GLib-GIO-CRITICAL: This application can not open files`), and the window never activates | `process.argv.length = 2` right after each host reads its own positional, before the bundle runs (`src/runner/host.ts`, `host-dev.ts`) — both mount `<GtkApplication>` from a `useLayoutEffect`, which always fires after this line. Not needed on the vite path (`gtkx build`/`gtkx dev` bundles run with no extra positional) or the SEA build (which never reads `process.argv`) | `@gtkx/react` exposes a way to pass `runApplication`'s argv explicitly (an `argv` prop on `<GtkApplication>`, or an options object) instead of always reading `process.argv` itself |";
|
|
1695
|
+
}, {
|
|
1696
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1697
|
+
readonly heading: "How each was checked against 1.2.2";
|
|
1698
|
+
readonly text: "The rule is that a changelog entry (or, for a stable release, a release page)\nis a claim and the removal condition is the test, so each row was re-run on\nthe real runtime rather than read about.\n\n- **`runtime-dedupe`** — reproduced the exact shape the condition names —\n two DISTINCT `.node` files in one process — by copying the installed\n `@gtkx/native` + `@gtkx/native-linux-arm64-gnu` package trees (1.2.2) to\n two separate absolute paths, each under its own `node_modules/@gtkx/`\n (Node caches a native addon by the resolved path of the `.node` FILE, so\n two copies at different paths are two distinct files even with identical\n bytes) and importing both `main.js` entry points in one script. First\n import succeeds; the second raises `gtkx: GLib-ERROR:\ng_log_set_writer_func() called multiple times` as an uncaught Node\n exception, exit code 1, no core file — reproduced twice for consistency.\n This is the SAME defect as 1.0 (`log_writer.rs`'s `install()` still uses a\n `OnceLock` — a WITHIN-one-binary guarantee only — confirmed unchanged\n since rc.4 by diffing the file across GitHub tags) but a DIFFERENT\n failure mode: 1.0's identical probe produced a bare SIGABRT/core dump\n (`exit 134`). The change traces to `node_env.rs`'s `raise_fatal`, which\n gained an explicit `napi_open_handle_scope`/`napi_close_handle_scope`\n pair around the raw `napi_fatal_exception` call in the 1.x line (absent\n at 1.0.0, confirmed by diffing `node_env.rs` at both tags) — see\n upstream-gtkx.md ask #2 for the full mechanism. Neither half of the\n removal condition is met: the error still does not name the duplicate\n package.\n- **`prop-portal`** — enumerated the real module exports by reading the\n compiled `dist/index.js` and `dist/internal.js` directly (same method as\n before): `@gtkx/react`'s `dist/index.js` exports exactly `useApplication`,\n `useBindSetting`, `useParentWindow`, `useProperty`, `useSetting`,\n `useSignal`, `rootElement`, `createPortal`, `createRoot`, `quit`;\n `dist/internal.js` exports `createApplicationWindowComponent`,\n `createApplicationComponent`, `createElementComponent`,\n `createPortaledComponent`, `createWindowComponent`, `useLatestRef`,\n `useMergedRef`, `settleAccessible`, `isRootElement`,\n `createReconcilerRoot`, `setReconcilerErrorHandler`. No value in either is\n `\"gtkx:prop\"` — `components/element.js` itself still exports both `Prop`\n and `createElementComponent`, but `internal.js` re-exports only the\n latter. `createPortal`'s own `.d.ts` signature is still `(children,\ncontainer, key?)`, byte-identical to rc.3/rc.4/1.0. A deep import of\n `@gtkx/react/dist/components/element.js` still throws `Package subpath\n'./dist/components/element.js' is not defined by \"exports\"` — reproduced\n fresh against 1.2.2. Functional confirmation:\n `tests/gtk/components/app-registry.gtk.test.tsx` (exercises\n `WindowActions`/`WindowControllers` built on `createSlotPortal`) passes\n clean, 6/6, on 1.2.2.\n- **`renderhook-no-window`** — reproduced the rc.4-era check verbatim, fresh\n on 1.2.2: in one throwaway test file, `Gtk.Window.getToplevels().getNItems()`\n before and after a bare `renderHook(() => null)` reads 0 → 0, then\n `render(null)` in the same file reads 0 → 1. `RenderHookOptions` in\n `dist/render-hook.d.ts` still carries only `wrapper` and `initialProps`,\n and `render-hook.tsx` still constructs `new Gtk.Box()` unconditionally as\n its container. Functional confirmation: `tests/gtk/apis/dimensions.test.tsx`\n (3/3) still passes using the `render()`-first pattern.\n- **`gtk-application-argv`** — read `@gtkx/react@1.2.2`'s installed\n `components/application.tsx` source directly: `commandLine` is still\n `[applicationId?.split(\".\").at(-1) ?? \"gtkx\", ...process.argv.slice(2)]`,\n and `ApplicationComponentProps` still only carries `applicationId`,\n `children` and `ref` — no `argv` field, no options object, grepped the\n whole `@gtkx/react` and `@gtkx/runtime` trees for `argv` and found nothing\n else relevant. Functional confirmation: this task's own\n `npm run typecheck`/`build:dist`/`gallery-smoke.ts` runs on the merged\n worktree state (which mounts `<GtkApplication>` through the workaround)\n stay green.";
|
|
1683
1699
|
}, {
|
|
1684
|
-
readonly doc: "docs/gtkx-
|
|
1685
|
-
readonly heading: "
|
|
1686
|
-
readonly text: "
|
|
1700
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1701
|
+
readonly heading: "What 1.2 changed under us";
|
|
1702
|
+
readonly text: "Unlike 1.0, 1.2 introduced **no new workaround**: the two breaks task 001\n(\"first light\") absorbed — strict signal typing, the `bundle.mjs` rename —\nwere both plain fixes to our own code (a looser-than-actual type signature,\na hardcoded output filename), not gtkx behavior we have to route around, so\nneither has a row here or a removal condition to track.\n\n**1.2.1's criticals-raise-uncaught-exceptions change** (task 001's own\n\"criticals-throw\" probes already confirmed clean at the application level —\nscroll adjustment lore, modal open/close cycles, teardown) turned out to\nmatter for this task too: it is the same change that altered\n`runtime-dedupe`'s failure mode (see the row above and upstream-gtkx.md\nask #2), and re-probing it with two FRESH, more aggressive stress tests\n(a synchronous 5,000-call burst of invalid `Gtk.Adjustment.configure()`\ncalls with an `uncaughtException` handler installed, and a real\n`GtkWidget.addTickCallback`-driven burst of 2,000 identical calls under the\nactual `@gtkx/vitest` forks pool — both well past the 1,699-call burst that\noriginally triggered ask #2's crash) produced zero crashes on 1.2.2, where\nthe same infrastructure crashed on 2026-08-04. See upstream-gtkx.md ask #2\nfor the full writeup and the mechanism found.\n\n`registerClass` subclassing's chain-up capability (1.0's candidate answer to\nupstream-gtkx.md ask #3 — every generated `vfunc*` method `protected` and\nchainable via `super.vfuncX()`) is unchanged on 1.2.2, confirmed by reading\nthe installed `@gtkx/gi/gtk` typings directly; still not adopted into\n`layout-manager.ts`, per this epic's scope (adopting it is a follow-up, not\na migration task).\n\n`createDialogComponent` (upstream ask #10) is unchanged on 1.2.2: the\ninstalled `dist/adw/dialog.d.ts` still types its returned component as\n`(props: PresentedProps<Adw.Dialog>) => ReactNode` with `Adw.Dialog`\nresolved against `@gtkx/react`'s own store — not generic, not\nstore-agnostic. See \"Resolved by configuration\" below; nothing to revert.";
|
|
1687
1703
|
}, {
|
|
1688
|
-
readonly doc: "docs/gtkx-
|
|
1689
|
-
readonly heading: "
|
|
1690
|
-
readonly text: "
|
|
1704
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1705
|
+
readonly heading: "Resolved by configuration";
|
|
1706
|
+
readonly text: "- `dialog-component-ref-widen` — @gtkx/react's `createDialogComponent` pins\n one store's `Adw.Dialog` in its returned props type, which breaks codegen\n typechecking for every workspace app with its own store (upstream ask #10\n in docs/upstream-gtkx.md, **still open on 1.2.2** — the installed\n `dist/adw/dialog.d.ts` is unchanged, confirmed by reading it directly). We\n no longer carry a workaround: the examples set `codegen: false` and share\n the root-generated store — the sanctioned workspace shape\n (`removeSharedStoreShadow` in @gtkx/cli exists exactly for it), which\n makes the app and @gtkx/react resolve the same store by construction.\n This shape stays required, not optional, on 1.2.2 — the factory has not\n become generic. A patch-package patch briefly filled this slot during the\n 1.0 migration and was removed the same day: the installed `.d.ts` proved\n platform-specific for one published version, making any single patch\n unappliable on the other OS.";
|
|
1691
1707
|
}, {
|
|
1692
|
-
readonly doc: "docs/gtkx-
|
|
1693
|
-
readonly heading: "
|
|
1694
|
-
readonly text: "rc.
|
|
1708
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1709
|
+
readonly heading: "Fixed in 1.2.1 (history)";
|
|
1710
|
+
readonly text: "- **`use-signal-stale-handler`** — gtkx's oldest workaround, alive since\n rc.3. `useSignal` routed the handler through React's `useEffectEvent`,\n and `react-reconciler@0.33.0` only refreshed it in\n `commitBeforeMutationEffects` for `case 0` (FunctionComponent) —\n `case 11` (ForwardRef) and `case 15` (SimpleMemoComponent) fell through\n unrefreshed, so any `useEffectEvent` inside a `memo`/`forwardRef`\n component was pinned to its mount closure forever (our `ScrollView` is a\n `forwardRef` with the `useSignal` calls inside it — a fetch-fed FlatList\n emptied itself on the first scroll). Upstream had ruled on this before\n (gtkx-org/gtkx#467, our own fix offered as #469 and **closed unmerged on\n purpose** — @eugeniodepalo: \"closing this in favour of waiting for\n upstream… Since React fixes this properly on 19.3 for all fiber tags, I'd\n rather take the version bump than carry a workaround I'd revert\") — and\n it was re-checked and reconfirmed unfixed on both rc.4 and 1.0.0, since\n the removal condition names a React version a release could satisfy by\n bumping.\n **gtkx fixed it directly instead, without waiting for React 19.3.** The\n 1.2.1 changelog's own bugfix entry: \"Fixed `useSignal` running the handler\n captured on the first render for every emission inside a component\n wrapped in `memo` or `forwardRef`... The hook built on React 19.2's\n `useEffectEvent`, which does not pick up the updated function through\n those wrappers; the handler is now held in a ref written from\n `useInsertionEffect`.\" Confirmed by reading the installed 1.2.2 source\n directly: `@gtkx/react`'s `hooks/use-signal.ts` no longer imports\n `useEffectEvent` at all — it calls the package's own new `useLatestRef`\n (`hooks/use-latest-ref.ts`), a `useRef` refreshed by a `useInsertionEffect`,\n exactly the pattern our bridge wrapper used to restore by hand.\n `react-reconciler` stayed at `^0.33.0` and `react` stayed on `^19.2` in\n the installed 1.2.2 tree — this is gtkx's own fix, not a React bump.\n Probed by flipping `tests/gtk/bridge/use-signal-upstream.gtk.test.tsx`'s\n `it.fails` guard into a plain `it` and running it targeted on 1.2.2: it\n now passes (previously, running the unflipped `it.fails` guard on 1.2.2\n first, per the \"reproduce the original failure first\" discipline, reports\n `Error: Expect test to fail` — the wrapped assertion itself succeeds,\n meaning `it.fails`'s own expectation of failure is what fails). Deleted\n the workaround: `src/gtkx/bridge/use-signal.ts` (the ref-plus-\n `useInsertionEffect` wrapper) is gone, and `src/gtkx/bridge/core.ts`\n re-exports `useSignal` straight from `@gtkx/react` again, alongside the\n package's other hooks.";
|
|
1695
1711
|
}, {
|
|
1696
|
-
readonly doc: "docs/gtkx-
|
|
1712
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1697
1713
|
readonly heading: "Fixed in rc.3 (history, one line each)";
|
|
1698
1714
|
readonly text: "- **`gsk-colorstop-boxed-write`** — constructing a `Gsk.ColorStop` threw in\n the native addon, so SVG gradients had zero constructible stops and painted\n nothing. **Fixed upstream by us** (gtkx-org/gtkx#473, closing #472): a\n record field write converts through `toNative` now.\n- **`graphene-rect-nested-boxed-props`** — the same native bug reached through\n `new Graphene.Rect({ origin, size })`; same upstream fix, so `svg-node.ts`\n uses the plain constructor again.\n- **The codegen freshness lie** — rc.2's `@gtkx/cli` could report \"bindings up\n to date\" over a store `npm install` had pruned. Fixed upstream in\n gtkx-org/gtkx#470 (also ours); separately `src/runner` calls the\n programmatic `@gtkx/codegen` API rather than the CLI.";
|
|
1699
1715
|
}, {
|
|
1700
|
-
readonly doc: "docs/gtkx-
|
|
1716
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1701
1717
|
readonly heading: "Fixed in rc.2 (history, one line each)";
|
|
1702
1718
|
readonly text: "- **`vitest-compositor`** — rc.1 defaulted the headless display to weston;\n rc.2's default IS sway, so `vitest.config.ts` calls the plugin with no\n arguments.\n- **`no-virtual-seat`** — rc.1 had no input seat under sway, so windows never\n activated and `userEvent` was impossible; rc.2 starts a virtual seat.\n- **`fixed-layout-child`** — rc.1's declarative `<GtkFixedLayoutChild>`\n created a detached object; moot since containers moved to our own\n `RnGtkxLayout` manager and GtkFixed left the codebase.\n- **`controllers-as-children`** — rc.1 silently ignored controllers passed as\n JSX; rc.2 has a `controllers` slot on `GtkWidget`. Pressable and TextInput\n still attach theirs imperatively on purpose — a choice now, not a\n workaround.";
|
|
1703
1719
|
}, {
|
|
1704
|
-
readonly doc: "docs/gtkx-
|
|
1705
|
-
readonly heading: "
|
|
1706
|
-
readonly text: "
|
|
1720
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1721
|
+
readonly heading: "Status of this migration";
|
|
1722
|
+
readonly text: "The full suite (186+ files) has not run yet — that is deliberately deferred\nto the `gtkx-1-2-migration` epic's task 003, which runs it exactly once for\nthe whole migration. What is confirmed on 1.2.2 as of this task: `npm run\ntypecheck` and `npm run build:dist` green (both before and after deleting\n`use-signal-stale-handler`), the flipped `use-signal-upstream.gtk.test.tsx`\nregression test green on a targeted run, and every probe in the tables above\n(four re-audited workarounds, two fresh upstream-ask #2 stress probes, one\nretired workaround) behaves as expected. Nothing here should be read as \"the\nsuite passes\" — that claim belongs to task 003 alone.\n\nTwo environmental notes carried forward from the rc.3/rc.4/1.0 era, neither\ngtkx-version-specific and both unexamined by this task:\n\n- **A first codegen after a version bump is slow enough to look like a hang.**\n The store fingerprint includes the app's own config, so each example\n regenerates once on top of the root's run — ~45 s for the gallery on the\n VM. `scripts/gtkx-dev-headless.ts` sleeps 25 s before its first shot and\n will report `FAST-REFRESH-FAIL` on a cold store; run `npx gtkx codegen` in\n the example first.\n- **`gtkx dev` still binds vite's HMR websocket on the fixed port 24678**, and\n the CLI exposes no way to move it. A second `gtkx dev` anywhere on the\n machine logs `WebSocket server error: Port 24678 is already in use` and the\n edit never reaches the app, while the supervisor still prints \"Fast Refresh\n complete\" — so the log marker alone is not proof the refresh applied.";
|
|
1707
1723
|
}, {
|
|
1708
|
-
readonly doc: "docs/gtkx-
|
|
1724
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1709
1725
|
readonly heading: "Behaviour rc.3 changed under us (still true)";
|
|
1710
|
-
readonly text: "- **Blockable signals are no longer suppressed for a whole React commit** —\n rc.3 wraps each framework write individually, so an emission the framework\n did not cause (one raised from a `useLayoutEffect`, or aimed at another\n `createRoot` tree) reaches its handler. Our navigators lean on this.\n- **`render`'s harness window is undecorated**, so role queries see only what\n the test rendered.\n- **A widget with `accessibleLabelledBy` reports the relation as its\n accessible name**, ahead of its own text — the precedence ARIA defines.\n- **`toHaveTextContent` no longer falls back to the accessible name**;\n **`toHaveDisplayValue` throws** on a widget without one; **checked state is\n tri-state**.\n- **Records are constructible only when their bytes can be copied.** Neither\n `Gsk.ColorStop` nor `Graphene.Rect` is caught by it.\n- **Single-child widgets have no `content`/`child` props** (pass the widget as\n a child instead).";
|
|
1726
|
+
readonly text: "Carried forward from the rc.3/rc.4/1.0 notes; none of this is re-verified by\nthis task (it is `@gtkx/testing`-adjacent runtime behavior, out of this\nepic's scope — see the `gtkx-1-0-migration` epic's task 004 for the last\nfull re-check):\n\n- **Blockable signals are no longer suppressed for a whole React commit** —\n rc.3 wraps each framework write individually, so an emission the framework\n did not cause (one raised from a `useLayoutEffect`, or aimed at another\n `createRoot` tree) reaches its handler. Our navigators lean on this.\n- **`render`'s harness window is undecorated**, so role queries see only what\n the test rendered.\n- **A widget with `accessibleLabelledBy` reports the relation as its\n accessible name**, ahead of its own text — the precedence ARIA defines.\n- **`toHaveTextContent` no longer falls back to the accessible name**;\n **`toHaveDisplayValue` throws** on a widget without one; **checked state is\n tri-state**.\n- **Records are constructible only when their bytes can be copied.** Neither\n `Gsk.ColorStop` nor `Graphene.Rect` is caught by it.\n- **Single-child widgets have no `content`/`child` props** (pass the widget as\n a child instead).";
|
|
1711
1727
|
}, {
|
|
1712
|
-
readonly doc: "docs/gtkx-
|
|
1728
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1713
1729
|
readonly heading: "Non-workarounds (quirks that stay)";
|
|
1714
|
-
readonly text: "- 64-bit FFI values arrive as BigInt → `toNumber()` at the boundary\n (`gtkx/bridge/measure.ts`);\n- signal names are kebab-case (\"value-changed\"); signals do not pass the\n emitter (get the widget from a ref);\n- role queries in tests use the `Gtk.AccessibleRole` enum, not strings;\n- `npm install` prunes the codegen store (`node_modules/.gtkx` is not in the\n lockfile) → run `npm run codegen` after installing — npm behavior, not gtkx;\n- measuring unmapped widgets yields 0 (offscreen Label probes are the\n exception) → re-measure on the `map` signal + re-commit measured leaves on\n every flush (`layout/node.ts`);\n- mixed-session setups only: running an app on a bare compositor (headless\n sway) while `XDG_RUNTIME_DIR` points at a full GNOME session can segfault in\n a GTK signal handler when the GNOME settings portal pushes updates into the\n app (`g_cclosure_marshal_VOID__OBJECTv` via the FFI emit path); cutting\n `DBUS_SESSION_BUS_ADDRESS` avoids it, which is why the headless scripts do.\n Normal desktop and container runs are unaffected. The portal-push crash\n needs a live settings change to trigger and stays on the list unconfirmed.";
|
|
1730
|
+
readonly text: "- 64-bit FFI values arrive as BigInt → `toNumber()` at the boundary\n (`gtkx/bridge/measure.ts`);\n- signal names are kebab-case (\"value-changed\"); signals do not pass the\n emitter (get the widget from a ref);\n- role queries in tests use the `Gtk.AccessibleRole` enum, not strings;\n- `npm install` prunes the codegen store (`node_modules/.gtkx` is not in the\n lockfile) → run `npm run codegen` after installing — npm behavior, not gtkx;\n- measuring unmapped widgets yields 0 (offscreen Label probes are the\n exception) → re-measure on the `map` signal + re-commit measured leaves on\n every flush (`layout/node.ts`);\n- mixed-session setups only: running an app on a bare compositor (headless\n sway) while `XDG_RUNTIME_DIR` points at a full GNOME session can segfault in\n a GTK signal handler when the GNOME settings portal pushes updates into the\n app (`g_cclosure_marshal_VOID__OBJECTv` via the FFI emit path); cutting\n `DBUS_SESSION_BUS_ADDRESS` avoids it, which is why the headless scripts do.\n Normal desktop and container runs are unaffected. The portal-push crash\n needs a live settings change to trigger and stays on the list unconfirmed;\n- GLib criticals and errors now raise as a Node `uncaughtException` (1.2.1,\n see upstream-gtkx.md ask #2) — a `g_return_if_fail` violation that used to\n scroll past in a log now ends an app with no `process.on(\"uncaughtException\")`\n handler. `gtkx dev` already installs one; so does every headless probe\n script this repo uses.";
|
|
1715
1731
|
}, {
|
|
1716
|
-
readonly doc: "docs/gtkx-
|
|
1732
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1717
1733
|
readonly heading: "Procedure when the next release ships";
|
|
1718
|
-
readonly text: "1. Update the `@gtkx/*` pins (root, spike, examples, template), then\n `npm install && rm -rf node_modules/.gtkx && npm run codegen`;\n2. Run everything on Linux: `npm run typecheck && npm test`, `build:dist`,\n `check:package`, plus the headless example proofs;\n3. Walk the live-workaround table: for each row check the removal condition,\n delete the tag and the row together when it is met, and move the entry into\n the history section above — **with a probe that proves the fix on the real\n runtime**, not just the release notes claiming it. And make the probe\n reproduce the ORIGINAL failure first: two of the three `runtime-dedupe`\n probes written for rc.4 reported a fix that was not there, because they\n were not actually building the duplicate;\n4. Re-tag whatever survives (`
|
|
1734
|
+
readonly text: "1. Update the `@gtkx/*` pins (root, spike, examples, template), then\n `npm install && rm -rf node_modules/.gtkx && npm run codegen`;\n2. Run everything on Linux: `npm run typecheck && npm test`, `build:dist`,\n `check:package`, plus the headless example proofs;\n3. Walk the live-workaround table: for each row check the removal condition,\n delete the tag and the row together when it is met, and move the entry into\n the history section above — **with a probe that proves the fix on the real\n runtime**, not just the release notes claiming it. And make the probe\n reproduce the ORIGINAL failure first: two of the three `runtime-dedupe`\n probes written for rc.4 reported a fix that was not there, because they\n were not actually building the duplicate; the `use-signal-stale-handler`\n guard the 1.2 audit flipped is the same discipline the other direction —\n running the UNFLIPPED `it.fails` guard on the new runtime first, so the\n \"now fails to fail\" observation is the actual probe, not an assumption.\n The same discipline applies to every future audit, this one included;\n4. Re-tag whatever survives (`1.2-WORKAROUND` → the new release), rename this\n file to match the new pin, and update `docs/upstream-gtkx.md` if an ask was\n answered.";
|
|
1719
1735
|
}, {
|
|
1720
1736
|
readonly doc: "docs/research/navigation-extensibility.md";
|
|
1721
1737
|
readonly heading: "1. The two layers";
|
|
@@ -1737,21 +1753,21 @@ export declare const DOC_CHUNKS: readonly [{
|
|
|
1737
1753
|
readonly heading: "5. The desktop-RN landscape";
|
|
1738
1754
|
readonly text: "No other desktop React Native platform has native navigation integration:\n\n- **react-native-screens** lists Windows support, but it is a thin\n old-architecture module; native-stack on modern react-native-windows\n fails, because screens has no new-architecture Windows implementation and\n RNW 0.82 removed the old one. Microsoft's own react-native-gallery falls\n back to the JS drawer.\n- **react-native-macos** is not supported by react-native-screens at all —\n AppKit has no navigation-stack primitive to bind to.\n\nOur path — a real `Adw.NavigationView` driven from a custom navigator, with\nreact-navigation state as the source of truth and native pops reported back\ninto it — is structurally the iOS native-stack / `UINavigationController`\nmodel, which neither desktop platform reached. GTK's advantage is that the\nprimitive exists at all: back button, Escape, back gesture, history menu and\ntransitions ship with the widget.\n\nThe trade: a JS stack can render anything into its fake header, while our\nchrome is real and had to be opened up deliberately — which is what the\nintrinsic-size root does.\n\nSources: react-native-screens README and discussions #1575 / #2541, RNW\ndiscussions #14273 / issue #4152 / new-architecture docs / 0.82 release\npost, microsoft/react-native-gallery, reactnavigation.org native-stack docs.";
|
|
1739
1755
|
}, {
|
|
1740
|
-
readonly doc: "docs/gtkx-
|
|
1741
|
-
readonly heading: "
|
|
1742
|
-
readonly text: "
|
|
1756
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1757
|
+
readonly heading: "1.2-WORKAROUND(runtime-dedupe)";
|
|
1758
|
+
readonly text: "Two bundled copies of the gtkx runtime still double-init GLib and abort; nothing guards against it across two DISTINCT `.node` files. Reproduced on 1.2.2 by actually building the duplicate: `gtkx: GLib-ERROR: g_log_set_writer_func() called multiple times`. The FAILURE MODE changed since 1.0 (see upstream-gtkx.md ask #2) — it is now a catchable, named Node `uncaughtException` instead of a SIGABRT/core dump — but the underlying defect has not: the init is still not idempotent across distinct binaries, and the error still does not name the duplicate package — our workaround: `src/vite/index.ts` puts `resolve.dedupe` over `@gtkx/*` + `react` (+ `@react-navigation/*` for its context) into the preset every app inherits — removed when: Idempotent runtime init upstream across distinct native-addon files, or an error that names the duplicate";
|
|
1743
1759
|
}, {
|
|
1744
|
-
readonly doc: "docs/gtkx-
|
|
1745
|
-
readonly heading: "
|
|
1746
|
-
readonly text: "
|
|
1760
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1761
|
+
readonly heading: "1.2-WORKAROUND(prop-portal)";
|
|
1762
|
+
readonly text: "`createPortal(children, container, key?)` is still byte-for-byte the rc.3/rc.4 signature and can still only target a container's DEFAULT slot (\"children\"). `@gtkx/react`'s public entry and its `/internal` subpath both still withhold the `\"gtkx:prop\"` element — `/internal` still re-exports `createElementComponent` (the function that BUILDS an intrinsic element by GType name) but not the `Prop` literal itself, which stays a sibling export inside `element.js` that no public or `/internal` path reaches — our workaround: `gtkx/bridge/slot-portal.ts` restates the `\"gtkx:prop\"` element name and wraps it in `createSlotPortal(children, target, slot)` — the one line that would move if gtkx renames it. `WindowActions`/`ApplicationActions`/`WindowControllers` are built on it — removed when: gtkx exports a slot-aware portal (or the prop element) from a public entry point";
|
|
1747
1763
|
}, {
|
|
1748
|
-
readonly doc: "docs/gtkx-
|
|
1749
|
-
readonly heading: "
|
|
1750
|
-
readonly text: "`
|
|
1764
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1765
|
+
readonly heading: "1.2-WORKAROUND(renderhook-no-window)";
|
|
1766
|
+
readonly text: "`renderHook` still mounts into a bare `Gtk.Box` — 1.2.2's `render-hook.js` still passes `container: new Gtk.Box()` unconditionally, and `RenderHookOptions` still carries only `wrapper` and `initialProps` — so window-dependent APIs have no toplevel to read — our workaround: Hook tests create a window with `render()` first (`tests/gtk/apis/dimensions.test.tsx`); packaged for consumers as `renderHookWithWindow` (`react-native-gtkx/testing`) — removed when: `renderHook` mounts into the same harness window `render` uses";
|
|
1751
1767
|
}, {
|
|
1752
|
-
readonly doc: "docs/gtkx-
|
|
1753
|
-
readonly heading: "
|
|
1754
|
-
readonly text: "`
|
|
1768
|
+
readonly doc: "docs/gtkx-1.2-notes.md";
|
|
1769
|
+
readonly heading: "1.2-WORKAROUND(gtk-application-argv)";
|
|
1770
|
+
readonly text: "`@gtkx/react`'s `<GtkApplication>` bootstrap still builds the GApplication's own command line as `[applicationId.split(\".\").at(-1), ...process.argv.slice(2)]` and hands it to `runApplication(application, commandLine)` — confirmed unchanged by reading the installed 1.2.2 source (`components/application.tsx`) directly, no `argv` prop or options object anywhere on `ApplicationComponentProps`. Our runner hosts are invoked as `node dist/runner/host.js <bundle-path>` / `node dist/runner/host-dev.js <bundle-url>`, so `process.argv[2]` is our OWN internal plumbing, not a user-facing argument — left in place it reaches GLib's local command-line handling as a stray positional it tries to open as a file (`GLib-GIO-CRITICAL: This application can not open files`), and the window never activates — our workaround: `process.argv.length = 2` right after each host reads its own positional, before the bundle runs (`src/runner/host.ts`, `host-dev.ts`) — both mount `<GtkApplication>` from a `useLayoutEffect`, which always fires after this line. Not needed on the vite path (`gtkx build`/`gtkx dev` bundles run with no extra positional) or the SEA build (which never reads `process.argv`) — removed when: `@gtkx/react` exposes a way to pass `runApplication`'s argv explicitly (an `argv` prop on `<GtkApplication>`, or an options object) instead of always reading `process.argv` itself";
|
|
1755
1771
|
}, {
|
|
1756
1772
|
readonly doc: "docs/reference/components/view.md";
|
|
1757
1773
|
readonly heading: "View";
|