react-native-gtkx 0.3.0-alpha.1 → 0.4.0-alpha.2
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 +1 -1
- package/dist/adw/index.d.ts +3 -2
- package/dist/adw/index.js +21 -4
- package/dist/adw/index.js.map +1 -1
- package/dist/adw/widgets.generated.d.ts +1 -1
- package/dist/adw/widgets.generated.js +2 -2
- package/dist/adw/widgets.generated.js.map +1 -1
- package/dist/animated/create-animated.d.ts +2 -0
- package/dist/animated/create-animated.js +2 -0
- package/dist/animated/create-animated.js.map +1 -1
- package/dist/animated/event.d.ts +15 -0
- package/dist/animated/event.js +80 -0
- package/dist/animated/event.js.map +1 -0
- package/dist/animated/index.d.ts +4 -0
- package/dist/animated/index.js +8 -0
- package/dist/animated/index.js.map +1 -1
- package/dist/animated/spring.d.ts +10 -0
- package/dist/animated/spring.js +20 -6
- package/dist/animated/spring.js.map +1 -1
- package/dist/animated/timing.d.ts +10 -0
- package/dist/animated/timing.js +21 -13
- package/dist/animated/timing.js.map +1 -1
- package/dist/apis/host.gtkx.js +70 -11
- package/dist/apis/host.gtkx.js.map +1 -1
- package/dist/common/navigation-stack.d.ts +6 -3
- package/dist/common/navigation-stack.js +8 -1
- package/dist/common/navigation-stack.js.map +1 -1
- package/dist/common/widget.js +2 -11
- package/dist/common/widget.js.map +1 -1
- package/dist/components/animated.d.ts +1 -0
- package/dist/components/animated.js +28 -4
- package/dist/components/animated.js.map +1 -1
- package/dist/components/app-registry.js +32 -8
- package/dist/components/app-registry.js.map +1 -1
- package/dist/components/request-animation-frame.d.ts +33 -0
- package/dist/components/request-animation-frame.js +83 -0
- package/dist/components/request-animation-frame.js.map +1 -0
- package/dist/components/scroll-view.js +60 -2
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/virtualized-list.js +1 -4
- package/dist/components/virtualized-list.js.map +1 -1
- package/dist/dnd/autoscroll.d.ts +44 -0
- package/dist/dnd/autoscroll.js +176 -0
- package/dist/dnd/autoscroll.js.map +1 -0
- package/dist/dnd/grid-order.d.ts +45 -0
- package/dist/dnd/grid-order.js +151 -0
- package/dist/dnd/grid-order.js.map +1 -0
- package/dist/dnd/grid.d.ts +44 -0
- package/dist/dnd/grid.js +397 -0
- package/dist/dnd/grid.js.map +1 -0
- package/dist/dnd/gtk-controllers.d.ts +16 -2
- package/dist/dnd/gtk-controllers.js +23 -3
- package/dist/dnd/gtk-controllers.js.map +1 -1
- package/dist/dnd/index.d.ts +4 -2
- package/dist/dnd/index.js +9 -2
- package/dist/dnd/index.js.map +1 -1
- package/dist/dnd/order-state.d.ts +14 -0
- package/dist/dnd/order-state.js +55 -0
- package/dist/dnd/order-state.js.map +1 -0
- package/dist/dnd/order.d.ts +19 -0
- package/dist/dnd/order.js +19 -0
- package/dist/dnd/order.js.map +1 -1
- package/dist/dnd/sortable.d.ts +29 -4
- package/dist/dnd/sortable.js +308 -115
- package/dist/dnd/sortable.js.map +1 -1
- package/dist/dnd/types.d.ts +236 -14
- package/dist/dnd/types.js +30 -0
- package/dist/dnd/types.js.map +1 -1
- package/dist/gesture-handler-compat/attach-context.d.ts +29 -0
- package/dist/gesture-handler-compat/attach-context.js +90 -0
- package/dist/gesture-handler-compat/attach-context.js.map +1 -0
- package/dist/gesture-handler-compat/detector-runtime.d.ts +14 -3
- package/dist/gesture-handler-compat/detector-runtime.js +15 -5
- package/dist/gesture-handler-compat/detector-runtime.js.map +1 -1
- package/dist/gesture-handler-compat/detector.js +57 -2
- package/dist/gesture-handler-compat/detector.js.map +1 -1
- package/dist/gesture-handler-compat/gesture-state-manager.d.ts +5 -0
- package/dist/gesture-handler-compat/gesture-state-manager.js +77 -0
- package/dist/gesture-handler-compat/gesture-state-manager.js.map +1 -0
- package/dist/gesture-handler-compat/index.d.ts +2 -2
- package/dist/gesture-handler-compat/index.js +38 -33
- package/dist/gesture-handler-compat/index.js.map +1 -1
- package/dist/gesture-handler-compat/recognizer.d.ts +12 -1
- package/dist/gesture-handler-compat/recognizer.js +23 -9
- package/dist/gesture-handler-compat/recognizer.js.map +1 -1
- package/dist/gesture-handler-compat/tag-registry.d.ts +14 -0
- package/dist/gesture-handler-compat/tag-registry.js +19 -0
- package/dist/gesture-handler-compat/tag-registry.js.map +1 -0
- package/dist/globals/index.d.ts +47 -0
- package/dist/globals/index.js +181 -0
- package/dist/globals/index.js.map +1 -0
- package/dist/globals/install.d.ts +1 -0
- package/dist/globals/install.js +14 -0
- package/dist/globals/install.js.map +1 -0
- package/dist/gtkx/bridge/adw-namespace.d.ts +2 -0
- package/dist/gtkx/bridge/adw-namespace.js +26 -0
- package/dist/gtkx/bridge/adw-namespace.js.map +1 -0
- package/dist/gtkx/bridge/adw.d.ts +23 -0
- package/dist/gtkx/bridge/adw.js +93 -0
- package/dist/gtkx/bridge/adw.js.map +1 -0
- package/dist/gtkx/bridge/color-scheme-parse.d.ts +11 -0
- package/dist/gtkx/bridge/color-scheme-parse.js +42 -0
- package/dist/gtkx/bridge/color-scheme-parse.js.map +1 -0
- package/dist/gtkx/bridge/color-scheme-portal.d.ts +24 -0
- package/dist/gtkx/bridge/color-scheme-portal.js +172 -0
- package/dist/gtkx/bridge/color-scheme-portal.js.map +1 -0
- package/dist/gtkx/bridge/core.d.ts +25 -0
- package/dist/gtkx/bridge/core.js +69 -0
- package/dist/gtkx/bridge/core.js.map +1 -0
- package/dist/gtkx/bridge/drag-layer.d.ts +27 -0
- package/dist/gtkx/bridge/drag-layer.js +177 -0
- package/dist/gtkx/bridge/drag-layer.js.map +1 -0
- package/dist/gtkx/bridge/index.d.ts +1 -27
- package/dist/gtkx/bridge/index.js +12 -71
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/widgets.generated.adw.d.ts +1 -0
- package/dist/gtkx/bridge/widgets.generated.adw.js +16 -0
- package/dist/gtkx/bridge/widgets.generated.adw.js.map +1 -0
- package/dist/gtkx/bridge/widgets.generated.d.ts +0 -1
- package/dist/gtkx/bridge/widgets.generated.js +3 -3
- package/dist/gtkx/bridge/widgets.generated.js.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/data/generated.d.ts +41 -20
- package/dist/mcp/data/generated.js +46 -20
- package/dist/mcp/data/generated.js.map +1 -1
- package/dist/metro/index.d.ts +1 -0
- package/dist/metro/index.js +12 -0
- package/dist/metro/index.js.map +1 -1
- package/dist/navigation/sidebar.js +2 -45
- package/dist/navigation/sidebar.js.map +1 -1
- package/dist/reanimated-compat/animatable-value.d.ts +158 -0
- package/dist/reanimated-compat/animatable-value.js +316 -0
- package/dist/reanimated-compat/animatable-value.js.map +1 -0
- package/dist/reanimated-compat/animation.d.ts +34 -13
- package/dist/reanimated-compat/animation.js +97 -25
- package/dist/reanimated-compat/animation.js.map +1 -1
- package/dist/reanimated-compat/mutable.js +6 -6
- package/dist/reanimated-compat/mutable.js.map +1 -1
- package/dist/reanimated-compat/updater-animations.js +32 -12
- package/dist/reanimated-compat/updater-animations.js.map +1 -1
- package/dist/runner/host-dev.js +5 -1
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +9 -1
- package/dist/runner/host.js.map +1 -1
- package/dist/vite/index.js +130 -0
- package/dist/vite/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/gtkx/bridge/theme.d.ts +0 -4
- package/dist/gtkx/bridge/theme.js +0 -5
- package/dist/gtkx/bridge/theme.js.map +0 -1
package/dist/apis/host.gtkx.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
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 {
|
|
4
|
+
import { adwAvailable, colorScheme, requireAdwGi, styleManager, } from "../gtkx/bridge/adw";
|
|
5
|
+
import { getPlainColorScheme, onPlainColorSchemeChange, setPlainColorScheme, } from "../gtkx/bridge/color-scheme-portal";
|
|
6
|
+
import { Gdk, Gio, Gtk, quit, toNumber } from "../gtkx/bridge/index";
|
|
5
7
|
const FALLBACK_METRICS = {
|
|
6
8
|
width: 0,
|
|
7
9
|
height: 0,
|
|
@@ -223,26 +225,35 @@ const gtkVersion = () => `${toNumber(Gtk.getMajorVersion())}.${toNumber(Gtk.getM
|
|
|
223
225
|
// answers the setting with "unsupported ... use AdwStyleManager:color-scheme
|
|
224
226
|
// instead" and keeps its own value, so all the duplicate ever produced was a
|
|
225
227
|
// warning per call — seven per test run.
|
|
226
|
-
const
|
|
228
|
+
const setColorSchemeAdw = (scheme) => {
|
|
227
229
|
const manager = styleManager();
|
|
230
|
+
const { ColorScheme } = requireAdwGi("Appearance");
|
|
228
231
|
if (scheme === "dark") {
|
|
229
|
-
manager.setColorScheme(
|
|
232
|
+
manager.setColorScheme(ColorScheme.FORCE_DARK);
|
|
230
233
|
}
|
|
231
234
|
else if (scheme === "light") {
|
|
232
|
-
manager.setColorScheme(
|
|
235
|
+
manager.setColorScheme(ColorScheme.FORCE_LIGHT);
|
|
233
236
|
}
|
|
234
237
|
else {
|
|
235
|
-
manager.setColorScheme(
|
|
238
|
+
manager.setColorScheme(ColorScheme.DEFAULT);
|
|
236
239
|
}
|
|
237
240
|
};
|
|
238
|
-
const
|
|
241
|
+
const onColorSchemeChangeAdw = (notify) => {
|
|
239
242
|
const manager = styleManager();
|
|
240
243
|
const listener = () => notify();
|
|
241
244
|
manager.on("notify::dark", listener);
|
|
242
245
|
return { remove: () => manager.off("notify::dark", listener) };
|
|
243
246
|
};
|
|
244
|
-
|
|
245
|
-
|
|
247
|
+
// Without Adw-1 (adwAvailable() === false): the org.freedesktop.appearance
|
|
248
|
+
// portal, falling back to Gtk.Settings — see gtkx/bridge/color-scheme-portal.ts
|
|
249
|
+
// for the two-tier mechanism and .claude/epics/adw-optional/004.md for why.
|
|
250
|
+
const setColorScheme = (scheme) => adwAvailable() ? setColorSchemeAdw(scheme) : setPlainColorScheme(scheme);
|
|
251
|
+
const onColorSchemeChange = (notify) => adwAvailable()
|
|
252
|
+
? onColorSchemeChangeAdw(notify)
|
|
253
|
+
: onPlainColorSchemeChange(notify);
|
|
254
|
+
const showAlertAdw = async (request) => {
|
|
255
|
+
const { AlertDialog, ResponseAppearance } = requireAdwGi("Alert");
|
|
256
|
+
const dialog = new AlertDialog();
|
|
246
257
|
dialog.setHeading(request.title);
|
|
247
258
|
if (request.message !== undefined && request.message.length > 0) {
|
|
248
259
|
dialog.setBody(request.message);
|
|
@@ -251,10 +262,10 @@ const showAlert = async (request) => {
|
|
|
251
262
|
for (const button of request.buttons) {
|
|
252
263
|
dialog.addResponse(button.id, button.label);
|
|
253
264
|
if (button.style === "destructive") {
|
|
254
|
-
dialog.setResponseAppearance(button.id,
|
|
265
|
+
dialog.setResponseAppearance(button.id, ResponseAppearance.DESTRUCTIVE);
|
|
255
266
|
}
|
|
256
267
|
if (button.isPreferred) {
|
|
257
|
-
dialog.setResponseAppearance(button.id,
|
|
268
|
+
dialog.setResponseAppearance(button.id, ResponseAppearance.SUGGESTED);
|
|
258
269
|
dialog.setDefaultResponse(button.id);
|
|
259
270
|
}
|
|
260
271
|
if (button.style === "cancel") {
|
|
@@ -277,6 +288,54 @@ const showAlert = async (request) => {
|
|
|
277
288
|
? response
|
|
278
289
|
: null;
|
|
279
290
|
};
|
|
291
|
+
// Without Adw-1: Gtk.AlertDialog (GTK >= 4.10) — index-based rather than
|
|
292
|
+
// Adw's string response ids, so the button's position in request.buttons IS
|
|
293
|
+
// its Gtk.AlertDialog index; no id bookkeeping needed. What is LOST: Adw's
|
|
294
|
+
// ResponseAppearance (DESTRUCTIVE/SUGGESTED) has no Gtk.AlertDialog
|
|
295
|
+
// equivalent at all — every button renders the same, undocumented-away in
|
|
296
|
+
// docs/api.md's Alert row rather than silently dropped. Default/cancel
|
|
297
|
+
// mapping is preserved via defaultButton/cancelButton, same idea as Adw's
|
|
298
|
+
// defaultResponse/closeResponse above.
|
|
299
|
+
const showAlertPlain = async (request) => {
|
|
300
|
+
const dialog = new Gtk.AlertDialog({
|
|
301
|
+
message: request.title,
|
|
302
|
+
detail: request.message ?? "",
|
|
303
|
+
buttons: request.buttons.map((button) => button.label),
|
|
304
|
+
modal: true,
|
|
305
|
+
});
|
|
306
|
+
const preferredIndex = request.buttons.findIndex((button) => button.isPreferred);
|
|
307
|
+
if (preferredIndex >= 0) {
|
|
308
|
+
dialog.setDefaultButton(preferredIndex);
|
|
309
|
+
}
|
|
310
|
+
const cancelIndex = request.buttons.findIndex((button) => button.style === "cancel");
|
|
311
|
+
if (cancelIndex >= 0) {
|
|
312
|
+
// Esc maps onto the cancel button, same as the Adw path's closeResponse.
|
|
313
|
+
dialog.setCancelButton(cancelIndex);
|
|
314
|
+
}
|
|
315
|
+
else if (!request.cancelable && process.env.NODE_ENV !== "production") {
|
|
316
|
+
// Unlike Adw.AlertDialog.setCanClose(false), Gtk.AlertDialog has no way
|
|
317
|
+
// to block Esc/window-close dismissal outright — with no cancel button
|
|
318
|
+
// set, GTK closes the dialog anyway and rejects choose() with
|
|
319
|
+
// Gtk.DialogError.DISMISSED (caught below, mapped to the same null
|
|
320
|
+
// dismissal cancelable: true would produce). Documented in docs/api.md;
|
|
321
|
+
// an app that truly needs to block dismissal should add a cancel
|
|
322
|
+
// button on both profiles rather than relying on cancelable: false alone.
|
|
323
|
+
console.warn('[react-native-gtkx] Alert.alert was called with cancelable: false and no "cancel" ' +
|
|
324
|
+
"style button. The plain-GTK profile's Gtk.AlertDialog fallback cannot block " +
|
|
325
|
+
"Esc/window-close dismissal the way Adw.AlertDialog does — the dialog stays " +
|
|
326
|
+
"dismissable. Add a cancel-style button for identical behavior on both profiles.");
|
|
327
|
+
}
|
|
328
|
+
try {
|
|
329
|
+
const index = await dialog.choose(resolveWindow());
|
|
330
|
+
return request.buttons[index]?.id ?? null;
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Dismissed (Esc / window-close) with no valid cancel button — the
|
|
334
|
+
// plain-profile equivalent of the Adw path's unmatched "close" response.
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
const showAlert = async (request) => adwAvailable() ? showAlertAdw(request) : showAlertPlain(request);
|
|
280
339
|
const launchUri = async (uri) => {
|
|
281
340
|
const launcher = new Gtk.UriLauncher({ uri });
|
|
282
341
|
// Promisified by the gi codegen; rejects with the GError on failure.
|
|
@@ -296,7 +355,7 @@ export const gtkxHost = {
|
|
|
296
355
|
getWindowMetrics: windowMetrics,
|
|
297
356
|
getScreenMetrics: screenMetrics,
|
|
298
357
|
onMetricsChange: (notify) => watchWindow(WINDOW_SIZE_SIGNALS, SURFACE_SIZE_SIGNALS, notify),
|
|
299
|
-
getColorScheme: () => colorScheme(),
|
|
358
|
+
getColorScheme: () => adwAvailable() ? colorScheme() : getPlainColorScheme(),
|
|
300
359
|
setColorScheme,
|
|
301
360
|
onColorSchemeChange,
|
|
302
361
|
isActive: isAnyWindowActive,
|
|
@@ -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 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\n// AdwStyleManager is the only thing that decides the palette here, and it is\n// enough on its own — appearance.test.tsx asserts that a real widget's\n// computed foreground flips with it. This used to also write the classic\n// GtkSettings:gtk-application-prefer-dark-theme, guarding against Adwaita\n// not restyling a GtkApplication (we do not use AdwApplication). Under\n// libadwaita that write is inert: adw_init() takes the color scheme over,\n// answers the setting with \"unsupported ... use AdwStyleManager:color-scheme\n// instead\" and keeps its own value, so all the duplicate ever produced was a\n// warning per call — seven per test run.\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}\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"]}
|
|
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 adwAvailable,\n colorScheme,\n requireAdwGi,\n styleManager,\n} from \"../gtkx/bridge/adw\"\nimport {\n getPlainColorScheme,\n onPlainColorSchemeChange,\n setPlainColorScheme,\n} from \"../gtkx/bridge/color-scheme-portal\"\nimport { Gdk, Gio, Gtk, quit, toNumber } 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\n// AdwStyleManager is the only thing that decides the palette here, and it is\n// enough on its own — appearance.test.tsx asserts that a real widget's\n// computed foreground flips with it. This used to also write the classic\n// GtkSettings:gtk-application-prefer-dark-theme, guarding against Adwaita\n// not restyling a GtkApplication (we do not use AdwApplication). Under\n// libadwaita that write is inert: adw_init() takes the color scheme over,\n// answers the setting with \"unsupported ... use AdwStyleManager:color-scheme\n// instead\" and keeps its own value, so all the duplicate ever produced was a\n// warning per call — seven per test run.\nconst setColorSchemeAdw = (scheme: ColorSchemeName | null): void => {\n const manager = styleManager()\n const { ColorScheme } = requireAdwGi(\"Appearance\")\n if (scheme === \"dark\") {\n manager.setColorScheme(ColorScheme.FORCE_DARK)\n } else if (scheme === \"light\") {\n manager.setColorScheme(ColorScheme.FORCE_LIGHT)\n } else {\n manager.setColorScheme(ColorScheme.DEFAULT)\n }\n}\n\nconst onColorSchemeChangeAdw = (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\n// Without Adw-1 (adwAvailable() === false): the org.freedesktop.appearance\n// portal, falling back to Gtk.Settings — see gtkx/bridge/color-scheme-portal.ts\n// for the two-tier mechanism and .claude/epics/adw-optional/004.md for why.\nconst setColorScheme = (scheme: ColorSchemeName | null): void =>\n adwAvailable() ? setColorSchemeAdw(scheme) : setPlainColorScheme(scheme)\n\nconst onColorSchemeChange = (notify: () => void): SubscriptionHandle =>\n adwAvailable()\n ? onColorSchemeChangeAdw(notify)\n : onPlainColorSchemeChange(notify)\n\nconst showAlertAdw = async (\n request: HostAlertRequest,\n): Promise<string | null> => {\n const { AlertDialog, ResponseAppearance } = requireAdwGi(\"Alert\")\n const dialog = new 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(button.id, ResponseAppearance.DESTRUCTIVE)\n }\n if (button.isPreferred) {\n dialog.setResponseAppearance(button.id, 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\n// Without Adw-1: Gtk.AlertDialog (GTK >= 4.10) — index-based rather than\n// Adw's string response ids, so the button's position in request.buttons IS\n// its Gtk.AlertDialog index; no id bookkeeping needed. What is LOST: Adw's\n// ResponseAppearance (DESTRUCTIVE/SUGGESTED) has no Gtk.AlertDialog\n// equivalent at all — every button renders the same, undocumented-away in\n// docs/api.md's Alert row rather than silently dropped. Default/cancel\n// mapping is preserved via defaultButton/cancelButton, same idea as Adw's\n// defaultResponse/closeResponse above.\nconst showAlertPlain = async (\n request: HostAlertRequest,\n): Promise<string | null> => {\n const dialog = new Gtk.AlertDialog({\n message: request.title,\n detail: request.message ?? \"\",\n buttons: request.buttons.map((button) => button.label),\n modal: true,\n })\n const preferredIndex = request.buttons.findIndex(\n (button) => button.isPreferred,\n )\n if (preferredIndex >= 0) {\n dialog.setDefaultButton(preferredIndex)\n }\n const cancelIndex = request.buttons.findIndex(\n (button) => button.style === \"cancel\",\n )\n if (cancelIndex >= 0) {\n // Esc maps onto the cancel button, same as the Adw path's closeResponse.\n dialog.setCancelButton(cancelIndex)\n } else if (!request.cancelable && process.env.NODE_ENV !== \"production\") {\n // Unlike Adw.AlertDialog.setCanClose(false), Gtk.AlertDialog has no way\n // to block Esc/window-close dismissal outright — with no cancel button\n // set, GTK closes the dialog anyway and rejects choose() with\n // Gtk.DialogError.DISMISSED (caught below, mapped to the same null\n // dismissal cancelable: true would produce). Documented in docs/api.md;\n // an app that truly needs to block dismissal should add a cancel\n // button on both profiles rather than relying on cancelable: false alone.\n console.warn(\n '[react-native-gtkx] Alert.alert was called with cancelable: false and no \"cancel\" ' +\n \"style button. The plain-GTK profile's Gtk.AlertDialog fallback cannot block \" +\n \"Esc/window-close dismissal the way Adw.AlertDialog does — the dialog stays \" +\n \"dismissable. Add a cancel-style button for identical behavior on both profiles.\",\n )\n }\n try {\n const index = await dialog.choose(resolveWindow())\n return request.buttons[index]?.id ?? null\n } catch {\n // Dismissed (Esc / window-close) with no valid cancel button — the\n // plain-profile equivalent of the Adw path's unmatched \"close\" response.\n return null\n }\n}\n\nconst showAlert = async (request: HostAlertRequest): Promise<string | null> =>\n adwAvailable() ? showAlertAdw(request) : showAlertPlain(request)\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: () =>\n adwAvailable() ? colorScheme() : getPlainColorScheme(),\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"]}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type ComponentProps, type ReactNode, type Ref } from "react";
|
|
2
|
-
import {
|
|
3
|
-
type
|
|
2
|
+
import { requireAdwJsx, type Adw } from "../gtkx/bridge/adw";
|
|
3
|
+
type AdwJsxModule = ReturnType<typeof requireAdwJsx>;
|
|
4
|
+
type RawAdwNavigationPageComponent = AdwJsxModule["AdwNavigationPage"];
|
|
5
|
+
type RawAdwNavigationViewComponent = AdwJsxModule["AdwNavigationView"];
|
|
6
|
+
type AdwPageProps = ComponentProps<RawAdwNavigationPageComponent>;
|
|
4
7
|
export type NavigationStackPageProps = AdwPageProps & {
|
|
5
8
|
/** Stable identity of this page inside the view. Required: the whole sync
|
|
6
9
|
* protocol is expressed in tags, and Adwaita itself pushes and pops by
|
|
@@ -15,7 +18,7 @@ export type NavigationStackPageProps = AdwPageProps & {
|
|
|
15
18
|
* deliberately does not guess, so raw GTK children keep working.
|
|
16
19
|
*/
|
|
17
20
|
export declare const NavigationStackPage: ({ tag, onHidden, onShown, ...rest }: NavigationStackPageProps) => React.JSX.Element;
|
|
18
|
-
type AdwViewProps = ComponentProps<
|
|
21
|
+
type AdwViewProps = ComponentProps<RawAdwNavigationViewComponent>;
|
|
19
22
|
export type NavigationStackProps = Omit<AdwViewProps, "onPopped" | "ref"> & {
|
|
20
23
|
/**
|
|
21
24
|
* The visible stack, root first, as page tags. Change it and the widget
|
|
@@ -28,7 +28,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
28
28
|
// mechanism — see beginTransition below.
|
|
29
29
|
import { Children, createContext, isValidElement, useCallback, useContext, useEffect, useInsertionEffect, useRef, useState, } from "react";
|
|
30
30
|
import { InteractionManager } from "../apis/interaction-manager";
|
|
31
|
-
import {
|
|
31
|
+
import { requireAdwJsx } from "../gtkx/bridge/adw";
|
|
32
32
|
/** A conservative fallback window for the two cases described above, where
|
|
33
33
|
* no real per-page signal ever arrives for this specific transition. This
|
|
34
34
|
* is NOT a measurement of Adwaita's actual transition length — an earlier
|
|
@@ -48,6 +48,11 @@ const PageLifecycleContext = createContext(null);
|
|
|
48
48
|
* deliberately does not guess, so raw GTK children keep working.
|
|
49
49
|
*/
|
|
50
50
|
export const NavigationStackPage = ({ tag, onHidden, onShown, ...rest }) => {
|
|
51
|
+
// Called on every render rather than memoized: requireAdwJsx() itself is
|
|
52
|
+
// memoized (see gtkx/bridge/adw.ts), so this is a cheap cache read once
|
|
53
|
+
// Adw has resolved, and the loud throw on the FIRST render is exactly the
|
|
54
|
+
// point when it has not.
|
|
55
|
+
const { AdwNavigationPage: RawAdwNavigationPage } = requireAdwJsx("NavigationStackPage");
|
|
51
56
|
const lifecycle = useContext(PageLifecycleContext);
|
|
52
57
|
const handleHidden = ((...args) => {
|
|
53
58
|
lifecycle?.reportHidden(tag);
|
|
@@ -78,6 +83,8 @@ export const NavigationStackPage = ({ tag, onHidden, onShown, ...rest }) => {
|
|
|
78
83
|
* component to back `createStackNavigator`.
|
|
79
84
|
*/
|
|
80
85
|
export const NavigationStack = ({ stack, children, onPopped, onPageClosed, onTransitionStart, onTransitionEnd, transitionDuration = DEFAULT_TRANSITION_MS, ref, ...rest }) => {
|
|
86
|
+
// See NavigationStackPage above — lazy for the same reason.
|
|
87
|
+
const { AdwNavigationView: RawAdwNavigationView } = requireAdwJsx("NavigationStack");
|
|
81
88
|
const viewRef = useRef(null);
|
|
82
89
|
// Mirror of the widget's visible stack. Maintained by the sync effect and
|
|
83
90
|
// by the popped handler; the two never race, because GTK signals run
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation-stack.js","sourceRoot":"","sources":["../../src/common/navigation-stack.tsx"],"names":[],"mappings":"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","sourcesContent":["// react-native-gtkx/adwaita — Adw.NavigationView as a declarative primitive.\n//\n// This layer knows NOTHING about react-navigation. You hand it the ordered\n// stack of page tags you want visible, it animates the widget to that stack\n// and tells you when the WIDGET popped on its own (back button, Escape, the\n// back gesture). Bring react-navigation, bring your own router, or drive it\n// from useState — the primitive does not care.\n//\n// react-native-gtkx/navigation is a thin adapter on top of this file, the\n// same way @react-navigation/native-stack sits on top of react-native-screens.\n//\n// Why the primitive owns retention: react-navigation (and any router) drops a\n// popped route immediately, while Adwaita still animates the page out. If the\n// consumer had to keep rendering pages it already considers gone, every\n// consumer would reimplement that bookkeeping and the primitive would be\n// useless without a router. So NavigationView snapshots a page when it\n// leaves `stack` and drops it on the page's \"hidden\" signal — the real\n// AdwNavigationPage signal, not a guess — with `transitionDuration` as a\n// fallback timer for two cases where the signal never arrives on its own:\n// environments that never deliver it at all (headless compositors with\n// animations disabled), and a page skipped entirely by a multi-hop pop\n// (measured on the rig: `popToTag` from [a,b,c] to \"a\" fires hiding/hidden\n// only on \"c\", the page that was actually visible — \"b\" gets no signal at\n// all, on any environment, because it was never itself on screen during the\n// transition). onTransitionStart/onTransitionEnd and the InteractionManager\n// bracket around them use the exact same real-signal-first, timer-fallback\n// mechanism — see beginTransition below.\nimport {\n Children,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useInsertionEffect,\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\"\nimport { InteractionManager } from \"../apis/interaction-manager\"\nimport {\n AdwNavigationPage as RawAdwNavigationPage,\n AdwNavigationView as RawAdwNavigationView,\n type Adw,\n} from \"../gtkx/bridge/index\"\n\n/** A conservative fallback window for the two cases described above, where\n * no real per-page signal ever arrives for this specific transition. This\n * is NOT a measurement of Adwaita's actual transition length — an earlier\n * version of this comment claimed \"~200 ms measured\", which was never\n * actually measured (found while auditing this file). On the project's own\n * headless GTK test rig the real signal always arrives, and in well under\n * a millisecond, so there is no rig measurement to cite either; this\n * number is simply a deliberately generous upper bound. Overridable\n * because a consumer may want a shorter/longer safety margin. */\nconst DEFAULT_TRANSITION_MS = 400\n\ntype PageLifecycle = {\n reportHidden: (tag: string) => void\n reportShown: (tag: string) => void\n}\n\nconst PageLifecycleContext = createContext<PageLifecycle | null>(null)\n\n// Every prop Adw.NavigationPage exposes flows through untouched, so anything\n// gtkx binds today (and anything it binds tomorrow) is reachable without a\n// change here. Only `onHidden` is intercepted, and it is still forwarded.\ntype AdwPageProps = ComponentProps<typeof RawAdwNavigationPage>\n\nexport type NavigationStackPageProps = AdwPageProps & {\n /** Stable identity of this page inside the view. Required: the whole sync\n * protocol is expressed in tags, and Adwaita itself pushes and pops by\n * tag. Use the same string you put in NavigationView's `stack`. */\n tag: string\n}\n\n/**\n * One page of an {@link NavigationStack}.\n *\n * Children are passed to the widget untouched. To put React Native content\n * inside a page, wrap it in `SlotContent` (see ./content) — the primitive\n * deliberately does not guess, so raw GTK children keep working.\n */\nexport const NavigationStackPage = ({\n tag,\n onHidden,\n onShown,\n ...rest\n}: NavigationStackPageProps) => {\n const lifecycle = useContext(PageLifecycleContext)\n const handleHidden = ((...args: unknown[]) => {\n lifecycle?.reportHidden(tag)\n // The consumer's own handler still runs, and runs second: retention\n // bookkeeping must not depend on what the consumer does here.\n ;(onHidden as ((...a: unknown[]) => void) | undefined)?.(...args)\n }) as AdwPageProps[\"onHidden\"]\n const handleShown = ((...args: unknown[]) => {\n lifecycle?.reportShown(tag)\n // Same ordering guarantee as onHidden above.\n ;(onShown as ((...a: unknown[]) => void) | undefined)?.(...args)\n }) as AdwPageProps[\"onShown\"]\n return (\n <RawAdwNavigationPage\n {...rest}\n tag={tag}\n onHidden={handleHidden}\n onShown={handleShown}\n />\n )\n}\n\ntype AdwViewProps = ComponentProps<typeof RawAdwNavigationView>\n\nexport type NavigationStackProps = Omit<AdwViewProps, \"onPopped\" | \"ref\"> & {\n /**\n * The visible stack, root first, as page tags. Change it and the widget\n * animates to match: appended tags push, removed tags pop, a changed root\n * replaces the whole stack.\n */\n stack: readonly string[]\n /** `NavigationStackPage` elements. Pages not in `stack` are still accepted —\n * they simply are not shown — so a router may render all of its screens. */\n children?: ReactNode\n /**\n * Whether push/pop/replace transitions animate at all, forwarded straight\n * to `Adw.NavigationView`'s own `animate-transitions` property (already\n * reachable through this component's inherited `Adw.NavigationView` props —\n * spelled out here because it is the one prop consumers most often go\n * looking for). GTK has exactly one transition style; there is no per-style\n * choice to make here, only whether it plays. Default true, matching the\n * widget's own default. Interactive swipe-back gestures always animate\n * regardless of this value — that is Adwaita's own behavior, not this\n * primitive's.\n */\n animateTransitions?: boolean\n /**\n * The widget popped a page by itself: the Adwaita back button, Escape, the\n * back gesture, or the back-history menu. NOT called for pops you caused by\n * changing `stack`. This is where a router follows the view.\n */\n onPopped?: (tag: string) => void\n /** A closing page finished animating out and was dropped from the tree. */\n onPageClosed?: (tag: string) => void\n /** A push/pop/replace transition started. */\n onTransitionStart?: () => void\n /** …and finished. Driven by the transitioning page's own real\n * `shown`/`hidden` AdwNavigationPage signal (whichever settles it —\n * see beginTransition), with `transitionDuration` as a fallback for the\n * cases where neither arrives. */\n onTransitionEnd?: () => void\n /** Fallback window in ms, used only when a page's own transition signal\n * never arrives (see the file header comment for the two cases this\n * covers) — for page retention and for the transition callbacks above.\n * NOT a measurement of the real transition length. Default 400. */\n transitionDuration?: number\n /** Escape hatch: the underlying Adw.NavigationView, for anything this\n * primitive does not model. */\n ref?: Ref<Adw.NavigationView | null>\n}\n\n/**\n * `Adw.NavigationView` driven declaratively.\n *\n * ```tsx\n * const [stack, setStack] = useState([\"home\"])\n *\n * <NavigationStack\n * stack={stack}\n * onPopped={(tag) => setStack((s) => s.filter((t) => t !== tag))}\n * >\n * <NavigationStackPage tag=\"home\" title=\"Home\">…</NavigationStackPage>\n * <NavigationStackPage tag=\"detail\" title=\"Detail\">…</NavigationStackPage>\n * </NavigationStack>\n * ```\n *\n * No router required. `react-native-gtkx/navigation` uses exactly this\n * component to back `createStackNavigator`.\n */\nexport const NavigationStack = ({\n stack,\n children,\n onPopped,\n onPageClosed,\n onTransitionStart,\n onTransitionEnd,\n transitionDuration = DEFAULT_TRANSITION_MS,\n ref,\n ...rest\n}: NavigationStackProps) => {\n const viewRef = useRef<Adw.NavigationView | null>(null)\n // Mirror of the widget's visible stack. Maintained by the sync effect and\n // by the popped handler; the two never race, because GTK signals run\n // synchronously inside the very push/pop calls the effect makes.\n const syncedRef = useRef<string[]>([])\n\n const pagesByTag = new Map<string, ReactNode>()\n for (const child of Children.toArray(children)) {\n if (isValidElement<{ tag?: unknown }>(child)) {\n const tag = child.props.tag\n if (typeof tag === \"string\") {\n pagesByTag.set(tag, child)\n }\n }\n }\n\n // Pages currently in the tree: everything in `stack`, plus pages that left\n // it and are still animating out.\n const [renderedTags, setRenderedTags] = useState<string[]>(() => [...stack])\n const missing = stack.filter((tag) => !renderedTags.includes(tag))\n if (missing.length > 0) {\n // The sanctioned derive-state-during-render pattern: a new page must be\n // in the tree within the same commit the sync effect pushes it.\n setRenderedTags([...renderedTags, ...missing])\n }\n\n // A state-held stable Map rather than a ref: the render path reads it for\n // closing pages, and reading a ref during render is rightly banned.\n const [snapshots] = useState(() => new Map<string, ReactNode>())\n useEffect(() => {\n for (const [tag, element] of pagesByTag) {\n snapshots.set(tag, element)\n }\n })\n\n const dropPage = useCallback(\n (tag: string): void => {\n let dropped = false\n setRenderedTags((tags) => {\n if (!tags.includes(tag)) {\n return tags\n }\n dropped = true\n return tags.filter((rendered) => rendered !== tag)\n })\n if (dropped) {\n snapshots.delete(tag)\n onPageClosed?.(tag)\n }\n },\n [onPageClosed, snapshots],\n )\n\n // Signal handlers read the CURRENT requested stack, not the one captured\n // when they were created. Refreshed in an insertion effect (the project's\n // standard escape from writing refs during render): insertion effects run\n // before layout effects, so the value is fresh by the time GTK can emit.\n const stackRef = useRef<readonly string[]>(stack)\n useInsertionEffect(() => {\n stackRef.current = stack\n })\n\n // Per-tag waiters for \"this specific page's transition settled\" — fed by\n // reportHidden/reportShown below, drained (and deleted) the moment either\n // fires. A page can end up \"shown\" after being \"hiding\" (an interrupted\n // pop reversed) or \"hidden\" after being \"showing\" (an interrupted push\n // superseded) — GObject-introspection documents both pairings — so a\n // waiter for a given tag resolves on WHICHEVER of the two settles it,\n // not just the one that would be expected in the common case.\n const transitionWaitersRef = useRef<Map<string, Array<() => void>>>(new Map())\n\n const addTransitionWaiter = useCallback(\n (tag: string, resolve: () => void): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (waiters) {\n waiters.push(resolve)\n } else {\n transitionWaitersRef.current.set(tag, [resolve])\n }\n },\n [],\n )\n\n const removeTransitionWaiter = useCallback(\n (tag: string, resolve: () => void): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (!waiters) {\n return\n }\n const next = waiters.filter((waiter) => waiter !== resolve)\n if (next.length > 0) {\n transitionWaitersRef.current.set(tag, next)\n } else {\n transitionWaitersRef.current.delete(tag)\n }\n },\n [],\n )\n\n const resolveTransitionWaiters = useCallback((tag: string): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (!waiters) {\n return\n }\n transitionWaitersRef.current.delete(tag)\n for (const resolve of waiters) {\n resolve()\n }\n }, [])\n\n const reportHidden = useCallback(\n (tag: string): void => {\n resolveTransitionWaiters(tag)\n // \"hidden\" also fires for a live page covered by a push — only pages\n // gone from the requested stack are actually closing.\n if (stackRef.current.includes(tag)) {\n return\n }\n dropPage(tag)\n },\n [dropPage, resolveTransitionWaiters],\n )\n\n const reportShown = useCallback(\n (tag: string): void => {\n resolveTransitionWaiters(tag)\n },\n [resolveTransitionWaiters],\n )\n\n // Delivery of \"hidden\" is not guaranteed — see the file header comment for\n // the two cases (a genuinely signal-less environment, and a page skipped\n // over by a multi-hop pop) — so a timer slightly longer than the fallback\n // window is the backstop. dropPage is idempotent: whichever wins, wins.\n const scheduleDrop = useCallback(\n (tag: string): void => {\n setTimeout(() => reportHidden(tag), transitionDuration)\n },\n [reportHidden, transitionDuration],\n )\n\n // Bracket every transition with an InteractionManager handle so\n // runAfterInteractions work (a screen's data load, a heavy render) waits\n // for the slide instead of stealing its frames, closing it and firing\n // onTransitionEnd exactly when the transition really settles: the real\n // \"shown\"/\"hidden\" signal on `targetTag` (the page this specific push,\n // popToTag or replaceWithTags call is bringing into view) if it arrives,\n // `transitionDuration` otherwise. `targetTag` is undefined only for\n // replaceWithTags([]) — no page becomes visible, nothing to wait on, the\n // timer alone settles it. Overlapping transitions reference-count through\n // the handle API.\n const beginTransition = useCallback(\n (targetTag: string | undefined): void => {\n const handle = InteractionManager.createInteractionHandle()\n onTransitionStart?.()\n let settled = false\n const settle = (): void => {\n if (settled) {\n return\n }\n settled = true\n InteractionManager.clearInteractionHandle(handle)\n onTransitionEnd?.()\n }\n if (targetTag !== undefined) {\n addTransitionWaiter(targetTag, settle)\n }\n setTimeout(() => {\n if (targetTag !== undefined) {\n removeTransitionWaiter(targetTag, settle)\n }\n settle()\n }, transitionDuration)\n },\n [\n addTransitionWaiter,\n removeTransitionWaiter,\n onTransitionEnd,\n onTransitionStart,\n transitionDuration,\n ],\n )\n\n useEffect(() => {\n const view = viewRef.current\n if (!view) {\n return\n }\n const target = [...stack]\n if (syncedRef.current.length === 0 && target.length > 0) {\n // First mount: NavigationView shows the first added page by itself.\n syncedRef.current = target.slice(0, 1)\n }\n let common = 0\n while (\n common < syncedRef.current.length &&\n common < target.length &&\n syncedRef.current[common] === target[common]\n ) {\n common += 1\n }\n if (common === 0 && syncedRef.current[0] !== target[0]) {\n // The root changed (a reset): swap the whole visible stack. The last\n // tag becomes the visible page (undefined only when target is empty —\n // see beginTransition's targetTag doc above).\n const leaving = syncedRef.current.filter((tag) => !target.includes(tag))\n syncedRef.current = [...target]\n beginTransition(target[target.length - 1])\n view.replaceWithTags(target)\n for (const tag of leaving) {\n scheduleDrop(tag)\n }\n return\n }\n if (syncedRef.current.length > common) {\n const anchor = target[common - 1]\n const leaving = syncedRef.current.slice(common)\n syncedRef.current = syncedRef.current.slice(0, common)\n if (anchor !== undefined) {\n beginTransition(anchor)\n view.popToTag(anchor)\n }\n for (const tag of leaving) {\n scheduleDrop(tag)\n }\n }\n for (\n let index = syncedRef.current.length;\n index < target.length;\n index += 1\n ) {\n const tag = target[index]!\n syncedRef.current.push(tag)\n beginTransition(tag)\n view.pushByTag(tag)\n }\n }, [stack, scheduleDrop, beginTransition])\n\n const handlePopped = (page: Adw.NavigationPage | null): void => {\n const tag = page?.getTag()\n if (!tag) {\n return\n }\n syncedRef.current = syncedRef.current.filter((synced) => synced !== tag)\n // Reported unconditionally: the consumer decides whether this pop was\n // one it already knows about. The primitive has no router state to\n // consult, and guessing here is exactly what would couple the layers.\n onPopped?.(tag)\n scheduleDrop(tag)\n }\n\n // The context value must be identity-stable (every page reads it), so the\n // live handlers are reached through refs rather than baked into the value.\n const reportHiddenRef = useRef<(tag: string) => void>(reportHidden)\n const reportShownRef = useRef<(tag: string) => void>(reportShown)\n useInsertionEffect(() => {\n reportHiddenRef.current = reportHidden\n reportShownRef.current = reportShown\n })\n const [lifecycle] = useState<PageLifecycle>(() => ({\n reportHidden: (tag: string) => reportHiddenRef.current(tag),\n reportShown: (tag: string) => reportShownRef.current(tag),\n }))\n\n return (\n <PageLifecycleContext.Provider value={lifecycle}>\n <RawAdwNavigationView\n {...rest}\n ref={(instance: Adw.NavigationView | null) => {\n viewRef.current = instance\n if (typeof ref === \"function\") {\n ref(instance)\n } else if (ref) {\n ref.current = instance\n }\n }}\n onPopped={(page: Adw.NavigationPage | null) => handlePopped(page)}\n >\n {renderedTags.map(\n (tag) => pagesByTag.get(tag) ?? snapshots.get(tag) ?? null,\n )}\n </RawAdwNavigationView>\n </PageLifecycleContext.Provider>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"navigation-stack.js","sourceRoot":"","sources":["../../src/common/navigation-stack.tsx"],"names":[],"mappings":"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","sourcesContent":["// react-native-gtkx/adwaita — Adw.NavigationView as a declarative primitive.\n//\n// This layer knows NOTHING about react-navigation. You hand it the ordered\n// stack of page tags you want visible, it animates the widget to that stack\n// and tells you when the WIDGET popped on its own (back button, Escape, the\n// back gesture). Bring react-navigation, bring your own router, or drive it\n// from useState — the primitive does not care.\n//\n// react-native-gtkx/navigation is a thin adapter on top of this file, the\n// same way @react-navigation/native-stack sits on top of react-native-screens.\n//\n// Why the primitive owns retention: react-navigation (and any router) drops a\n// popped route immediately, while Adwaita still animates the page out. If the\n// consumer had to keep rendering pages it already considers gone, every\n// consumer would reimplement that bookkeeping and the primitive would be\n// useless without a router. So NavigationView snapshots a page when it\n// leaves `stack` and drops it on the page's \"hidden\" signal — the real\n// AdwNavigationPage signal, not a guess — with `transitionDuration` as a\n// fallback timer for two cases where the signal never arrives on its own:\n// environments that never deliver it at all (headless compositors with\n// animations disabled), and a page skipped entirely by a multi-hop pop\n// (measured on the rig: `popToTag` from [a,b,c] to \"a\" fires hiding/hidden\n// only on \"c\", the page that was actually visible — \"b\" gets no signal at\n// all, on any environment, because it was never itself on screen during the\n// transition). onTransitionStart/onTransitionEnd and the InteractionManager\n// bracket around them use the exact same real-signal-first, timer-fallback\n// mechanism — see beginTransition below.\nimport {\n Children,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useInsertionEffect,\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\"\nimport { InteractionManager } from \"../apis/interaction-manager\"\nimport { requireAdwJsx, type Adw } from \"../gtkx/bridge/adw\"\n\n// Types only — requireAdwJsx() itself is called lazily, inside each\n// component below, not at module scope: this file lives under\n// react-native-gtkx/common, whose barrel ALSO exports Adw-free helpers\n// (Widget, Icon, SlotContent — see ./index.ts), so importing e.g. Widget\n// alone must not force Adw-1 to exist. Rendering NavigationStack (or\n// NavigationStackPage) without it is what throws the named error — see\n// .claude/epics/adw-optional/001.md.\ntype AdwJsxModule = ReturnType<typeof requireAdwJsx>\ntype RawAdwNavigationPageComponent = AdwJsxModule[\"AdwNavigationPage\"]\ntype RawAdwNavigationViewComponent = AdwJsxModule[\"AdwNavigationView\"]\n\n/** A conservative fallback window for the two cases described above, where\n * no real per-page signal ever arrives for this specific transition. This\n * is NOT a measurement of Adwaita's actual transition length — an earlier\n * version of this comment claimed \"~200 ms measured\", which was never\n * actually measured (found while auditing this file). On the project's own\n * headless GTK test rig the real signal always arrives, and in well under\n * a millisecond, so there is no rig measurement to cite either; this\n * number is simply a deliberately generous upper bound. Overridable\n * because a consumer may want a shorter/longer safety margin. */\nconst DEFAULT_TRANSITION_MS = 400\n\ntype PageLifecycle = {\n reportHidden: (tag: string) => void\n reportShown: (tag: string) => void\n}\n\nconst PageLifecycleContext = createContext<PageLifecycle | null>(null)\n\n// Every prop Adw.NavigationPage exposes flows through untouched, so anything\n// gtkx binds today (and anything it binds tomorrow) is reachable without a\n// change here. Only `onHidden` is intercepted, and it is still forwarded.\ntype AdwPageProps = ComponentProps<RawAdwNavigationPageComponent>\n\nexport type NavigationStackPageProps = AdwPageProps & {\n /** Stable identity of this page inside the view. Required: the whole sync\n * protocol is expressed in tags, and Adwaita itself pushes and pops by\n * tag. Use the same string you put in NavigationView's `stack`. */\n tag: string\n}\n\n/**\n * One page of an {@link NavigationStack}.\n *\n * Children are passed to the widget untouched. To put React Native content\n * inside a page, wrap it in `SlotContent` (see ./content) — the primitive\n * deliberately does not guess, so raw GTK children keep working.\n */\nexport const NavigationStackPage = ({\n tag,\n onHidden,\n onShown,\n ...rest\n}: NavigationStackPageProps) => {\n // Called on every render rather than memoized: requireAdwJsx() itself is\n // memoized (see gtkx/bridge/adw.ts), so this is a cheap cache read once\n // Adw has resolved, and the loud throw on the FIRST render is exactly the\n // point when it has not.\n const { AdwNavigationPage: RawAdwNavigationPage } = requireAdwJsx(\n \"NavigationStackPage\",\n )\n const lifecycle = useContext(PageLifecycleContext)\n const handleHidden = ((...args: unknown[]) => {\n lifecycle?.reportHidden(tag)\n // The consumer's own handler still runs, and runs second: retention\n // bookkeeping must not depend on what the consumer does here.\n ;(onHidden as ((...a: unknown[]) => void) | undefined)?.(...args)\n }) as AdwPageProps[\"onHidden\"]\n const handleShown = ((...args: unknown[]) => {\n lifecycle?.reportShown(tag)\n // Same ordering guarantee as onHidden above.\n ;(onShown as ((...a: unknown[]) => void) | undefined)?.(...args)\n }) as AdwPageProps[\"onShown\"]\n return (\n <RawAdwNavigationPage\n {...rest}\n tag={tag}\n onHidden={handleHidden}\n onShown={handleShown}\n />\n )\n}\n\ntype AdwViewProps = ComponentProps<RawAdwNavigationViewComponent>\n\nexport type NavigationStackProps = Omit<AdwViewProps, \"onPopped\" | \"ref\"> & {\n /**\n * The visible stack, root first, as page tags. Change it and the widget\n * animates to match: appended tags push, removed tags pop, a changed root\n * replaces the whole stack.\n */\n stack: readonly string[]\n /** `NavigationStackPage` elements. Pages not in `stack` are still accepted —\n * they simply are not shown — so a router may render all of its screens. */\n children?: ReactNode\n /**\n * Whether push/pop/replace transitions animate at all, forwarded straight\n * to `Adw.NavigationView`'s own `animate-transitions` property (already\n * reachable through this component's inherited `Adw.NavigationView` props —\n * spelled out here because it is the one prop consumers most often go\n * looking for). GTK has exactly one transition style; there is no per-style\n * choice to make here, only whether it plays. Default true, matching the\n * widget's own default. Interactive swipe-back gestures always animate\n * regardless of this value — that is Adwaita's own behavior, not this\n * primitive's.\n */\n animateTransitions?: boolean\n /**\n * The widget popped a page by itself: the Adwaita back button, Escape, the\n * back gesture, or the back-history menu. NOT called for pops you caused by\n * changing `stack`. This is where a router follows the view.\n */\n onPopped?: (tag: string) => void\n /** A closing page finished animating out and was dropped from the tree. */\n onPageClosed?: (tag: string) => void\n /** A push/pop/replace transition started. */\n onTransitionStart?: () => void\n /** …and finished. Driven by the transitioning page's own real\n * `shown`/`hidden` AdwNavigationPage signal (whichever settles it —\n * see beginTransition), with `transitionDuration` as a fallback for the\n * cases where neither arrives. */\n onTransitionEnd?: () => void\n /** Fallback window in ms, used only when a page's own transition signal\n * never arrives (see the file header comment for the two cases this\n * covers) — for page retention and for the transition callbacks above.\n * NOT a measurement of the real transition length. Default 400. */\n transitionDuration?: number\n /** Escape hatch: the underlying Adw.NavigationView, for anything this\n * primitive does not model. */\n ref?: Ref<Adw.NavigationView | null>\n}\n\n/**\n * `Adw.NavigationView` driven declaratively.\n *\n * ```tsx\n * const [stack, setStack] = useState([\"home\"])\n *\n * <NavigationStack\n * stack={stack}\n * onPopped={(tag) => setStack((s) => s.filter((t) => t !== tag))}\n * >\n * <NavigationStackPage tag=\"home\" title=\"Home\">…</NavigationStackPage>\n * <NavigationStackPage tag=\"detail\" title=\"Detail\">…</NavigationStackPage>\n * </NavigationStack>\n * ```\n *\n * No router required. `react-native-gtkx/navigation` uses exactly this\n * component to back `createStackNavigator`.\n */\nexport const NavigationStack = ({\n stack,\n children,\n onPopped,\n onPageClosed,\n onTransitionStart,\n onTransitionEnd,\n transitionDuration = DEFAULT_TRANSITION_MS,\n ref,\n ...rest\n}: NavigationStackProps) => {\n // See NavigationStackPage above — lazy for the same reason.\n const { AdwNavigationView: RawAdwNavigationView } =\n requireAdwJsx(\"NavigationStack\")\n const viewRef = useRef<Adw.NavigationView | null>(null)\n // Mirror of the widget's visible stack. Maintained by the sync effect and\n // by the popped handler; the two never race, because GTK signals run\n // synchronously inside the very push/pop calls the effect makes.\n const syncedRef = useRef<string[]>([])\n\n const pagesByTag = new Map<string, ReactNode>()\n for (const child of Children.toArray(children)) {\n if (isValidElement<{ tag?: unknown }>(child)) {\n const tag = child.props.tag\n if (typeof tag === \"string\") {\n pagesByTag.set(tag, child)\n }\n }\n }\n\n // Pages currently in the tree: everything in `stack`, plus pages that left\n // it and are still animating out.\n const [renderedTags, setRenderedTags] = useState<string[]>(() => [...stack])\n const missing = stack.filter((tag) => !renderedTags.includes(tag))\n if (missing.length > 0) {\n // The sanctioned derive-state-during-render pattern: a new page must be\n // in the tree within the same commit the sync effect pushes it.\n setRenderedTags([...renderedTags, ...missing])\n }\n\n // A state-held stable Map rather than a ref: the render path reads it for\n // closing pages, and reading a ref during render is rightly banned.\n const [snapshots] = useState(() => new Map<string, ReactNode>())\n useEffect(() => {\n for (const [tag, element] of pagesByTag) {\n snapshots.set(tag, element)\n }\n })\n\n const dropPage = useCallback(\n (tag: string): void => {\n let dropped = false\n setRenderedTags((tags) => {\n if (!tags.includes(tag)) {\n return tags\n }\n dropped = true\n return tags.filter((rendered) => rendered !== tag)\n })\n if (dropped) {\n snapshots.delete(tag)\n onPageClosed?.(tag)\n }\n },\n [onPageClosed, snapshots],\n )\n\n // Signal handlers read the CURRENT requested stack, not the one captured\n // when they were created. Refreshed in an insertion effect (the project's\n // standard escape from writing refs during render): insertion effects run\n // before layout effects, so the value is fresh by the time GTK can emit.\n const stackRef = useRef<readonly string[]>(stack)\n useInsertionEffect(() => {\n stackRef.current = stack\n })\n\n // Per-tag waiters for \"this specific page's transition settled\" — fed by\n // reportHidden/reportShown below, drained (and deleted) the moment either\n // fires. A page can end up \"shown\" after being \"hiding\" (an interrupted\n // pop reversed) or \"hidden\" after being \"showing\" (an interrupted push\n // superseded) — GObject-introspection documents both pairings — so a\n // waiter for a given tag resolves on WHICHEVER of the two settles it,\n // not just the one that would be expected in the common case.\n const transitionWaitersRef = useRef<Map<string, Array<() => void>>>(new Map())\n\n const addTransitionWaiter = useCallback(\n (tag: string, resolve: () => void): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (waiters) {\n waiters.push(resolve)\n } else {\n transitionWaitersRef.current.set(tag, [resolve])\n }\n },\n [],\n )\n\n const removeTransitionWaiter = useCallback(\n (tag: string, resolve: () => void): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (!waiters) {\n return\n }\n const next = waiters.filter((waiter) => waiter !== resolve)\n if (next.length > 0) {\n transitionWaitersRef.current.set(tag, next)\n } else {\n transitionWaitersRef.current.delete(tag)\n }\n },\n [],\n )\n\n const resolveTransitionWaiters = useCallback((tag: string): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (!waiters) {\n return\n }\n transitionWaitersRef.current.delete(tag)\n for (const resolve of waiters) {\n resolve()\n }\n }, [])\n\n const reportHidden = useCallback(\n (tag: string): void => {\n resolveTransitionWaiters(tag)\n // \"hidden\" also fires for a live page covered by a push — only pages\n // gone from the requested stack are actually closing.\n if (stackRef.current.includes(tag)) {\n return\n }\n dropPage(tag)\n },\n [dropPage, resolveTransitionWaiters],\n )\n\n const reportShown = useCallback(\n (tag: string): void => {\n resolveTransitionWaiters(tag)\n },\n [resolveTransitionWaiters],\n )\n\n // Delivery of \"hidden\" is not guaranteed — see the file header comment for\n // the two cases (a genuinely signal-less environment, and a page skipped\n // over by a multi-hop pop) — so a timer slightly longer than the fallback\n // window is the backstop. dropPage is idempotent: whichever wins, wins.\n const scheduleDrop = useCallback(\n (tag: string): void => {\n setTimeout(() => reportHidden(tag), transitionDuration)\n },\n [reportHidden, transitionDuration],\n )\n\n // Bracket every transition with an InteractionManager handle so\n // runAfterInteractions work (a screen's data load, a heavy render) waits\n // for the slide instead of stealing its frames, closing it and firing\n // onTransitionEnd exactly when the transition really settles: the real\n // \"shown\"/\"hidden\" signal on `targetTag` (the page this specific push,\n // popToTag or replaceWithTags call is bringing into view) if it arrives,\n // `transitionDuration` otherwise. `targetTag` is undefined only for\n // replaceWithTags([]) — no page becomes visible, nothing to wait on, the\n // timer alone settles it. Overlapping transitions reference-count through\n // the handle API.\n const beginTransition = useCallback(\n (targetTag: string | undefined): void => {\n const handle = InteractionManager.createInteractionHandle()\n onTransitionStart?.()\n let settled = false\n const settle = (): void => {\n if (settled) {\n return\n }\n settled = true\n InteractionManager.clearInteractionHandle(handle)\n onTransitionEnd?.()\n }\n if (targetTag !== undefined) {\n addTransitionWaiter(targetTag, settle)\n }\n setTimeout(() => {\n if (targetTag !== undefined) {\n removeTransitionWaiter(targetTag, settle)\n }\n settle()\n }, transitionDuration)\n },\n [\n addTransitionWaiter,\n removeTransitionWaiter,\n onTransitionEnd,\n onTransitionStart,\n transitionDuration,\n ],\n )\n\n useEffect(() => {\n const view = viewRef.current\n if (!view) {\n return\n }\n const target = [...stack]\n if (syncedRef.current.length === 0 && target.length > 0) {\n // First mount: NavigationView shows the first added page by itself.\n syncedRef.current = target.slice(0, 1)\n }\n let common = 0\n while (\n common < syncedRef.current.length &&\n common < target.length &&\n syncedRef.current[common] === target[common]\n ) {\n common += 1\n }\n if (common === 0 && syncedRef.current[0] !== target[0]) {\n // The root changed (a reset): swap the whole visible stack. The last\n // tag becomes the visible page (undefined only when target is empty —\n // see beginTransition's targetTag doc above).\n const leaving = syncedRef.current.filter((tag) => !target.includes(tag))\n syncedRef.current = [...target]\n beginTransition(target[target.length - 1])\n view.replaceWithTags(target)\n for (const tag of leaving) {\n scheduleDrop(tag)\n }\n return\n }\n if (syncedRef.current.length > common) {\n const anchor = target[common - 1]\n const leaving = syncedRef.current.slice(common)\n syncedRef.current = syncedRef.current.slice(0, common)\n if (anchor !== undefined) {\n beginTransition(anchor)\n view.popToTag(anchor)\n }\n for (const tag of leaving) {\n scheduleDrop(tag)\n }\n }\n for (\n let index = syncedRef.current.length;\n index < target.length;\n index += 1\n ) {\n const tag = target[index]!\n syncedRef.current.push(tag)\n beginTransition(tag)\n view.pushByTag(tag)\n }\n }, [stack, scheduleDrop, beginTransition])\n\n const handlePopped = (page: Adw.NavigationPage | null): void => {\n const tag = page?.getTag()\n if (!tag) {\n return\n }\n syncedRef.current = syncedRef.current.filter((synced) => synced !== tag)\n // Reported unconditionally: the consumer decides whether this pop was\n // one it already knows about. The primitive has no router state to\n // consult, and guessing here is exactly what would couple the layers.\n onPopped?.(tag)\n scheduleDrop(tag)\n }\n\n // The context value must be identity-stable (every page reads it), so the\n // live handlers are reached through refs rather than baked into the value.\n const reportHiddenRef = useRef<(tag: string) => void>(reportHidden)\n const reportShownRef = useRef<(tag: string) => void>(reportShown)\n useInsertionEffect(() => {\n reportHiddenRef.current = reportHidden\n reportShownRef.current = reportShown\n })\n const [lifecycle] = useState<PageLifecycle>(() => ({\n reportHidden: (tag: string) => reportHiddenRef.current(tag),\n reportShown: (tag: string) => reportShownRef.current(tag),\n }))\n\n return (\n <PageLifecycleContext.Provider value={lifecycle}>\n <RawAdwNavigationView\n {...rest}\n ref={(instance: Adw.NavigationView | null) => {\n viewRef.current = instance\n if (typeof ref === \"function\") {\n ref(instance)\n } else if (ref) {\n ref.current = instance\n }\n }}\n onPopped={(page: Adw.NavigationPage | null) => handlePopped(page)}\n >\n {renderedTags.map(\n (tag) => pagesByTag.get(tag) ?? snapshots.get(tag) ?? null,\n )}\n </RawAdwNavigationView>\n </PageLifecycleContext.Provider>\n )\n}\n"]}
|
package/dist/common/widget.js
CHANGED
|
@@ -118,13 +118,7 @@ export const useWidgetLayout = (ref, options = {}) => {
|
|
|
118
118
|
// with nothing in the name or the GIR type to tell them apart — the answer
|
|
119
119
|
// lives in the widget's own layout code. The boundary is what makes NOT
|
|
120
120
|
// saying a readable error instead of a silent mislayout — see useHostNode.
|
|
121
|
-
const SlotBoundary = ({ location, children, }) => (
|
|
122
|
-
// Two providers, no widget: a context provider is invisible to the gtkx
|
|
123
|
-
// reconciler, so this is safe even on slots whose value is NOT a widget
|
|
124
|
-
// (`breakpoints`, `menuModel`, `buffer`, `adjustment` — the majority of
|
|
125
|
-
// element-valued props, in fact) — wrapping those in a real box would put
|
|
126
|
-
// a GtkBox where an AdwBreakpoint belongs.
|
|
127
|
-
_jsx(SlotContext.Provider, { value: location, children: _jsx(HostNodeContext.Provider, { value: null, children: children }) }));
|
|
121
|
+
const SlotBoundary = ({ location, children, }) => (_jsx(SlotContext.Provider, { value: location, children: _jsx(HostNodeContext.Provider, { value: null, children: children }) }));
|
|
128
122
|
const holdsElement = (value) => isValidElement(value) || (Array.isArray(value) && value.some(holdsElement));
|
|
129
123
|
// Puts every element-valued prop, and the children, behind a boundary.
|
|
130
124
|
// `ref` is never content; anything that holds no element (a string child, a
|
|
@@ -141,10 +135,7 @@ const withSlotBoundaries = (props, widget) => {
|
|
|
141
135
|
continue;
|
|
142
136
|
}
|
|
143
137
|
bounded ??= {};
|
|
144
|
-
bounded[key] = (
|
|
145
|
-
// Children are not a named slot: the error says "inside AdwBottomSheet"
|
|
146
|
-
// rather than naming a property that does not exist.
|
|
147
|
-
_jsx(SlotBoundary, { location: { widget, slot: key === "children" ? null : key }, children: value }));
|
|
138
|
+
bounded[key] = (_jsx(SlotBoundary, { location: { widget, slot: key === "children" ? null : key }, children: value }));
|
|
148
139
|
}
|
|
149
140
|
// The common case is a widget with no element-valued prop at all: return the
|
|
150
141
|
// props object untouched rather than allocate a copy per render.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../../src/common/widget.tsx"],"names":[],"mappings":"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","sourcesContent":["// Making a raw GTK widget a first-class citizen of React Native layout.\n//\n// The widgets this subpath re-exports are real GTK widgets, and GTK widgets\n// know nothing about Yoga. Dropped into a <View> as-is they would never be\n// measured or positioned, which would make \"we export everything\" a hollow\n// promise. `Widget` closes that gap: it gives the widget a Yoga node, applies\n// the layout half of a React Native style to it, and — this is the part that\n// matters — measures the widget itself, so it lands at the size the GTK theme\n// actually wants instead of collapsing to zero.\n//\n// The visual half of the style (background, border, radius) is applied as a\n// GTK CSS class, the same mechanism View uses.\nimport {\n isValidElement,\n useContext,\n useRef,\n type ComponentType,\n type ReactNode,\n} from \"react\"\nimport {\n HostNodeContext,\n SlotContext,\n type SlotLocation,\n} from \"../components/host-node\"\nimport {\n useLayoutChild,\n type LayoutEvent,\n} from \"../components/use-layout-child\"\nimport type { StyleProp } from \"../contracts\"\nimport { GtkBox, type Gtk } from \"../gtkx/bridge/index\"\n\nexport type WidgetProps = {\n /** React Native style. The layout half drives Yoga, the visual half becomes\n * a GTK CSS class. Omit sizing and the widget's own natural size wins. */\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n /** The GTK widget(s) to lay out. Your own `ref` on them is untouched. */\n children: ReactNode\n testID?: string\n}\n\n/**\n * Put any GTK widget into React Native layout.\n *\n * ```tsx\n * <View style={{ flexDirection: \"row\", gap: 8, padding: 12 }}>\n * <Widget style={{ flex: 1 }}>\n * <GtkEntry placeholderText=\"Search\" />\n * </Widget>\n * <Widget>\n * <GtkButton iconName=\"edit-find-symbolic\" />\n * </Widget>\n * </View>\n * ```\n *\n * The entry flexes, the button takes its natural size, both sit in the row\n * exactly like React Native children — because to Yoga they now are.\n *\n * For the reverse direction (React Native content inside a GTK slot) see\n * `SlotContent` and `IntrinsicContent`.\n */\nexport const Widget = ({ style, onLayout, children, testID }: WidgetProps) => {\n // The wrapper box IS the Yoga leaf, and it is measured through GTK, so the\n // widget inside reports its natural size up to Yoga. Wrapping rather than\n // cloning keeps the child's own ref and props untouched.\n const boxRef = useRef<Gtk.Box | null>(null)\n const { cssClass } = useLayoutChild(boxRef, {\n style,\n onLayout,\n // Without this a widget with no explicit size would measure as zero —\n // the whole reason a naked GtkButton in a View looks broken.\n measureFromWidget: true,\n })\n\n return (\n <GtkBox\n ref={boxRef}\n name={testID}\n cssClasses={cssClass ? [cssClass] : undefined}\n >\n {children}\n </GtkBox>\n )\n}\n\nexport type UseWidgetLayoutOptions = {\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n}\n\n/**\n * The same thing as {@link Widget}, without the extra component — attach the\n * ref yourself when you already hold one.\n *\n * ```tsx\n * const ref = useRef<Gtk.Button | null>(null)\n * useWidgetLayout(ref, { style: { width: 40, height: 40 } })\n * return <GtkButton ref={ref} iconName=\"open-menu-symbolic\" />\n * ```\n *\n * Returns the GTK CSS class produced by the visual half of the style, or\n * null — pass it to the widget's `cssClasses` if you want backgrounds and\n * borders from the style to apply.\n */\nexport const useWidgetLayout = (\n ref: { current: Gtk.Widget | null },\n options: UseWidgetLayoutOptions = {},\n): string | null => {\n const { cssClass } = useLayoutChild(ref, {\n style: options.style,\n onLayout: options.onLayout,\n measureFromWidget: true,\n })\n return cssClass\n}\n\nexport type ReactNativeLayoutProps = {\n /** React Native style. The layout half drives Yoga, the visual half becomes\n * a GTK CSS class. Omit sizing and the widget's natural size wins. */\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n}\n\n/**\n * Give a GTK component React Native layout, keeping every prop it already\n * has.\n *\n * ```tsx\n * const Button = wrapReactNative(GtkButton)\n *\n * <View style={{ flexDirection: \"row\", gap: 8 }}>\n * <Button style={{ flex: 1 }} label=\"Save\" onClicked={save} />\n * </View>\n * ```\n *\n * The result is generic in the wrapped component's props, so `label`,\n * `onClicked` and everything else gtkx binds keep their types; `style` and\n * `onLayout` are added on top.\n *\n * **Outside React Native layout it steps aside.** The same widget is often\n * used in a pure GTK slot — a HeaderBar's `start`, a ToolbarView's `topBar` —\n * where there is no Yoga tree to join. The wrapper detects that and renders\n * the bare component, so one exported symbol works in both worlds.\n */\n// A wrapped widget is a Yoga LEAF, so everything INSIDE it is GTK's\n// territory — its children and its slots alike.\n//\n// A widget SLOT is a property that takes a widget (`titleWidget`, `sheet`,\n// `sidebar`, `startChild`); a widget's content area is an ordinary child.\n// The distinction is gtkx's, it moves between releases — rc.3 took the\n// `content`/`child` props off single-child widgets and made that content a\n// child — and it has never had anything to do with layout. Both keep\n// rendering where they were written, so both keep seeing the enclosing React\n// Native layout root even though GTK has parented them somewhere else\n// entirely. Content then joins a Yoga tree whose viewport is the WINDOW\n// while GTK gives it the widget's own rectangle: laid out against one box,\n// drawn in another, and silently stealing space from a tree it was never\n// meant to be in.\n//\n// So the boundary clears the layout root on the way in. The widgets a slot\n// or a child usually holds want exactly that (it is what `WidgetContent`\n// does by hand), and React Native content entering has to bring its own root\n// — `SlotContent` to fill the area, `IntrinsicContent` to size the area to\n// itself. Which of the two is right cannot be inferred, and measurement says\n// so louder than argument: `AdwBottomSheet` alone FILLS in its content child\n// but HUGS in both `sheet` (a bottom sheet rises to the height of its own\n// contents) and `bottomBar`. One widget, three content areas, two answers,\n// with nothing in the name or the GIR type to tell them apart — the answer\n// lives in the widget's own layout code. The boundary is what makes NOT\n// saying a readable error instead of a silent mislayout — see useHostNode.\nconst SlotBoundary = ({\n location,\n children,\n}: {\n location: SlotLocation\n children: ReactNode\n}) => (\n // Two providers, no widget: a context provider is invisible to the gtkx\n // reconciler, so this is safe even on slots whose value is NOT a widget\n // (`breakpoints`, `menuModel`, `buffer`, `adjustment` — the majority of\n // element-valued props, in fact) — wrapping those in a real box would put\n // a GtkBox where an AdwBreakpoint belongs.\n <SlotContext.Provider value={location}>\n <HostNodeContext.Provider value={null}>{children}</HostNodeContext.Provider>\n </SlotContext.Provider>\n)\n\nconst holdsElement = (value: unknown): boolean =>\n isValidElement(value) || (Array.isArray(value) && value.some(holdsElement))\n\n// Puts every element-valued prop, and the children, behind a boundary.\n// `ref` is never content; anything that holds no element (a string child, a\n// number, an already-constructed GObject) is left exactly as it was, so the\n// common widget pays nothing.\nconst withSlotBoundaries = <P extends object>(props: P, widget: string): P => {\n let bounded: Record<string, unknown> | undefined\n for (const key in props) {\n if (key === \"ref\") {\n continue\n }\n const value = (props as Record<string, unknown>)[key]\n if (!holdsElement(value)) {\n continue\n }\n bounded ??= {}\n bounded[key] = (\n // Children are not a named slot: the error says \"inside AdwBottomSheet\"\n // rather than naming a property that does not exist.\n <SlotBoundary\n location={{ widget, slot: key === \"children\" ? null : key }}\n >\n {value as ReactNode}\n </SlotBoundary>\n )\n }\n // The common case is a widget with no element-valued prop at all: return the\n // props object untouched rather than allocate a copy per render.\n return bounded ? ({ ...props, ...bounded } as P) : props\n}\n\nexport const wrapReactNative = <P extends object>(\n Component: ComponentType<P>,\n // The widget's name, for error messages and React devtools. gtkx builds its\n // components from a factory, so they carry no name of their own — the\n // generated widget surface passes the class name it already knows.\n widgetName?: string,\n): ComponentType<P & ReactNativeLayoutProps> => {\n const name =\n widgetName ||\n (Component as { displayName?: string; name?: string }).displayName ||\n (Component as { name?: string }).name ||\n \"Widget\"\n\n const InLayout = (props: P & ReactNativeLayoutProps) => {\n const { style, onLayout, ...rest } = props\n const boxRef = useRef<Gtk.Box | null>(null)\n const { cssClass } = useLayoutChild(boxRef, {\n style,\n onLayout,\n // Without this a widget with no explicit size measures as zero — the\n // whole reason a naked GtkButton in a View looks broken.\n measureFromWidget: true,\n })\n const inner = rest as P & { cssClasses?: string[] } & {\n hexpand?: boolean\n vexpand?: boolean\n }\n return (\n <GtkBox ref={boxRef}>\n <Component\n {...inner}\n // The style's visual half lands on the WIDGET, not on the wrapper,\n // so backgrounds and borders colour the button itself. This is the\n // point: on this platform React Native style drives GTK.\n cssClasses={\n cssClass\n ? [...(inner.cssClasses ?? []), cssClass]\n : inner.cssClasses\n }\n // Fill the rect Yoga computed, so `flex: 1` and explicit sizes mean\n // what they mean everywhere else in React Native. An explicit\n // hexpand/vexpand from the caller still wins.\n hexpand={inner.hexpand ?? true}\n vexpand={inner.vexpand ?? true}\n />\n </GtkBox>\n )\n }\n\n const Wrapped = (props: P & ReactNativeLayoutProps) => {\n // Every slot this widget is given becomes GTK territory, in both branches\n // below: whether the widget itself joined React Native layout has nothing\n // to do with what its slots hold.\n const withSlots = withSlotBoundaries(props, name)\n // Read the context directly rather than through useHostNode, which throws\n // by design: here its absence is a supported case, not a mistake. The\n // same widget is often used in a pure GTK slot (a HeaderBar's `start`, a\n // ToolbarView's `topBar`) where there is no Yoga tree to join.\n const host = useContext(HostNodeContext)\n if (!host) {\n // style/onLayout are meaningless without a Yoga tree — drop them rather\n // than forward them onto a GObject that has no such properties.\n const rest = { ...withSlots } as Partial<ReactNativeLayoutProps>\n delete rest.style\n delete rest.onLayout\n return <Component {...(rest as P)} />\n }\n return <InLayout {...withSlots} />\n }\n\n InLayout.displayName = `wrapReactNative(${name}).InLayout`\n Wrapped.displayName = `wrapReactNative(${name})`\n return Wrapped\n}\n"]}
|
|
1
|
+
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../../src/common/widget.tsx"],"names":[],"mappings":"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","sourcesContent":["// Making a raw GTK widget a first-class citizen of React Native layout.\n//\n// The widgets this subpath re-exports are real GTK widgets, and GTK widgets\n// know nothing about Yoga. Dropped into a <View> as-is they would never be\n// measured or positioned, which would make \"we export everything\" a hollow\n// promise. `Widget` closes that gap: it gives the widget a Yoga node, applies\n// the layout half of a React Native style to it, and — this is the part that\n// matters — measures the widget itself, so it lands at the size the GTK theme\n// actually wants instead of collapsing to zero.\n//\n// The visual half of the style (background, border, radius) is applied as a\n// GTK CSS class, the same mechanism View uses.\nimport {\n isValidElement,\n useContext,\n useRef,\n type ComponentType,\n type ReactNode,\n} from \"react\"\nimport {\n HostNodeContext,\n SlotContext,\n type SlotLocation,\n} from \"../components/host-node\"\nimport {\n useLayoutChild,\n type LayoutEvent,\n} from \"../components/use-layout-child\"\nimport type { StyleProp } from \"../contracts\"\nimport { GtkBox, type Gtk } from \"../gtkx/bridge/index\"\n\nexport type WidgetProps = {\n /** React Native style. The layout half drives Yoga, the visual half becomes\n * a GTK CSS class. Omit sizing and the widget's own natural size wins. */\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n /** The GTK widget(s) to lay out. Your own `ref` on them is untouched. */\n children: ReactNode\n testID?: string\n}\n\n/**\n * Put any GTK widget into React Native layout.\n *\n * ```tsx\n * <View style={{ flexDirection: \"row\", gap: 8, padding: 12 }}>\n * <Widget style={{ flex: 1 }}>\n * <GtkEntry placeholderText=\"Search\" />\n * </Widget>\n * <Widget>\n * <GtkButton iconName=\"edit-find-symbolic\" />\n * </Widget>\n * </View>\n * ```\n *\n * The entry flexes, the button takes its natural size, both sit in the row\n * exactly like React Native children — because to Yoga they now are.\n *\n * For the reverse direction (React Native content inside a GTK slot) see\n * `SlotContent` and `IntrinsicContent`.\n */\nexport const Widget = ({ style, onLayout, children, testID }: WidgetProps) => {\n // The wrapper box IS the Yoga leaf, and it is measured through GTK, so the\n // widget inside reports its natural size up to Yoga. Wrapping rather than\n // cloning keeps the child's own ref and props untouched.\n const boxRef = useRef<Gtk.Box | null>(null)\n const { cssClass } = useLayoutChild(boxRef, {\n style,\n onLayout,\n // Without this a widget with no explicit size would measure as zero —\n // the whole reason a naked GtkButton in a View looks broken.\n measureFromWidget: true,\n })\n\n return (\n <GtkBox\n ref={boxRef}\n name={testID}\n cssClasses={cssClass ? [cssClass] : undefined}\n >\n {children}\n </GtkBox>\n )\n}\n\nexport type UseWidgetLayoutOptions = {\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n}\n\n/**\n * The same thing as {@link Widget}, without the extra component — attach the\n * ref yourself when you already hold one.\n *\n * ```tsx\n * const ref = useRef<Gtk.Button | null>(null)\n * useWidgetLayout(ref, { style: { width: 40, height: 40 } })\n * return <GtkButton ref={ref} iconName=\"open-menu-symbolic\" />\n * ```\n *\n * Returns the GTK CSS class produced by the visual half of the style, or\n * null — pass it to the widget's `cssClasses` if you want backgrounds and\n * borders from the style to apply.\n */\nexport const useWidgetLayout = (\n ref: { current: Gtk.Widget | null },\n options: UseWidgetLayoutOptions = {},\n): string | null => {\n const { cssClass } = useLayoutChild(ref, {\n style: options.style,\n onLayout: options.onLayout,\n measureFromWidget: true,\n })\n return cssClass\n}\n\nexport type ReactNativeLayoutProps = {\n /** React Native style. The layout half drives Yoga, the visual half becomes\n * a GTK CSS class. Omit sizing and the widget's natural size wins. */\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n}\n\n/**\n * Give a GTK component React Native layout, keeping every prop it already\n * has.\n *\n * ```tsx\n * const Button = wrapReactNative(GtkButton)\n *\n * <View style={{ flexDirection: \"row\", gap: 8 }}>\n * <Button style={{ flex: 1 }} label=\"Save\" onClicked={save} />\n * </View>\n * ```\n *\n * The result is generic in the wrapped component's props, so `label`,\n * `onClicked` and everything else gtkx binds keep their types; `style` and\n * `onLayout` are added on top.\n *\n * **Outside React Native layout it steps aside.** The same widget is often\n * used in a pure GTK slot — a HeaderBar's `start`, a ToolbarView's `topBar` —\n * where there is no Yoga tree to join. The wrapper detects that and renders\n * the bare component, so one exported symbol works in both worlds.\n */\n// A wrapped widget is a Yoga LEAF, so everything INSIDE it is GTK's\n// territory — its children and its slots alike.\n//\n// A widget SLOT is a property that takes a widget (`titleWidget`, `sheet`,\n// `sidebar`, `startChild`); a widget's content area is an ordinary child.\n// The distinction is gtkx's, it moves between releases — rc.3 took the\n// `content`/`child` props off single-child widgets and made that content a\n// child — and it has never had anything to do with layout. Both keep\n// rendering where they were written, so both keep seeing the enclosing React\n// Native layout root even though GTK has parented them somewhere else\n// entirely. Content then joins a Yoga tree whose viewport is the WINDOW\n// while GTK gives it the widget's own rectangle: laid out against one box,\n// drawn in another, and silently stealing space from a tree it was never\n// meant to be in.\n//\n// So the boundary clears the layout root on the way in. The widgets a slot\n// or a child usually holds want exactly that (it is what `WidgetContent`\n// does by hand), and React Native content entering has to bring its own root\n// — `SlotContent` to fill the area, `IntrinsicContent` to size the area to\n// itself. Which of the two is right cannot be inferred, and measurement says\n// so louder than argument: `AdwBottomSheet` alone FILLS in its content child\n// but HUGS in both `sheet` (a bottom sheet rises to the height of its own\n// contents) and `bottomBar`. One widget, three content areas, two answers,\n// with nothing in the name or the GIR type to tell them apart — the answer\n// lives in the widget's own layout code. The boundary is what makes NOT\n// saying a readable error instead of a silent mislayout — see useHostNode.\nconst SlotBoundary = ({\n location,\n children,\n}: {\n location: SlotLocation\n children: ReactNode\n}) => (\n // Two providers, no widget: a context provider is invisible to the gtkx\n // reconciler, so this is safe even on slots whose value is NOT a widget\n // (`breakpoints`, `menuModel`, `buffer`, `adjustment` — the majority of\n // element-valued props, in fact) — wrapping those in a real box would put\n // a GtkBox where an AdwBreakpoint belongs.\n <SlotContext.Provider value={location}>\n <HostNodeContext.Provider value={null}>{children}</HostNodeContext.Provider>\n </SlotContext.Provider>\n)\n\nconst holdsElement = (value: unknown): boolean =>\n isValidElement(value) || (Array.isArray(value) && value.some(holdsElement))\n\n// Puts every element-valued prop, and the children, behind a boundary.\n// `ref` is never content; anything that holds no element (a string child, a\n// number, an already-constructed GObject) is left exactly as it was, so the\n// common widget pays nothing.\nconst withSlotBoundaries = <P extends object>(props: P, widget: string): P => {\n let bounded: Record<string, unknown> | undefined\n for (const key in props) {\n if (key === \"ref\") {\n continue\n }\n const value = (props as Record<string, unknown>)[key]\n if (!holdsElement(value)) {\n continue\n }\n bounded ??= {}\n bounded[key] = (\n // Children are not a named slot: the error says \"inside AdwBottomSheet\"\n // rather than naming a property that does not exist.\n <SlotBoundary\n location={{ widget, slot: key === \"children\" ? null : key }}\n >\n {value as ReactNode}\n </SlotBoundary>\n )\n }\n // The common case is a widget with no element-valued prop at all: return the\n // props object untouched rather than allocate a copy per render.\n return bounded ? ({ ...props, ...bounded } as P) : props\n}\n\nexport const wrapReactNative = <P extends object>(\n Component: ComponentType<P>,\n // The widget's name, for error messages and React devtools. gtkx builds its\n // components from a factory, so they carry no name of their own — the\n // generated widget surface passes the class name it already knows.\n widgetName?: string,\n): ComponentType<P & ReactNativeLayoutProps> => {\n const name =\n widgetName ||\n (Component as { displayName?: string; name?: string }).displayName ||\n (Component as { name?: string }).name ||\n \"Widget\"\n\n const InLayout = (props: P & ReactNativeLayoutProps) => {\n const { style, onLayout, ...rest } = props\n const boxRef = useRef<Gtk.Box | null>(null)\n const { cssClass } = useLayoutChild(boxRef, {\n style,\n onLayout,\n // Without this a widget with no explicit size measures as zero — the\n // whole reason a naked GtkButton in a View looks broken.\n measureFromWidget: true,\n })\n const inner = rest as P & { cssClasses?: string[] } & {\n hexpand?: boolean\n vexpand?: boolean\n }\n return (\n <GtkBox ref={boxRef}>\n <Component\n {...inner}\n // The style's visual half lands on the WIDGET, not on the wrapper,\n // so backgrounds and borders colour the button itself. This is the\n // point: on this platform React Native style drives GTK.\n cssClasses={\n cssClass\n ? [...(inner.cssClasses ?? []), cssClass]\n : inner.cssClasses\n }\n // Fill the rect Yoga computed, so `flex: 1` and explicit sizes mean\n // what they mean everywhere else in React Native. An explicit\n // hexpand/vexpand from the caller still wins.\n hexpand={inner.hexpand ?? true}\n vexpand={inner.vexpand ?? true}\n />\n </GtkBox>\n )\n }\n\n const Wrapped = (props: P & ReactNativeLayoutProps) => {\n // Every slot this widget is given becomes GTK territory, in both branches\n // below: whether the widget itself joined React Native layout has nothing\n // to do with what its slots hold.\n const withSlots = withSlotBoundaries(props, name)\n // Read the context directly rather than through useHostNode, which throws\n // by design: here its absence is a supported case, not a mistake. The\n // same widget is often used in a pure GTK slot (a HeaderBar's `start`, a\n // ToolbarView's `topBar`) where there is no Yoga tree to join.\n const host = useContext(HostNodeContext)\n if (!host) {\n // style/onLayout are meaningless without a Yoga tree — drop them rather\n // than forward them onto a GObject that has no such properties.\n const rest = { ...withSlots } as Partial<ReactNativeLayoutProps>\n delete rest.style\n delete rest.onLayout\n return <Component {...(rest as P)} />\n }\n return <InLayout {...withSlots} />\n }\n\n InLayout.displayName = `wrapReactNative(${name}).InLayout`\n Wrapped.displayName = `wrapReactNative(${name})`\n return Wrapped\n}\n"]}
|
|
@@ -97,5 +97,6 @@ export declare const Animated: {
|
|
|
97
97
|
parallel(animations: import("../animated/types").CompositeAnimation[], config?: import("../animated/types").ParallelConfig): import("../animated/types").CompositeAnimation;
|
|
98
98
|
delay(ms: number): import("../animated/types").CompositeAnimation;
|
|
99
99
|
loop(animation: import("../animated/types").CompositeAnimation, config?: import("../animated/types").LoopConfig): import("../animated/types").CompositeAnimation;
|
|
100
|
+
event(argMapping: readonly (import("../animated/event").EventMapping | null | undefined)[], config?: import("../animated/event").AnimatedEventConfig): (...args: unknown[]) => void;
|
|
100
101
|
};
|
|
101
102
|
export { Easing } from "../animated/index";
|