@gtkx/testing 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/pretty-widget.js +2 -1
- package/dist/render.js +1 -2
- package/dist/screen.d.ts +1 -1
- package/dist/screen.js +2 -2
- package/dist/traversal.d.ts +1 -1
- package/dist/traversal.js +4 -3
- package/dist/user-event.d.ts +2 -2
- package/dist/user-event.js +22 -9
- package/dist/widget-text.js +2 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -71,6 +71,7 @@ render(<App />, "com.example.counter");
|
|
|
71
71
|
- **React 19** — Hooks, concurrent features, and the component model you know
|
|
72
72
|
- **Native GTK4 widgets** — Real native controls, not web components in a webview
|
|
73
73
|
- **Adwaita support** — Modern GNOME styling with Libadwaita components
|
|
74
|
+
- **Declarative animations** — Framer Motion-like API using native Adwaita animations
|
|
74
75
|
- **Hot Module Replacement** — Fast refresh during development
|
|
75
76
|
- **TypeScript first** — Full type safety with auto-generated bindings
|
|
76
77
|
- **CSS-in-JS styling** — Familiar styling patterns adapted for GTK
|
package/dist/pretty-widget.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getNativeId } from "@gtkx/ffi";
|
|
2
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
3
|
import { formatRole } from "./role-helpers.js";
|
|
3
4
|
import { isApplication } from "./traversal.js";
|
|
4
5
|
import { getWidgetText } from "./widget-text.js";
|
|
@@ -105,7 +106,7 @@ const printWidget = (widget, colors, depth, includeIds) => {
|
|
|
105
106
|
};
|
|
106
107
|
const printContainer = (container, colors, includeIds) => {
|
|
107
108
|
if (isApplication(container)) {
|
|
108
|
-
const windows =
|
|
109
|
+
const windows = Gtk.Window.listToplevels();
|
|
109
110
|
return windows.map((window) => printWidget(window, colors, 0, includeIds)).join("");
|
|
110
111
|
}
|
|
111
112
|
return printWidget(container, colors, 0, includeIds);
|
package/dist/render.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { start, stop } from "@gtkx/ffi";
|
|
3
3
|
import * as Gio from "@gtkx/ffi/gio";
|
|
4
4
|
import { ApplicationContext, GtkApplicationWindow, reconciler } from "@gtkx/react";
|
|
5
5
|
import { bindQueries } from "./bind-queries.js";
|
|
@@ -20,7 +20,6 @@ const update = async (instance, element, fiberRoot) => {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
const handleError = (error) => {
|
|
23
|
-
discardAllBatches();
|
|
24
23
|
lastRenderError = error;
|
|
25
24
|
};
|
|
26
25
|
const ensureInitialized = () => {
|
package/dist/screen.d.ts
CHANGED
package/dist/screen.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
4
5
|
import { bindQueries } from "./bind-queries.js";
|
|
5
6
|
import { prettyWidget } from "./pretty-widget.js";
|
|
6
7
|
import { logRoles } from "./role-helpers.js";
|
|
@@ -80,8 +81,7 @@ export const screen = {
|
|
|
80
81
|
* ```
|
|
81
82
|
*/
|
|
82
83
|
screenshot: async (selector, options) => {
|
|
83
|
-
const
|
|
84
|
-
const windows = root.getWindows();
|
|
84
|
+
const windows = Gtk.Window.listToplevels();
|
|
85
85
|
if (windows.length === 0) {
|
|
86
86
|
throw new Error("No windows available for screenshot");
|
|
87
87
|
}
|
package/dist/traversal.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
2
|
export type Container = Gtk.Application | Gtk.Widget;
|
|
3
3
|
export declare const isApplication: (container: Container) => container is Gtk.Application;
|
|
4
4
|
export declare const traverse: (container: Container) => Generator<Gtk.Widget>;
|
package/dist/traversal.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as Gtk from "@gtkx/ffi/gtk";
|
|
1
2
|
export const isApplication = (container) => "getWindows" in container && typeof container.getWindows === "function";
|
|
2
3
|
const traverseWidgetTree = function* (root) {
|
|
3
4
|
yield root;
|
|
@@ -7,15 +8,15 @@ const traverseWidgetTree = function* (root) {
|
|
|
7
8
|
child = child.getNextSibling();
|
|
8
9
|
}
|
|
9
10
|
};
|
|
10
|
-
const
|
|
11
|
-
const windows =
|
|
11
|
+
const traverseWindows = function* () {
|
|
12
|
+
const windows = Gtk.Window.listToplevels();
|
|
12
13
|
for (const window of windows) {
|
|
13
14
|
yield* traverseWidgetTree(window);
|
|
14
15
|
}
|
|
15
16
|
};
|
|
16
17
|
export const traverse = function* (container) {
|
|
17
18
|
if (isApplication(container)) {
|
|
18
|
-
yield*
|
|
19
|
+
yield* traverseWindows();
|
|
19
20
|
}
|
|
20
21
|
else {
|
|
21
22
|
yield* traverseWidgetTree(container);
|
package/dist/user-event.d.ts
CHANGED
|
@@ -46,13 +46,13 @@ export declare const userEvent: {
|
|
|
46
46
|
/**
|
|
47
47
|
* Double-clicks a widget.
|
|
48
48
|
*
|
|
49
|
-
* Emits
|
|
49
|
+
* Emits pressed/released signals with n_press=1, then n_press=2.
|
|
50
50
|
*/
|
|
51
51
|
dblClick: (element: Gtk.Widget) => Promise<void>;
|
|
52
52
|
/**
|
|
53
53
|
* Triple-clicks a widget.
|
|
54
54
|
*
|
|
55
|
-
* Emits
|
|
55
|
+
* Emits pressed/released signals with n_press=1, 2, then 3. Useful for text selection.
|
|
56
56
|
*/
|
|
57
57
|
tripleClick: (element: Gtk.Widget) => Promise<void>;
|
|
58
58
|
/**
|
package/dist/user-event.js
CHANGED
|
@@ -35,14 +35,25 @@ const click = async (element) => {
|
|
|
35
35
|
await fireEvent(element, "clicked");
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
const emitClickSequence = async (element, nPress) => {
|
|
39
|
+
const controller = getOrCreateController(element, Gtk.GestureClick);
|
|
40
|
+
for (let i = 1; i <= nPress; i++) {
|
|
41
|
+
const args = [
|
|
42
|
+
Value.newFromObject(controller),
|
|
43
|
+
Value.newFromInt(i),
|
|
44
|
+
Value.newFromDouble(0),
|
|
45
|
+
Value.newFromDouble(0),
|
|
46
|
+
];
|
|
47
|
+
signalEmitv(args, getSignalId(controller, "pressed"), 0, null);
|
|
48
|
+
signalEmitv(args, getSignalId(controller, "released"), 0, null);
|
|
49
|
+
}
|
|
50
|
+
await tick();
|
|
51
|
+
};
|
|
38
52
|
const dblClick = async (element) => {
|
|
39
|
-
await
|
|
40
|
-
await fireEvent(element, "clicked");
|
|
53
|
+
await emitClickSequence(element, 2);
|
|
41
54
|
};
|
|
42
55
|
const tripleClick = async (element) => {
|
|
43
|
-
await
|
|
44
|
-
await fireEvent(element, "clicked");
|
|
45
|
-
await fireEvent(element, "clicked");
|
|
56
|
+
await emitClickSequence(element, 3);
|
|
46
57
|
};
|
|
47
58
|
const tab = async (element, options) => {
|
|
48
59
|
const direction = options?.shift ? Gtk.DirectionType.TAB_BACKWARD : Gtk.DirectionType.TAB_FORWARD;
|
|
@@ -238,17 +249,19 @@ const parseKeyboardInput = (input) => {
|
|
|
238
249
|
}
|
|
239
250
|
return actions;
|
|
240
251
|
};
|
|
252
|
+
let gdkModifierType = null;
|
|
241
253
|
const keyboard = async (element, input) => {
|
|
254
|
+
gdkModifierType ??= typeFromName("GdkModifierType");
|
|
242
255
|
const controller = getOrCreateController(element, Gtk.EventControllerKey);
|
|
243
256
|
const actions = parseKeyboardInput(input);
|
|
244
257
|
for (const action of actions) {
|
|
245
258
|
const signalName = action.press ? "key-pressed" : "key-released";
|
|
246
|
-
const returnValue = Value.newFromBoolean(false);
|
|
259
|
+
const returnValue = action.press ? Value.newFromBoolean(false) : null;
|
|
247
260
|
signalEmitv([
|
|
248
261
|
Value.newFromObject(controller),
|
|
249
262
|
Value.newFromUint(action.keyval),
|
|
250
263
|
Value.newFromUint(0),
|
|
251
|
-
Value.
|
|
264
|
+
Value.newFromFlags(gdkModifierType, 0),
|
|
252
265
|
], getSignalId(controller, signalName), 0, returnValue);
|
|
253
266
|
if (action.press && action.keyval === Gdk.KEY_Return && isEditable(element)) {
|
|
254
267
|
await fireEvent(element, "activate");
|
|
@@ -314,13 +327,13 @@ export const userEvent = {
|
|
|
314
327
|
/**
|
|
315
328
|
* Double-clicks a widget.
|
|
316
329
|
*
|
|
317
|
-
* Emits
|
|
330
|
+
* Emits pressed/released signals with n_press=1, then n_press=2.
|
|
318
331
|
*/
|
|
319
332
|
dblClick,
|
|
320
333
|
/**
|
|
321
334
|
* Triple-clicks a widget.
|
|
322
335
|
*
|
|
323
|
-
* Emits
|
|
336
|
+
* Emits pressed/released signals with n_press=1, 2, then 3. Useful for text selection.
|
|
324
337
|
*/
|
|
325
338
|
tripleClick,
|
|
326
339
|
/**
|
package/dist/widget-text.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getNativeInterface } from "@gtkx/ffi";
|
|
2
2
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
3
3
|
const ROLES_WITH_INTERNAL_LABELS = new Set([
|
|
4
4
|
Gtk.AccessibleRole.BUTTON,
|
|
@@ -77,7 +77,7 @@ export const getWidgetText = (widget) => {
|
|
|
77
77
|
case Gtk.AccessibleRole.TEXT_BOX:
|
|
78
78
|
case Gtk.AccessibleRole.SEARCH_BOX:
|
|
79
79
|
case Gtk.AccessibleRole.SPIN_BUTTON:
|
|
80
|
-
return
|
|
80
|
+
return getNativeInterface(widget, Gtk.Editable)?.getText() ?? null;
|
|
81
81
|
case Gtk.AccessibleRole.GROUP:
|
|
82
82
|
return widget.getLabel?.() ?? null;
|
|
83
83
|
case Gtk.AccessibleRole.WINDOW:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtkx/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Testing utilities for GTKX applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gtkx",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@gtkx/ffi": "0.
|
|
40
|
-
"@gtkx/react": "0.
|
|
39
|
+
"@gtkx/ffi": "0.16.0",
|
|
40
|
+
"@gtkx/react": "0.16.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/react-reconciler": "^0.32.3",
|
|
44
44
|
"react-reconciler": "^0.33.0",
|
|
45
|
-
"@gtkx/vitest": "0.
|
|
45
|
+
"@gtkx/vitest": "0.16.0"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "tsc -b && cp ../../README.md .",
|