react-native-gtkx 0.1.0-alpha.2 → 0.1.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 +4 -5
- package/dist/apis/back-handler.d.ts +9 -0
- package/dist/apis/back-handler.js +30 -0
- package/dist/apis/back-handler.js.map +1 -0
- package/dist/apis/host.d.ts +7 -1
- package/dist/apis/host.gtkx.js +12 -1
- package/dist/apis/host.gtkx.js.map +1 -1
- package/dist/apis/host.js.map +1 -1
- package/dist/apis/i18n-manager.d.ts +14 -0
- package/dist/apis/i18n-manager.js +20 -0
- package/dist/apis/i18n-manager.js.map +1 -0
- package/dist/apis/index.d.ts +17 -0
- package/dist/apis/index.js +5 -0
- package/dist/apis/index.js.map +1 -1
- package/dist/apis/interaction-manager.d.ts +16 -0
- package/dist/apis/interaction-manager.js +96 -0
- package/dist/apis/interaction-manager.js.map +1 -0
- package/dist/apis/linking.d.ts +4 -0
- package/dist/apis/linking.js +9 -0
- package/dist/apis/linking.js.map +1 -1
- package/dist/components/app-registry.d.ts +2 -0
- package/dist/components/app-registry.js +19 -2
- package/dist/components/app-registry.js.map +1 -1
- package/dist/components/flat-list.d.ts +2 -0
- package/dist/components/flat-list.js.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/index.js.map +1 -1
- package/dist/components/modal.d.ts +1 -1
- package/dist/components/root.d.ts +10 -1
- package/dist/components/root.js +39 -1
- package/dist/components/root.js.map +1 -1
- package/dist/components/scroll-view.js +58 -5
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/text-input.d.ts +1 -0
- package/dist/components/text-input.js +31 -3
- package/dist/components/text-input.js.map +1 -1
- package/dist/components/use-layout-child.d.ts +1 -1
- package/dist/components/use-layout-child.js +22 -2
- package/dist/components/use-layout-child.js.map +1 -1
- package/dist/components/virtualized-list.d.ts +2 -0
- package/dist/components/virtualized-list.js +132 -10
- package/dist/components/virtualized-list.js.map +1 -1
- package/dist/gtkx/bridge/index.d.ts +4 -2
- package/dist/gtkx/bridge/index.js +6 -2
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/measure.js +5 -0
- package/dist/gtkx/bridge/measure.js.map +1 -1
- package/dist/gtkx/bridge/use-signal.d.ts +2 -0
- package/dist/gtkx/bridge/use-signal.js +30 -0
- package/dist/gtkx/bridge/use-signal.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/layout/engine.d.ts +4 -0
- package/dist/layout/engine.js +97 -5
- package/dist/layout/engine.js.map +1 -1
- package/dist/layout/node.d.ts +1 -1
- package/dist/layout/node.js +8 -5
- package/dist/layout/node.js.map +1 -1
- package/dist/metro/index.js +1 -0
- package/dist/metro/index.js.map +1 -1
- package/dist/navigation/index.d.ts +44 -0
- package/dist/navigation/index.js +216 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/option-warnings.d.ts +2 -0
- package/dist/navigation/option-warnings.js +61 -0
- package/dist/navigation/option-warnings.js.map +1 -0
- package/dist/navigation/sidebar.d.ts +37 -0
- package/dist/navigation/sidebar.js +71 -0
- package/dist/navigation/sidebar.js.map +1 -0
- package/dist/perf.d.ts +9 -0
- package/dist/perf.js +156 -0
- package/dist/perf.js.map +1 -0
- package/dist/runner/host-dev.js +15 -6
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +24 -9
- package/dist/runner/host.js.map +1 -1
- package/dist/runner/index.js +4 -1
- package/dist/runner/index.js.map +1 -1
- package/dist/vite/index.d.ts +5 -4
- package/dist/vite/index.js +41 -7
- package/dist/vite/index.js.map +1 -1
- package/package.json +18 -10
- package/types.d.ts +13 -0
package/README.md
CHANGED
|
@@ -16,11 +16,10 @@ applications on real GTK4/Adwaita widgets, with no WebView and no canvas renderi
|
|
|
16
16
|
|
|
17
17
|
Under the hood: [gtkx](https://github.com/gtkx-org/gtkx) (a React reconciler for GTK4 on Node.js) + [Yoga](https://yogalayout.dev) (the RN flexbox engine). The model follows react-native-web: a compatibility layer on top of another renderer, with the `react-native` → `react-native-gtkx` alias provided by the Metro preset (Linux as a standard RN [out-of-tree platform](https://reactnative.dev/docs/out-of-tree-platforms) — `npx react-native run-linux` next to `run-ios`/`run-android`) or by the vite preset for Linux-first projects.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
</p>
|
|
19
|
+
|  |  |
|
|
20
|
+
| :-------------------------------------------------------------: | :----------------------------------------------------: |
|
|
22
21
|
|
|
23
|
-
_`examples/
|
|
22
|
+
_`examples/hn-app`, live in native GTK windows: a Hacker News reader on the standard React Native Metro toolchain. Tapping a card pushes a real `Adw.NavigationView` page — the back button, the slide and the preserved list position come from the platform, not from JS. The search field sits **inside** the HeaderBar (real RN content in native chrome) and queries the HN API; comments load as you scroll. The data layer is plain Node `fetch` — on this platform "native modules" are just Node._
|
|
24
23
|
|
|
25
24
|
And the portability proof — `examples/profile` renders ONE source file with both renderers, not a single `@gtkx/*` import in it:
|
|
26
25
|
|
|
@@ -72,7 +71,7 @@ docs/research/layout-manager.md).
|
|
|
72
71
|
|
|
73
72
|
## Requirements
|
|
74
73
|
|
|
75
|
-
Linux, GTK4 ≥ 4.20, libadwaita ≥ 1.8, Node.js ≥
|
|
74
|
+
Linux, GTK4 ≥ 4.20, libadwaita ≥ 1.8, Node.js ≥ 24.
|
|
76
75
|
|
|
77
76
|
## License
|
|
78
77
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SubscriptionHandle } from "../contracts";
|
|
2
|
+
import type { BackHandlerHost } from "./host";
|
|
3
|
+
export type BackPressEventName = "hardwareBackPress";
|
|
4
|
+
export type BackPressHandler = () => boolean | null | undefined;
|
|
5
|
+
export declare const createBackHandler: (host: BackHandlerHost) => {
|
|
6
|
+
addEventListener(_event: BackPressEventName, handler: BackPressHandler): SubscriptionHandle;
|
|
7
|
+
exitApp(): void;
|
|
8
|
+
dispatchBackPress(): boolean;
|
|
9
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const createBackHandler = (host) => {
|
|
2
|
+
const handlers = [];
|
|
3
|
+
const remove = (handler) => {
|
|
4
|
+
const index = handlers.indexOf(handler);
|
|
5
|
+
if (index !== -1) {
|
|
6
|
+
handlers.splice(index, 1);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
return {
|
|
10
|
+
addEventListener(_event, handler) {
|
|
11
|
+
handlers.push(handler);
|
|
12
|
+
return { remove: () => remove(handler) };
|
|
13
|
+
},
|
|
14
|
+
exitApp() {
|
|
15
|
+
host.exitApp();
|
|
16
|
+
},
|
|
17
|
+
// Not part of the RN surface: drives the handler chain exactly like a
|
|
18
|
+
// hardware back press would. Returns true when a handler consumed it.
|
|
19
|
+
dispatchBackPress() {
|
|
20
|
+
for (let index = handlers.length - 1; index >= 0; index -= 1) {
|
|
21
|
+
if (handlers[index]?.() === true) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
host.exitApp();
|
|
26
|
+
return false;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=back-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"back-handler.js","sourceRoot":"","sources":["../../src/apis/back-handler.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAqB,EAAE,EAAE;IACzD,MAAM,QAAQ,GAAuB,EAAE,CAAA;IAEvC,MAAM,MAAM,GAAG,CAAC,OAAyB,EAAQ,EAAE;QACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QACvC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QAC3B,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,gBAAgB,CACd,MAA0B,EAC1B,OAAyB;YAEzB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACtB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAA;QAC1C,CAAC;QAED,OAAO;YACL,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;QAED,sEAAsE;QACtE,sEAAsE;QACtE,iBAAiB;YACf,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC7D,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE,CAAC;oBACjC,OAAO,IAAI,CAAA;gBACb,CAAC;YACH,CAAC;YACD,IAAI,CAAC,OAAO,EAAE,CAAA;YACd,OAAO,KAAK,CAAA;QACd,CAAC;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["// react-native BackHandler. Desktop has no hardware back key, so no event\n// fires today — subscriptions are honored and dispatchBackPress exists as\n// the single entry point for a future key binding (RN semantics: handlers\n// run last-registered-first, the first returning true consumes the press,\n// an unconsumed press exits the app — the Android default).\nimport type { SubscriptionHandle } from \"../contracts\"\nimport type { BackHandlerHost } from \"./host\"\n\nexport type BackPressEventName = \"hardwareBackPress\"\nexport type BackPressHandler = () => boolean | null | undefined\n\nexport const createBackHandler = (host: BackHandlerHost) => {\n const handlers: BackPressHandler[] = []\n\n const remove = (handler: BackPressHandler): void => {\n const index = handlers.indexOf(handler)\n if (index !== -1) {\n handlers.splice(index, 1)\n }\n }\n\n return {\n addEventListener(\n _event: BackPressEventName,\n handler: BackPressHandler,\n ): SubscriptionHandle {\n handlers.push(handler)\n return { remove: () => remove(handler) }\n },\n\n exitApp(): void {\n host.exitApp()\n },\n\n // Not part of the RN surface: drives the handler chain exactly like a\n // hardware back press would. Returns true when a handler consumed it.\n dispatchBackPress(): boolean {\n for (let index = handlers.length - 1; index >= 0; index -= 1) {\n if (handlers[index]?.() === true) {\n return true\n }\n }\n host.exitApp()\n return false\n },\n }\n}\n"]}
|
package/dist/apis/host.d.ts
CHANGED
|
@@ -42,4 +42,10 @@ export interface AlertHost {
|
|
|
42
42
|
export interface LinkingHost {
|
|
43
43
|
launchUri(uri: string): Promise<void>;
|
|
44
44
|
}
|
|
45
|
-
export
|
|
45
|
+
export interface I18nHost {
|
|
46
|
+
isRTL(): boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface BackHandlerHost {
|
|
49
|
+
exitApp(): void;
|
|
50
|
+
}
|
|
51
|
+
export type Host = PlatformHost & DimensionsHost & AppearanceHost & AppStateHost & AlertHost & LinkingHost & I18nHost & BackHandlerHost;
|
package/dist/apis/host.gtkx.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Production host adapter: the ONLY module under src/apis/ allowed to import
|
|
2
2
|
// the gtkx bridge. Everything GTK-specific lives here; the API modules stay
|
|
3
3
|
// pure and receive this object (or a mock in unit tests) via injection.
|
|
4
|
-
import { Adw, colorScheme, Gdk, Gio, Gtk, styleManager, toNumber, } from "../gtkx/bridge/index";
|
|
4
|
+
import { Adw, colorScheme, Gdk, Gio, Gtk, quit, styleManager, toNumber, } from "../gtkx/bridge/index";
|
|
5
5
|
const FALLBACK_METRICS = {
|
|
6
6
|
width: 0,
|
|
7
7
|
height: 0,
|
|
@@ -285,6 +285,15 @@ const launchUri = async (uri) => {
|
|
|
285
285
|
// Promisified by the gi codegen; rejects with the GError on failure.
|
|
286
286
|
await launcher.launch(resolveWindow());
|
|
287
287
|
};
|
|
288
|
+
// The default widget direction is GTK's read of the locale text direction.
|
|
289
|
+
const isRTL = () => {
|
|
290
|
+
try {
|
|
291
|
+
return Gtk.Widget.getDefaultDirection() === Gtk.TextDirection.RTL;
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
288
297
|
export const gtkxHost = {
|
|
289
298
|
gtkVersion,
|
|
290
299
|
getWindowMetrics: windowMetrics,
|
|
@@ -297,5 +306,7 @@ export const gtkxHost = {
|
|
|
297
306
|
onActiveChange: (notify) => watchWindow(WINDOW_ACTIVE_SIGNALS, [], notify),
|
|
298
307
|
showAlert,
|
|
299
308
|
launchUri,
|
|
309
|
+
isRTL,
|
|
310
|
+
exitApp: () => quit(),
|
|
300
311
|
};
|
|
301
312
|
//# sourceMappingURL=host.gtkx.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.gtkx.js","sourceRoot":"","sources":["../../src/apis/host.gtkx.ts"],"names":[],"mappings":"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","sourcesContent":["// Production host adapter: the ONLY module under src/apis/ allowed to import\n// the gtkx bridge. Everything GTK-specific lives here; the API modules stay\n// pure and receive this object (or a mock in unit tests) via injection.\n\nimport type { SubscriptionHandle } from \"../contracts\"\nimport {\n Adw,\n colorScheme,\n Gdk,\n Gio,\n Gtk,\n styleManager,\n toNumber,\n} from \"../gtkx/bridge/index\"\nimport type {\n ColorSchemeName,\n Host,\n HostAlertRequest,\n ScaledSize,\n} from \"./host\"\n\nconst FALLBACK_METRICS: ScaledSize = {\n width: 0,\n height: 0,\n scale: 1,\n fontScale: 1,\n}\n\nconst getApplication = (): Gtk.Application | null =>\n Gio.Application.getDefault() as unknown as Gtk.Application | null\n\nconst getActiveAppWindow = (): Gtk.Window | null => {\n const app = getApplication()\n if (!app || typeof app.getActiveWindow !== \"function\") {\n return null\n }\n return app.getActiveWindow() ?? null\n}\n\nconst windowAt = (model: Gio.ListModel, index: number): Gtk.Window | null =>\n model.getItem(index) as unknown as Gtk.Window | null\n\n// The application's active window if any, otherwise the first toplevel. The\n// toplevel fallback covers the test harness, where windows exist without a\n// GtkApplication (`Gio.Application.getDefault()` is null there).\n// RN's Dimensions(\"window\") means the MAIN window: transient toplevels\n// (Modal → modal GtkWindow, dialogs) must never be resolved as \"the window\" —\n// an open modal becomes the active window and would shrink the app viewport\n// to the modal size.\nconst isMainWindow = (window: Gtk.Window): boolean =>\n window.getTransientFor() === null\n\nconst resolveWindow = (): Gtk.Window | null => {\n const active = getActiveAppWindow()\n if (active && isMainWindow(active)) {\n return active\n }\n const toplevels = Gtk.Window.getToplevels()\n const count = toNumber(toplevels.getNItems())\n let first: Gtk.Window | null = null\n for (let index = 0; index < count; index += 1) {\n const window = windowAt(toplevels, index)\n if (!window || !isMainWindow(window)) {\n continue\n }\n if (window.isActive()) {\n return window\n }\n first = first ?? window\n }\n return first\n}\n\nconst isAnyWindowActive = (): boolean => {\n const toplevels = Gtk.Window.getToplevels()\n const count = toNumber(toplevels.getNItems())\n for (let index = 0; index < count; index += 1) {\n if (windowAt(toplevels, index)?.isActive()) {\n return true\n }\n }\n return false\n}\n\nconst windowMetrics = (): ScaledSize => {\n const window = resolveWindow()\n if (!window) {\n return FALLBACK_METRICS\n }\n // RN's Dimensions(\"window\") is the app viewport: the window CHILD's\n // allocation (the content area under the headerbar), not the window widget\n // size. Falls back to the window size before the first allocation.\n const child = window.getChild()\n const childAllocation = child?.getAllocation()\n const allocatedWidth =\n childAllocation && childAllocation.width > 0\n ? toNumber(childAllocation.width)\n : toNumber(window.getWidth())\n const allocatedHeight =\n childAllocation && childAllocation.height > 0\n ? toNumber(childAllocation.height)\n : toNumber(window.getHeight())\n // Before the first allocation everything reports 0 — fall back to\n // the requested default size (which GTK4 also keeps updated on resize).\n const width =\n allocatedWidth > 0\n ? allocatedWidth\n : Math.max(toNumber(window.defaultWidth ?? 0), 0)\n const height =\n allocatedHeight > 0\n ? allocatedHeight\n : Math.max(toNumber(window.defaultHeight ?? 0), 0)\n return {\n width,\n height,\n scale: toNumber(window.getScaleFactor()),\n fontScale: 1,\n }\n}\n\nconst screenMetrics = (): ScaledSize => {\n const display = Gdk.Display.getDefault()\n if (!display) {\n return windowMetrics()\n }\n const monitors = display.getMonitors()\n if (toNumber(monitors.getNItems()) === 0) {\n return windowMetrics()\n }\n const monitor = monitors.getItem(0) as unknown as Gdk.Monitor | null\n if (!monitor) {\n return windowMetrics()\n }\n const geometry = monitor.getGeometry()\n return {\n width: toNumber(geometry.width),\n height: toNumber(geometry.height),\n scale: toNumber(monitor.getScaleFactor()),\n fontScale: 1,\n }\n}\n\n// GtkNative.getSurface is an interface method merged onto Gtk.Window at\n// runtime via mixins; accessed defensively to stay typecheckable either way.\nconst surfaceOf = (window: Gtk.Window): Gdk.Surface | null => {\n const native = window as unknown as { getSurface?: () => Gdk.Surface | null }\n return typeof native.getSurface === \"function\"\n ? (native.getSurface() ?? null)\n : null\n}\n\n// Tracks the \"current\" window across creation/destruction/focus moves:\n// listens on the given signals of the resolved window (and, when requested,\n// its GdkSurface) plus the toplevel list model, re-resolving and re-attaching\n// whenever the tracked window may have changed. Modules dedupe, so\n// over-notifying is fine.\n//\n// Why the surface: notify::default-width fires when setDefaultSize() is\n// called, i.e. before the compositor actually resizes the surface — the\n// allocated size (what Dimensions reports) only changes when the surface\n// does. And GdkSurface notify::width/height fires at configure time, still\n// before the widget allocation pass, so the \"layout\" signal is also needed:\n// it is emitted during the frame's layout phase and — because GTK's own\n// relayout handler is connected first — our handler observes the updated\n// allocation. The module dedupes, so early/no-op emissions cost nothing.\nconst watchWindow = (\n windowSignals: readonly string[],\n surfaceSignals: readonly string[],\n notify: () => void,\n): SubscriptionHandle => {\n let window: Gtk.Window | null = null\n let surface: Gdk.Surface | null = null\n\n const attachWindow = (): void => {\n if (!window) {\n return\n }\n for (const signal of windowSignals) {\n window.on(signal, onSignal)\n }\n }\n\n const detachWindow = (): void => {\n if (!window) {\n return\n }\n for (const signal of windowSignals) {\n window.off(signal, onSignal)\n }\n }\n\n const attachSurface = (): void => {\n if (!surface) {\n return\n }\n for (const signal of surfaceSignals) {\n surface.on(signal, onSignal)\n }\n }\n\n const detachSurface = (): void => {\n if (!surface) {\n return\n }\n for (const signal of surfaceSignals) {\n surface.off(signal, onSignal)\n }\n }\n\n const syncTargets = (): void => {\n const nextWindow = resolveWindow()\n if (nextWindow !== window) {\n detachWindow()\n window = nextWindow\n attachWindow()\n }\n const nextSurface =\n window && surfaceSignals.length > 0 ? surfaceOf(window) : null\n if (nextSurface !== surface) {\n detachSurface()\n surface = nextSurface\n attachSurface()\n }\n }\n\n const onSignal = (): void => {\n syncTargets()\n notify()\n }\n\n const toplevels = Gtk.Window.getToplevels()\n const onToplevelsChanged = (): void => {\n syncTargets()\n notify()\n }\n toplevels.on(\"items-changed\", onToplevelsChanged)\n syncTargets()\n\n return {\n remove: () => {\n detachWindow()\n detachSurface()\n window = null\n surface = null\n toplevels.off(\"items-changed\", onToplevelsChanged)\n },\n }\n}\n\n// realize/map re-run target resolution so the surface listeners attach as\n// soon as the surface exists.\nconst WINDOW_SIZE_SIGNALS = [\n \"notify::default-width\",\n \"notify::default-height\",\n \"realize\",\n \"map\",\n] as const\n\nconst SURFACE_SIZE_SIGNALS = [\n \"notify::width\",\n \"notify::height\",\n \"layout\",\n] as const\n\nconst WINDOW_ACTIVE_SIGNALS = [\"notify::is-active\"] as const\n\nconst gtkVersion = (): string =>\n `${toNumber(Gtk.getMajorVersion())}.${toNumber(Gtk.getMinorVersion())}.${toNumber(Gtk.getMicroVersion())}`\n\nconst setColorScheme = (scheme: ColorSchemeName | null): void => {\n const manager = styleManager()\n if (scheme === \"dark\") {\n manager.setColorScheme(Adw.ColorScheme.FORCE_DARK)\n } else if (scheme === \"light\") {\n manager.setColorScheme(Adw.ColorScheme.FORCE_LIGHT)\n } else {\n manager.setColorScheme(Adw.ColorScheme.DEFAULT)\n }\n // Our apps are GtkApplication (not AdwApplication), so Adwaita may not\n // restyle widgets: duplicate the request through the classic GTK setting,\n // which the theme always honors.\n const settings = Gtk.Settings.getDefault()\n if (settings) {\n if (scheme === null) {\n settings.resetProperty(\"gtk-application-prefer-dark-theme\")\n } else {\n settings.gtkApplicationPreferDarkTheme = scheme === \"dark\"\n }\n }\n}\n\nconst onColorSchemeChange = (notify: () => void): SubscriptionHandle => {\n const manager = styleManager()\n const listener = (): void => notify()\n manager.on(\"notify::dark\", listener)\n return { remove: () => manager.off(\"notify::dark\", listener) }\n}\n\nconst showAlert = async (request: HostAlertRequest): Promise<string | null> => {\n const dialog = new Adw.AlertDialog()\n dialog.setHeading(request.title)\n if (request.message !== undefined && request.message.length > 0) {\n dialog.setBody(request.message)\n }\n let closeResponse: string | null = null\n for (const button of request.buttons) {\n dialog.addResponse(button.id, button.label)\n if (button.style === \"destructive\") {\n dialog.setResponseAppearance(\n button.id,\n Adw.ResponseAppearance.DESTRUCTIVE,\n )\n }\n if (button.isPreferred) {\n dialog.setResponseAppearance(button.id, Adw.ResponseAppearance.SUGGESTED)\n dialog.setDefaultResponse(button.id)\n }\n if (button.style === \"cancel\") {\n closeResponse = button.id\n }\n }\n if (closeResponse !== null) {\n // Esc / close maps onto the cancel button, like RN's cancel semantics.\n dialog.setCloseResponse(closeResponse)\n } else if (!request.cancelable) {\n // No cancel button and not cancelable: block Esc-dismissal. Responses\n // still close the dialog (they bypass the can-close guard).\n dialog.setCanClose(false)\n }\n const response = await dialog.choose(resolveWindow())\n // Anything that is not one of our buttons (e.g. the built-in \"close\"\n // response) is a dismissal.\n return request.buttons.some((button) => button.id === response)\n ? response\n : null\n}\n\nconst launchUri = async (uri: string): Promise<void> => {\n const launcher = new Gtk.UriLauncher({ uri })\n // Promisified by the gi codegen; rejects with the GError on failure.\n await launcher.launch(resolveWindow())\n}\n\nexport const gtkxHost: Host = {\n gtkVersion,\n getWindowMetrics: windowMetrics,\n getScreenMetrics: screenMetrics,\n onMetricsChange: (notify) =>\n watchWindow(WINDOW_SIZE_SIGNALS, SURFACE_SIZE_SIGNALS, notify),\n getColorScheme: () => colorScheme(),\n setColorScheme,\n onColorSchemeChange,\n isActive: isAnyWindowActive,\n onActiveChange: (notify) => watchWindow(WINDOW_ACTIVE_SIGNALS, [], notify),\n showAlert,\n launchUri,\n}\n"]}
|
|
1
|
+
{"version":3,"file":"host.gtkx.js","sourceRoot":"","sources":["../../src/apis/host.gtkx.ts"],"names":[],"mappings":"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","sourcesContent":["// Production host adapter: the ONLY module under src/apis/ allowed to import\n// the gtkx bridge. Everything GTK-specific lives here; the API modules stay\n// pure and receive this object (or a mock in unit tests) via injection.\n\nimport type { SubscriptionHandle } from \"../contracts\"\nimport {\n Adw,\n colorScheme,\n Gdk,\n Gio,\n Gtk,\n quit,\n styleManager,\n toNumber,\n} from \"../gtkx/bridge/index\"\nimport type {\n ColorSchemeName,\n Host,\n HostAlertRequest,\n ScaledSize,\n} from \"./host\"\n\nconst FALLBACK_METRICS: ScaledSize = {\n width: 0,\n height: 0,\n scale: 1,\n fontScale: 1,\n}\n\nconst getApplication = (): Gtk.Application | null =>\n Gio.Application.getDefault() as unknown as Gtk.Application | null\n\nconst getActiveAppWindow = (): Gtk.Window | null => {\n const app = getApplication()\n if (!app || typeof app.getActiveWindow !== \"function\") {\n return null\n }\n return app.getActiveWindow() ?? null\n}\n\nconst windowAt = (model: Gio.ListModel, index: number): Gtk.Window | null =>\n model.getItem(index) as unknown as Gtk.Window | null\n\n// The application's active window if any, otherwise the first toplevel. The\n// toplevel fallback covers the test harness, where windows exist without a\n// GtkApplication (`Gio.Application.getDefault()` is null there).\n// RN's Dimensions(\"window\") means the MAIN window: transient toplevels\n// (Modal → modal GtkWindow, dialogs) must never be resolved as \"the window\" —\n// an open modal becomes the active window and would shrink the app viewport\n// to the modal size.\nconst isMainWindow = (window: Gtk.Window): boolean =>\n window.getTransientFor() === null\n\nconst resolveWindow = (): Gtk.Window | null => {\n const active = getActiveAppWindow()\n if (active && isMainWindow(active)) {\n return active\n }\n const toplevels = Gtk.Window.getToplevels()\n const count = toNumber(toplevels.getNItems())\n let first: Gtk.Window | null = null\n for (let index = 0; index < count; index += 1) {\n const window = windowAt(toplevels, index)\n if (!window || !isMainWindow(window)) {\n continue\n }\n if (window.isActive()) {\n return window\n }\n first = first ?? window\n }\n return first\n}\n\nconst isAnyWindowActive = (): boolean => {\n const toplevels = Gtk.Window.getToplevels()\n const count = toNumber(toplevels.getNItems())\n for (let index = 0; index < count; index += 1) {\n if (windowAt(toplevels, index)?.isActive()) {\n return true\n }\n }\n return false\n}\n\nconst windowMetrics = (): ScaledSize => {\n const window = resolveWindow()\n if (!window) {\n return FALLBACK_METRICS\n }\n // RN's Dimensions(\"window\") is the app viewport: the window CHILD's\n // allocation (the content area under the headerbar), not the window widget\n // size. Falls back to the window size before the first allocation.\n const child = window.getChild()\n const childAllocation = child?.getAllocation()\n const allocatedWidth =\n childAllocation && childAllocation.width > 0\n ? toNumber(childAllocation.width)\n : toNumber(window.getWidth())\n const allocatedHeight =\n childAllocation && childAllocation.height > 0\n ? toNumber(childAllocation.height)\n : toNumber(window.getHeight())\n // Before the first allocation everything reports 0 — fall back to\n // the requested default size (which GTK4 also keeps updated on resize).\n const width =\n allocatedWidth > 0\n ? allocatedWidth\n : Math.max(toNumber(window.defaultWidth ?? 0), 0)\n const height =\n allocatedHeight > 0\n ? allocatedHeight\n : Math.max(toNumber(window.defaultHeight ?? 0), 0)\n return {\n width,\n height,\n scale: toNumber(window.getScaleFactor()),\n fontScale: 1,\n }\n}\n\nconst screenMetrics = (): ScaledSize => {\n const display = Gdk.Display.getDefault()\n if (!display) {\n return windowMetrics()\n }\n const monitors = display.getMonitors()\n if (toNumber(monitors.getNItems()) === 0) {\n return windowMetrics()\n }\n const monitor = monitors.getItem(0) as unknown as Gdk.Monitor | null\n if (!monitor) {\n return windowMetrics()\n }\n const geometry = monitor.getGeometry()\n return {\n width: toNumber(geometry.width),\n height: toNumber(geometry.height),\n scale: toNumber(monitor.getScaleFactor()),\n fontScale: 1,\n }\n}\n\n// GtkNative.getSurface is an interface method merged onto Gtk.Window at\n// runtime via mixins; accessed defensively to stay typecheckable either way.\nconst surfaceOf = (window: Gtk.Window): Gdk.Surface | null => {\n const native = window as unknown as { getSurface?: () => Gdk.Surface | null }\n return typeof native.getSurface === \"function\"\n ? (native.getSurface() ?? null)\n : null\n}\n\n// Tracks the \"current\" window across creation/destruction/focus moves:\n// listens on the given signals of the resolved window (and, when requested,\n// its GdkSurface) plus the toplevel list model, re-resolving and re-attaching\n// whenever the tracked window may have changed. Modules dedupe, so\n// over-notifying is fine.\n//\n// Why the surface: notify::default-width fires when setDefaultSize() is\n// called, i.e. before the compositor actually resizes the surface — the\n// allocated size (what Dimensions reports) only changes when the surface\n// does. And GdkSurface notify::width/height fires at configure time, still\n// before the widget allocation pass, so the \"layout\" signal is also needed:\n// it is emitted during the frame's layout phase and — because GTK's own\n// relayout handler is connected first — our handler observes the updated\n// allocation. The module dedupes, so early/no-op emissions cost nothing.\nconst watchWindow = (\n windowSignals: readonly string[],\n surfaceSignals: readonly string[],\n notify: () => void,\n): SubscriptionHandle => {\n let window: Gtk.Window | null = null\n let surface: Gdk.Surface | null = null\n\n const attachWindow = (): void => {\n if (!window) {\n return\n }\n for (const signal of windowSignals) {\n window.on(signal, onSignal)\n }\n }\n\n const detachWindow = (): void => {\n if (!window) {\n return\n }\n for (const signal of windowSignals) {\n window.off(signal, onSignal)\n }\n }\n\n const attachSurface = (): void => {\n if (!surface) {\n return\n }\n for (const signal of surfaceSignals) {\n surface.on(signal, onSignal)\n }\n }\n\n const detachSurface = (): void => {\n if (!surface) {\n return\n }\n for (const signal of surfaceSignals) {\n surface.off(signal, onSignal)\n }\n }\n\n const syncTargets = (): void => {\n const nextWindow = resolveWindow()\n if (nextWindow !== window) {\n detachWindow()\n window = nextWindow\n attachWindow()\n }\n const nextSurface =\n window && surfaceSignals.length > 0 ? surfaceOf(window) : null\n if (nextSurface !== surface) {\n detachSurface()\n surface = nextSurface\n attachSurface()\n }\n }\n\n const onSignal = (): void => {\n syncTargets()\n notify()\n }\n\n const toplevels = Gtk.Window.getToplevels()\n const onToplevelsChanged = (): void => {\n syncTargets()\n notify()\n }\n toplevels.on(\"items-changed\", onToplevelsChanged)\n syncTargets()\n\n return {\n remove: () => {\n detachWindow()\n detachSurface()\n window = null\n surface = null\n toplevels.off(\"items-changed\", onToplevelsChanged)\n },\n }\n}\n\n// realize/map re-run target resolution so the surface listeners attach as\n// soon as the surface exists.\nconst WINDOW_SIZE_SIGNALS = [\n \"notify::default-width\",\n \"notify::default-height\",\n \"realize\",\n \"map\",\n] as const\n\nconst SURFACE_SIZE_SIGNALS = [\n \"notify::width\",\n \"notify::height\",\n \"layout\",\n] as const\n\nconst WINDOW_ACTIVE_SIGNALS = [\"notify::is-active\"] as const\n\nconst gtkVersion = (): string =>\n `${toNumber(Gtk.getMajorVersion())}.${toNumber(Gtk.getMinorVersion())}.${toNumber(Gtk.getMicroVersion())}`\n\nconst setColorScheme = (scheme: ColorSchemeName | null): void => {\n const manager = styleManager()\n if (scheme === \"dark\") {\n manager.setColorScheme(Adw.ColorScheme.FORCE_DARK)\n } else if (scheme === \"light\") {\n manager.setColorScheme(Adw.ColorScheme.FORCE_LIGHT)\n } else {\n manager.setColorScheme(Adw.ColorScheme.DEFAULT)\n }\n // Our apps are GtkApplication (not AdwApplication), so Adwaita may not\n // restyle widgets: duplicate the request through the classic GTK setting,\n // which the theme always honors.\n const settings = Gtk.Settings.getDefault()\n if (settings) {\n if (scheme === null) {\n settings.resetProperty(\"gtk-application-prefer-dark-theme\")\n } else {\n settings.gtkApplicationPreferDarkTheme = scheme === \"dark\"\n }\n }\n}\n\nconst onColorSchemeChange = (notify: () => void): SubscriptionHandle => {\n const manager = styleManager()\n const listener = (): void => notify()\n manager.on(\"notify::dark\", listener)\n return { remove: () => manager.off(\"notify::dark\", listener) }\n}\n\nconst showAlert = async (request: HostAlertRequest): Promise<string | null> => {\n const dialog = new Adw.AlertDialog()\n dialog.setHeading(request.title)\n if (request.message !== undefined && request.message.length > 0) {\n dialog.setBody(request.message)\n }\n let closeResponse: string | null = null\n for (const button of request.buttons) {\n dialog.addResponse(button.id, button.label)\n if (button.style === \"destructive\") {\n dialog.setResponseAppearance(\n button.id,\n Adw.ResponseAppearance.DESTRUCTIVE,\n )\n }\n if (button.isPreferred) {\n dialog.setResponseAppearance(button.id, Adw.ResponseAppearance.SUGGESTED)\n dialog.setDefaultResponse(button.id)\n }\n if (button.style === \"cancel\") {\n closeResponse = button.id\n }\n }\n if (closeResponse !== null) {\n // Esc / close maps onto the cancel button, like RN's cancel semantics.\n dialog.setCloseResponse(closeResponse)\n } else if (!request.cancelable) {\n // No cancel button and not cancelable: block Esc-dismissal. Responses\n // still close the dialog (they bypass the can-close guard).\n dialog.setCanClose(false)\n }\n const response = await dialog.choose(resolveWindow())\n // Anything that is not one of our buttons (e.g. the built-in \"close\"\n // response) is a dismissal.\n return request.buttons.some((button) => button.id === response)\n ? response\n : null\n}\n\nconst launchUri = async (uri: string): Promise<void> => {\n const launcher = new Gtk.UriLauncher({ uri })\n // Promisified by the gi codegen; rejects with the GError on failure.\n await launcher.launch(resolveWindow())\n}\n\n// The default widget direction is GTK's read of the locale text direction.\nconst isRTL = (): boolean => {\n try {\n return Gtk.Widget.getDefaultDirection() === Gtk.TextDirection.RTL\n } catch {\n return false\n }\n}\n\nexport const gtkxHost: Host = {\n gtkVersion,\n getWindowMetrics: windowMetrics,\n getScreenMetrics: screenMetrics,\n onMetricsChange: (notify) =>\n watchWindow(WINDOW_SIZE_SIGNALS, SURFACE_SIZE_SIGNALS, notify),\n getColorScheme: () => colorScheme(),\n setColorScheme,\n onColorSchemeChange,\n isActive: isAnyWindowActive,\n onActiveChange: (notify) => watchWindow(WINDOW_ACTIVE_SIGNALS, [], notify),\n showAlert,\n launchUri,\n isRTL,\n exitApp: () => quit(),\n}\n"]}
|
package/dist/apis/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/apis/host.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,+EAA+E;AAC/E,4EAA4E;AAC5E,yDAAyD","sourcesContent":["// Narrow host interfaces backing the react-native compatible API modules.\n// The pure modules in this directory receive these capabilities via injection:\n// production wiring passes the gtkx adapter (host.gtkx.ts), unit tests pass\n// in-memory mocks, so all module logic runs without GTK.\n\nimport type { SubscriptionHandle } from \"../contracts\"\n\nexport type ColorSchemeName = \"light\" | \"dark\"\n\n// Matches react-native's ScaledSize (Dimensions.get / useWindowDimensions).\nexport type ScaledSize = {\n width: number\n height: number\n scale: number\n fontScale: number\n}\n\nexport type AlertButtonStyle = \"default\" | \"cancel\" | \"destructive\"\n\nexport type HostAlertButton = {\n id: string\n label: string\n style: AlertButtonStyle\n isPreferred: boolean\n}\n\nexport type HostAlertRequest = {\n title: string\n message?: string\n buttons: HostAlertButton[]\n cancelable: boolean\n}\n\nexport interface PlatformHost {\n // Runtime GTK version, e.g. \"4.22.4\".\n gtkVersion(): string\n}\n\nexport interface DimensionsHost {\n getWindowMetrics(): ScaledSize\n getScreenMetrics(): ScaledSize\n // Fires whenever the window geometry (or the tracked window itself) may\n // have changed; the module re-reads metrics and dedupes.\n onMetricsChange(notify: () => void): SubscriptionHandle\n}\n\nexport interface AppearanceHost {\n getColorScheme(): ColorSchemeName\n // null resets to the system preference.\n setColorScheme(scheme: ColorSchemeName | null): void\n onColorSchemeChange(notify: () => void): SubscriptionHandle\n}\n\nexport interface AppStateHost {\n isActive(): boolean\n onActiveChange(notify: () => void): SubscriptionHandle\n}\n\nexport interface AlertHost {\n // Resolves with the id of the pressed button, or null when the dialog was\n // dismissed without pressing any of the requested buttons.\n showAlert(request: HostAlertRequest): Promise<string | null>\n}\n\nexport interface LinkingHost {\n launchUri(uri: string): Promise<void>\n}\n\nexport type Host = PlatformHost &\n DimensionsHost &\n AppearanceHost &\n AppStateHost &\n AlertHost &\n LinkingHost\n"]}
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/apis/host.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,+EAA+E;AAC/E,4EAA4E;AAC5E,yDAAyD","sourcesContent":["// Narrow host interfaces backing the react-native compatible API modules.\n// The pure modules in this directory receive these capabilities via injection:\n// production wiring passes the gtkx adapter (host.gtkx.ts), unit tests pass\n// in-memory mocks, so all module logic runs without GTK.\n\nimport type { SubscriptionHandle } from \"../contracts\"\n\nexport type ColorSchemeName = \"light\" | \"dark\"\n\n// Matches react-native's ScaledSize (Dimensions.get / useWindowDimensions).\nexport type ScaledSize = {\n width: number\n height: number\n scale: number\n fontScale: number\n}\n\nexport type AlertButtonStyle = \"default\" | \"cancel\" | \"destructive\"\n\nexport type HostAlertButton = {\n id: string\n label: string\n style: AlertButtonStyle\n isPreferred: boolean\n}\n\nexport type HostAlertRequest = {\n title: string\n message?: string\n buttons: HostAlertButton[]\n cancelable: boolean\n}\n\nexport interface PlatformHost {\n // Runtime GTK version, e.g. \"4.22.4\".\n gtkVersion(): string\n}\n\nexport interface DimensionsHost {\n getWindowMetrics(): ScaledSize\n getScreenMetrics(): ScaledSize\n // Fires whenever the window geometry (or the tracked window itself) may\n // have changed; the module re-reads metrics and dedupes.\n onMetricsChange(notify: () => void): SubscriptionHandle\n}\n\nexport interface AppearanceHost {\n getColorScheme(): ColorSchemeName\n // null resets to the system preference.\n setColorScheme(scheme: ColorSchemeName | null): void\n onColorSchemeChange(notify: () => void): SubscriptionHandle\n}\n\nexport interface AppStateHost {\n isActive(): boolean\n onActiveChange(notify: () => void): SubscriptionHandle\n}\n\nexport interface AlertHost {\n // Resolves with the id of the pressed button, or null when the dialog was\n // dismissed without pressing any of the requested buttons.\n showAlert(request: HostAlertRequest): Promise<string | null>\n}\n\nexport interface LinkingHost {\n launchUri(uri: string): Promise<void>\n}\n\nexport interface I18nHost {\n // Locale text direction as GTK resolved it (the widget default direction).\n isRTL(): boolean\n}\n\nexport interface BackHandlerHost {\n exitApp(): void\n}\n\nexport type Host = PlatformHost &\n DimensionsHost &\n AppearanceHost &\n AppStateHost &\n AlertHost &\n LinkingHost &\n I18nHost &\n BackHandlerHost\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { I18nHost } from "./host";
|
|
2
|
+
export type I18nManagerConstants = {
|
|
3
|
+
isRTL: boolean;
|
|
4
|
+
doLeftAndRightSwapInRTL: boolean;
|
|
5
|
+
localeIdentifier?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const createI18nManager: (host: I18nHost) => {
|
|
8
|
+
readonly isRTL: boolean;
|
|
9
|
+
doLeftAndRightSwapInRTL: boolean;
|
|
10
|
+
getConstants: () => I18nManagerConstants;
|
|
11
|
+
allowRTL: (allow: boolean) => void;
|
|
12
|
+
forceRTL: (force: boolean) => void;
|
|
13
|
+
swapLeftAndRightInRTL: (swap: boolean) => void;
|
|
14
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const createI18nManager = (host) => ({
|
|
2
|
+
get isRTL() {
|
|
3
|
+
return host.isRTL();
|
|
4
|
+
},
|
|
5
|
+
doLeftAndRightSwapInRTL: true,
|
|
6
|
+
getConstants: () => ({
|
|
7
|
+
isRTL: host.isRTL(),
|
|
8
|
+
doLeftAndRightSwapInRTL: true,
|
|
9
|
+
}),
|
|
10
|
+
allowRTL: (allow) => {
|
|
11
|
+
void allow;
|
|
12
|
+
},
|
|
13
|
+
forceRTL: (force) => {
|
|
14
|
+
void force;
|
|
15
|
+
},
|
|
16
|
+
swapLeftAndRightInRTL: (swap) => {
|
|
17
|
+
void swap;
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=i18n-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n-manager.js","sourceRoot":"","sources":["../../src/apis/i18n-manager.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAc,EAAE,EAAE,CAAC,CAAC;IACpD,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,KAAK,EAAE,CAAA;IACrB,CAAC;IACD,uBAAuB,EAAE,IAAI;IAC7B,YAAY,EAAE,GAAyB,EAAE,CAAC,CAAC;QACzC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;QACnB,uBAAuB,EAAE,IAAI;KAC9B,CAAC;IACF,QAAQ,EAAE,CAAC,KAAc,EAAQ,EAAE;QACjC,KAAK,KAAK,CAAA;IACZ,CAAC;IACD,QAAQ,EAAE,CAAC,KAAc,EAAQ,EAAE;QACjC,KAAK,KAAK,CAAA;IACZ,CAAC;IACD,qBAAqB,EAAE,CAAC,IAAa,EAAQ,EAAE;QAC7C,KAAK,IAAI,CAAA;IACX,CAAC;CACF,CAAC,CAAA","sourcesContent":["// react-native I18nManager. Reads are real: isRTL reflects the locale text\n// direction GTK resolved for the process. The writers (allowRTL / forceRTL /\n// swapLeftAndRightInRTL) are persisted preferences on mobile that apply from\n// the NEXT app start — there is no equivalent desktop store, so they are\n// accepted and ignored (documented in docs/api.md).\nimport type { I18nHost } from \"./host\"\n\nexport type I18nManagerConstants = {\n isRTL: boolean\n doLeftAndRightSwapInRTL: boolean\n localeIdentifier?: string\n}\n\nexport const createI18nManager = (host: I18nHost) => ({\n get isRTL(): boolean {\n return host.isRTL()\n },\n doLeftAndRightSwapInRTL: true,\n getConstants: (): I18nManagerConstants => ({\n isRTL: host.isRTL(),\n doLeftAndRightSwapInRTL: true,\n }),\n allowRTL: (allow: boolean): void => {\n void allow\n },\n forceRTL: (force: boolean): void => {\n void force\n },\n swapLeftAndRightInRTL: (swap: boolean): void => {\n void swap\n },\n})\n"]}
|
package/dist/apis/index.d.ts
CHANGED
|
@@ -27,8 +27,25 @@ export declare const Linking: {
|
|
|
27
27
|
openURL: (url: string) => Promise<void>;
|
|
28
28
|
canOpenURL: (url: string) => Promise<boolean>;
|
|
29
29
|
getInitialURL: () => Promise<string | null>;
|
|
30
|
+
addEventListener: (type: "url", handler: (event: {
|
|
31
|
+
url: string;
|
|
32
|
+
}) => void) => import("../contracts").SubscriptionHandle;
|
|
33
|
+
};
|
|
34
|
+
export declare const I18nManager: {
|
|
35
|
+
readonly isRTL: boolean;
|
|
36
|
+
doLeftAndRightSwapInRTL: boolean;
|
|
37
|
+
getConstants: () => import("./i18n-manager").I18nManagerConstants;
|
|
38
|
+
allowRTL: (allow: boolean) => void;
|
|
39
|
+
forceRTL: (force: boolean) => void;
|
|
40
|
+
swapLeftAndRightInRTL: (swap: boolean) => void;
|
|
41
|
+
};
|
|
42
|
+
export declare const BackHandler: {
|
|
43
|
+
addEventListener(_event: import("./back-handler").BackPressEventName, handler: import("./back-handler").BackPressHandler): import("../contracts").SubscriptionHandle;
|
|
44
|
+
exitApp(): void;
|
|
45
|
+
dispatchBackPress(): boolean;
|
|
30
46
|
};
|
|
31
47
|
export { DevSettings } from "./dev-settings";
|
|
48
|
+
export { InteractionManager, type InteractionPromise, } from "./interaction-manager";
|
|
32
49
|
export declare const useWindowDimensions: () => import("./host").ScaledSize;
|
|
33
50
|
export declare const useColorScheme: () => import("./host").ColorSchemeName;
|
|
34
51
|
export type { AlertButton, AlertOptions } from "./alert";
|
package/dist/apis/index.js
CHANGED
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
import { createAlert } from "./alert";
|
|
5
5
|
import { createAppState } from "./app-state";
|
|
6
6
|
import { createAppearance } from "./appearance";
|
|
7
|
+
import { createBackHandler } from "./back-handler";
|
|
7
8
|
import { createDimensions } from "./dimensions";
|
|
8
9
|
import { createUseColorScheme, createUseWindowDimensions } from "./hooks";
|
|
9
10
|
import { gtkxHost } from "./host.gtkx";
|
|
11
|
+
import { createI18nManager } from "./i18n-manager";
|
|
10
12
|
import { createLinking } from "./linking";
|
|
11
13
|
import { createPlatform } from "./platform";
|
|
12
14
|
export const Platform = createPlatform(gtkxHost);
|
|
@@ -15,7 +17,10 @@ export const Appearance = createAppearance(gtkxHost);
|
|
|
15
17
|
export const AppState = createAppState(gtkxHost);
|
|
16
18
|
export const Alert = createAlert(gtkxHost);
|
|
17
19
|
export const Linking = createLinking(gtkxHost);
|
|
20
|
+
export const I18nManager = createI18nManager(gtkxHost);
|
|
21
|
+
export const BackHandler = createBackHandler(gtkxHost);
|
|
18
22
|
export { DevSettings } from "./dev-settings";
|
|
23
|
+
export { InteractionManager, } from "./interaction-manager";
|
|
19
24
|
export const useWindowDimensions = createUseWindowDimensions(Dimensions);
|
|
20
25
|
export const useColorScheme = createUseColorScheme(Appearance);
|
|
21
26
|
//# sourceMappingURL=index.js.map
|
package/dist/apis/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/apis/index.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,8EAA8E;AAC9E,0EAA0E;AAE1E,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;AAChD,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;AACpD,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;AAChD,MAAM,CAAC,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAC1C,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/apis/index.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,8EAA8E;AAC9E,0EAA0E;AAE1E,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;AAChD,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;AACpD,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;AAChD,MAAM,CAAC,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAC1C,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;AAC9C,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACtD,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EACL,kBAAkB,GAEnB,MAAM,uBAAuB,CAAA;AAE9B,MAAM,CAAC,MAAM,mBAAmB,GAAG,yBAAyB,CAAC,UAAU,CAAC,CAAA;AACxE,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAA","sourcesContent":["// Production wiring: singleton API modules bound to the gtkx host, exported\n// under their react-native names. Unit tests use the create* factories with a\n// mock host instead of importing this file (it pulls in the gtkx bridge).\n\nimport { createAlert } from \"./alert\"\nimport { createAppState } from \"./app-state\"\nimport { createAppearance } from \"./appearance\"\nimport { createBackHandler } from \"./back-handler\"\nimport { createDimensions } from \"./dimensions\"\nimport { createUseColorScheme, createUseWindowDimensions } from \"./hooks\"\nimport { gtkxHost } from \"./host.gtkx\"\nimport { createI18nManager } from \"./i18n-manager\"\nimport { createLinking } from \"./linking\"\nimport { createPlatform } from \"./platform\"\n\nexport const Platform = createPlatform(gtkxHost)\nexport const Dimensions = createDimensions(gtkxHost)\nexport const Appearance = createAppearance(gtkxHost)\nexport const AppState = createAppState(gtkxHost)\nexport const Alert = createAlert(gtkxHost)\nexport const Linking = createLinking(gtkxHost)\nexport const I18nManager = createI18nManager(gtkxHost)\nexport const BackHandler = createBackHandler(gtkxHost)\nexport { DevSettings } from \"./dev-settings\"\nexport {\n InteractionManager,\n type InteractionPromise,\n} from \"./interaction-manager\"\n\nexport const useWindowDimensions = createUseWindowDimensions(Dimensions)\nexport const useColorScheme = createUseColorScheme(Appearance)\n\nexport type { AlertButton, AlertOptions } from \"./alert\"\nexport type { AppStateEvent, AppStateStatus } from \"./app-state\"\nexport type { AppearancePreferences } from \"./appearance\"\nexport type { DimensionKey, DimensionsPayload } from \"./dimensions\"\nexport type { AlertButtonStyle, ColorSchemeName, ScaledSize } from \"./host\"\nexport type { PlatformSelectSpec } from \"./platform\"\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type Task = () => void;
|
|
2
|
+
type InteractionListener = () => void;
|
|
3
|
+
export type InteractionPromise = Promise<void> & {
|
|
4
|
+
cancel: () => void;
|
|
5
|
+
done: (callback: Task) => void;
|
|
6
|
+
};
|
|
7
|
+
export declare const InteractionManager: {
|
|
8
|
+
runAfterInteractions(task?: Task): InteractionPromise;
|
|
9
|
+
createInteractionHandle(): number;
|
|
10
|
+
clearInteractionHandle(handle: number): void;
|
|
11
|
+
addListener(event: "interactionStart" | "interactionComplete", listener: InteractionListener): {
|
|
12
|
+
remove: () => void;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare const resetInteractionManager: () => void;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// react-native InteractionManager. Long-running work (list rendering, data
|
|
2
|
+
// crunching) scheduled through runAfterInteractions waits until no
|
|
3
|
+
// "interaction" is in progress — on this platform an interaction is a
|
|
4
|
+
// navigation transition (a stack push/pop slide). This keeps the animation
|
|
5
|
+
// frames clear of competing work; the navigators bracket their transitions
|
|
6
|
+
// with createInteractionHandle / clearInteractionHandle.
|
|
7
|
+
//
|
|
8
|
+
// Semantics mirror RN's: handles are reference-counted, tasks queue while
|
|
9
|
+
// any handle is open and flush once the count returns to zero, and
|
|
10
|
+
// runAfterInteractions returns a cancellable, then-able handle.
|
|
11
|
+
let handleCounter = 0;
|
|
12
|
+
const openHandles = new Set();
|
|
13
|
+
let pending = [];
|
|
14
|
+
let taskCounter = 0;
|
|
15
|
+
const startListeners = new Set();
|
|
16
|
+
const completeListeners = new Set();
|
|
17
|
+
const flushIfIdle = () => {
|
|
18
|
+
if (openHandles.size > 0 || pending.length === 0) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const tasks = pending;
|
|
22
|
+
pending = [];
|
|
23
|
+
for (const task of tasks) {
|
|
24
|
+
task.run();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export const InteractionManager = {
|
|
28
|
+
// RN parity: a small pre-flush spacing so a burst of scheduling does not
|
|
29
|
+
// starve the very frame the last interaction ended on. Kept minimal.
|
|
30
|
+
runAfterInteractions(task) {
|
|
31
|
+
const id = (taskCounter += 1);
|
|
32
|
+
let cancelled = false;
|
|
33
|
+
let settle = () => { };
|
|
34
|
+
const promise = new Promise((resolve) => {
|
|
35
|
+
settle = resolve;
|
|
36
|
+
});
|
|
37
|
+
const run = () => {
|
|
38
|
+
if (cancelled) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
task?.();
|
|
42
|
+
settle();
|
|
43
|
+
};
|
|
44
|
+
pending.push({ id, run });
|
|
45
|
+
promise.cancel = () => {
|
|
46
|
+
cancelled = true;
|
|
47
|
+
pending = pending.filter((entry) => entry.id !== id);
|
|
48
|
+
};
|
|
49
|
+
promise.done = (callback) => {
|
|
50
|
+
void promise.then(callback);
|
|
51
|
+
};
|
|
52
|
+
// If nothing is in progress, flush on the next microtask (never
|
|
53
|
+
// synchronously — RN callers rely on the async boundary).
|
|
54
|
+
queueMicrotask(flushIfIdle);
|
|
55
|
+
return promise;
|
|
56
|
+
},
|
|
57
|
+
createInteractionHandle() {
|
|
58
|
+
const handle = (handleCounter += 1);
|
|
59
|
+
const wasIdle = openHandles.size === 0;
|
|
60
|
+
openHandles.add(handle);
|
|
61
|
+
if (wasIdle) {
|
|
62
|
+
for (const listener of startListeners) {
|
|
63
|
+
listener();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return handle;
|
|
67
|
+
},
|
|
68
|
+
clearInteractionHandle(handle) {
|
|
69
|
+
if (!openHandles.delete(handle)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (openHandles.size === 0) {
|
|
73
|
+
for (const listener of completeListeners) {
|
|
74
|
+
listener();
|
|
75
|
+
}
|
|
76
|
+
// Defer the flush a microtask so a synchronous clear-then-create pair
|
|
77
|
+
// (a pop immediately followed by a push) does not flush in between.
|
|
78
|
+
queueMicrotask(flushIfIdle);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
addListener(event, listener) {
|
|
82
|
+
const set = event === "interactionStart" ? startListeners : completeListeners;
|
|
83
|
+
set.add(listener);
|
|
84
|
+
return { remove: () => set.delete(listener) };
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
// Test hook: reset the module state between cases.
|
|
88
|
+
export const resetInteractionManager = () => {
|
|
89
|
+
handleCounter = 0;
|
|
90
|
+
taskCounter = 0;
|
|
91
|
+
openHandles.clear();
|
|
92
|
+
pending = [];
|
|
93
|
+
startListeners.clear();
|
|
94
|
+
completeListeners.clear();
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=interaction-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction-manager.js","sourceRoot":"","sources":["../../src/apis/interaction-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// react-native InteractionManager. Long-running work (list rendering, data\n// crunching) scheduled through runAfterInteractions waits until no\n// \"interaction\" is in progress — on this platform an interaction is a\n// navigation transition (a stack push/pop slide). This keeps the animation\n// frames clear of competing work; the navigators bracket their transitions\n// with createInteractionHandle / clearInteractionHandle.\n//\n// Semantics mirror RN's: handles are reference-counted, tasks queue while\n// any handle is open and flush once the count returns to zero, and\n// runAfterInteractions returns a cancellable, then-able handle.\n\ntype Task = () => void\n\nlet handleCounter = 0\nconst openHandles = new Set<number>()\nlet pending: Array<{ id: number; run: Task }> = []\nlet taskCounter = 0\n\ntype InteractionListener = () => void\nconst startListeners = new Set<InteractionListener>()\nconst completeListeners = new Set<InteractionListener>()\n\nconst flushIfIdle = (): void => {\n if (openHandles.size > 0 || pending.length === 0) {\n return\n }\n const tasks = pending\n pending = []\n for (const task of tasks) {\n task.run()\n }\n}\n\nexport type InteractionPromise = Promise<void> & {\n cancel: () => void\n done: (callback: Task) => void\n}\n\nexport const InteractionManager = {\n // RN parity: a small pre-flush spacing so a burst of scheduling does not\n // starve the very frame the last interaction ended on. Kept minimal.\n runAfterInteractions(task?: Task): InteractionPromise {\n const id = (taskCounter += 1)\n let cancelled = false\n let settle: () => void = () => {}\n const promise = new Promise<void>((resolve) => {\n settle = resolve\n }) as InteractionPromise\n const run: Task = () => {\n if (cancelled) {\n return\n }\n task?.()\n settle()\n }\n pending.push({ id, run })\n promise.cancel = () => {\n cancelled = true\n pending = pending.filter((entry) => entry.id !== id)\n }\n promise.done = (callback: Task) => {\n void promise.then(callback)\n }\n // If nothing is in progress, flush on the next microtask (never\n // synchronously — RN callers rely on the async boundary).\n queueMicrotask(flushIfIdle)\n return promise\n },\n\n createInteractionHandle(): number {\n const handle = (handleCounter += 1)\n const wasIdle = openHandles.size === 0\n openHandles.add(handle)\n if (wasIdle) {\n for (const listener of startListeners) {\n listener()\n }\n }\n return handle\n },\n\n clearInteractionHandle(handle: number): void {\n if (!openHandles.delete(handle)) {\n return\n }\n if (openHandles.size === 0) {\n for (const listener of completeListeners) {\n listener()\n }\n // Defer the flush a microtask so a synchronous clear-then-create pair\n // (a pop immediately followed by a push) does not flush in between.\n queueMicrotask(flushIfIdle)\n }\n },\n\n addListener(\n event: \"interactionStart\" | \"interactionComplete\",\n listener: InteractionListener,\n ): { remove: () => void } {\n const set =\n event === \"interactionStart\" ? startListeners : completeListeners\n set.add(listener)\n return { remove: () => set.delete(listener) }\n },\n}\n\n// Test hook: reset the module state between cases.\nexport const resetInteractionManager = (): void => {\n handleCounter = 0\n taskCounter = 0\n openHandles.clear()\n pending = []\n startListeners.clear()\n completeListeners.clear()\n}\n"]}
|
package/dist/apis/linking.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import type { SubscriptionHandle } from "../contracts";
|
|
1
2
|
import type { LinkingHost } from "./host";
|
|
2
3
|
export declare const createLinking: (host: LinkingHost) => {
|
|
3
4
|
openURL: (url: string) => Promise<void>;
|
|
4
5
|
canOpenURL: (url: string) => Promise<boolean>;
|
|
5
6
|
getInitialURL: () => Promise<string | null>;
|
|
7
|
+
addEventListener: (type: "url", handler: (event: {
|
|
8
|
+
url: string;
|
|
9
|
+
}) => void) => SubscriptionHandle;
|
|
6
10
|
};
|
|
7
11
|
export type LinkingModule = ReturnType<typeof createLinking>;
|
package/dist/apis/linking.js
CHANGED
|
@@ -24,5 +24,14 @@ export const createLinking = (host) => ({
|
|
|
24
24
|
},
|
|
25
25
|
// Desktop apps are not launched through deep links: always null.
|
|
26
26
|
getInitialURL: () => Promise.resolve(null),
|
|
27
|
+
// RN parity for consumers that subscribe to incoming deep links
|
|
28
|
+
// (react-navigation's useLinking does on mount). Nothing delivers "url"
|
|
29
|
+
// events on desktop today — a future Gio.Application::open wiring would;
|
|
30
|
+
// the subscription contract is honored so such consumers mount cleanly.
|
|
31
|
+
addEventListener: (type, handler) => {
|
|
32
|
+
void type;
|
|
33
|
+
void handler;
|
|
34
|
+
return { remove: () => { } };
|
|
35
|
+
},
|
|
27
36
|
});
|
|
28
37
|
//# sourceMappingURL=linking.js.map
|
package/dist/apis/linking.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linking.js","sourceRoot":"","sources":["../../src/apis/linking.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"linking.js","sourceRoot":"","sources":["../../src/apis/linking.ts"],"names":[],"mappings":"AAGA,8EAA8E;AAC9E,wEAAwE;AACxE,8CAA8C;AAC9C,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;AAEtE,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAiB,EAAE;IAC9C,MAAM,KAAK,GAAG,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAChD,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;IACzB,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAA;AAC3D,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAiB,EAAE,EAAE,CAAC,CAAC;IACnD,0EAA0E;IAC1E,OAAO,EAAE,CAAC,GAAW,EAAiB,EAAE;QACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAC7D,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IACD,UAAU,EAAE,CAAC,GAAW,EAAoB,EAAE;QAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,OAAO,CAAC,MAAM,CACnB,IAAI,KAAK,CAAC,0CAA0C,CAAC,CACtD,CAAA;QACH,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;QAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,IAAI,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;IAC1E,CAAC;IACD,iEAAiE;IACjE,aAAa,EAAE,GAA2B,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;IAElE,gEAAgE;IAChE,wEAAwE;IACxE,yEAAyE;IACzE,wEAAwE;IACxE,gBAAgB,EAAE,CAChB,IAAW,EACX,OAAyC,EACrB,EAAE;QACtB,KAAK,IAAI,CAAA;QACT,KAAK,OAAO,CAAA;QACZ,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAA;IAC7B,CAAC;CACF,CAAC,CAAA","sourcesContent":["import type { SubscriptionHandle } from \"../contracts\"\nimport type { LinkingHost } from \"./host\"\n\n// Schemes every Linux desktop resolves through the portal / default handlers.\n// There is no per-handler introspection API comparable to canOpenURL on\n// mobile, so the answer is static per scheme.\nconst SUPPORTED_SCHEMES = new Set([\"http\", \"https\", \"mailto\", \"file\"])\n\nconst schemeOf = (url: string): string | null => {\n const match = /^([a-z][a-z0-9+.-]*):/i.exec(url)\n const scheme = match?.[1]\n return scheme === undefined ? null : scheme.toLowerCase()\n}\n\nexport const createLinking = (host: LinkingHost) => ({\n // Opens the URL in the user's default handler (Gtk.UriLauncher → portal).\n openURL: (url: string): Promise<void> => {\n if (typeof url !== \"string\" || url.length === 0) {\n return Promise.reject(\n new Error(\"Linking.openURL: url must be a non-empty string\"),\n )\n }\n return host.launchUri(url)\n },\n canOpenURL: (url: string): Promise<boolean> => {\n if (typeof url !== \"string\") {\n return Promise.reject(\n new Error(\"Linking.canOpenURL: url must be a string\"),\n )\n }\n const scheme = schemeOf(url)\n return Promise.resolve(scheme !== null && SUPPORTED_SCHEMES.has(scheme))\n },\n // Desktop apps are not launched through deep links: always null.\n getInitialURL: (): Promise<string | null> => Promise.resolve(null),\n\n // RN parity for consumers that subscribe to incoming deep links\n // (react-navigation's useLinking does on mount). Nothing delivers \"url\"\n // events on desktop today — a future Gio.Application::open wiring would;\n // the subscription contract is honored so such consumers mount cleanly.\n addEventListener: (\n type: \"url\",\n handler: (event: { url: string }) => void,\n ): SubscriptionHandle => {\n void type\n void handler\n return { remove: () => {} }\n },\n})\n\nexport type LinkingModule = ReturnType<typeof createLinking>\n"]}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type ComponentType } from "react";
|
|
2
2
|
type ComponentProvider = () => ComponentType<Record<string, unknown>>;
|
|
3
|
+
export declare const getActiveChrome: () => "system" | "content" | null;
|
|
3
4
|
export type RunApplicationParams = {
|
|
4
5
|
initialProps?: Record<string, unknown>;
|
|
5
6
|
title?: string;
|
|
6
7
|
width?: number;
|
|
7
8
|
height?: number;
|
|
9
|
+
chrome?: "system" | "content";
|
|
8
10
|
};
|
|
9
11
|
export declare const AppRegistry: {
|
|
10
12
|
registerComponent(appKey: string, provider: ComponentProvider): string;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useLayoutEffect } from "react";
|
|
3
|
-
import { createRoot, Gtk, GtkApplication, GtkApplicationWindow, quit, } from "../gtkx/bridge/index";
|
|
3
|
+
import { AdwApplicationWindow, createRoot, Gtk, GtkApplication, GtkApplicationWindow, quit, } from "../gtkx/bridge/index";
|
|
4
4
|
import { Root } from "./root";
|
|
5
5
|
const registry = new Map();
|
|
6
|
+
// The chrome the running app was started with — read by the navigation
|
|
7
|
+
// dev-mode hint (a HeaderBar page under "system" chrome renders a doubled
|
|
8
|
+
// titlebar). null until runApplication ran (test harnesses never set it).
|
|
9
|
+
let activeChrome = null;
|
|
10
|
+
export const getActiveChrome = () => activeChrome;
|
|
6
11
|
// RN parity: system "reduce animations" hints never auto-stop RN animations
|
|
7
12
|
// (ActivityIndicator keeps spinning; honoring reduce-motion is an explicit
|
|
8
13
|
// opt-in via AccessibilityInfo). Our Animated runs on GLib timers and already
|
|
@@ -24,6 +29,15 @@ const forceEnableAnimations = () => {
|
|
|
24
29
|
// later portal update cannot flip this back.
|
|
25
30
|
settings.gtkEnableAnimations = true;
|
|
26
31
|
};
|
|
32
|
+
// chrome "content": the app component IS the window content (a navigation
|
|
33
|
+
// container whose pages host their own NestedRoots) — no window-level Yoga
|
|
34
|
+
// root in between: the layout root would not allocate foreign GTK children.
|
|
35
|
+
const ContentChrome = ({ App, initialProps, }) => {
|
|
36
|
+
useLayoutEffect(() => {
|
|
37
|
+
forceEnableAnimations();
|
|
38
|
+
}, []);
|
|
39
|
+
return _jsx(App, { ...initialProps });
|
|
40
|
+
};
|
|
27
41
|
const WindowContent = ({ App, initialProps, initialWidth, initialHeight, }) => {
|
|
28
42
|
// Settings need an initialized display, and writing them mid-render is
|
|
29
43
|
// unsafe — apply after the window mounts.
|
|
@@ -54,7 +68,10 @@ export const AppRegistry = {
|
|
|
54
68
|
const App = provider();
|
|
55
69
|
const width = params.width ?? 800;
|
|
56
70
|
const height = params.height ?? 600;
|
|
57
|
-
const
|
|
71
|
+
const contentChrome = params.chrome === "content";
|
|
72
|
+
activeChrome = contentChrome ? "content" : "system";
|
|
73
|
+
const Window = contentChrome ? AdwApplicationWindow : GtkApplicationWindow;
|
|
74
|
+
const AppWindow = () => (_jsx(Window, { title: params.title ?? appKey, defaultWidth: width, defaultHeight: height, onCloseRequest: quit, children: contentChrome ? (_jsx(ContentChrome, { App: App, initialProps: params.initialProps ?? {} })) : (_jsx(WindowContent, { App: App, initialProps: params.initialProps ?? {}, initialWidth: width, initialHeight: height })) }));
|
|
58
75
|
createRoot().render(_jsx(GtkApplication, { children: _jsx(AppWindow, {}) }));
|
|
59
76
|
},
|
|
60
77
|
};
|