@gtkx/testing 0.14.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 +2 -1
- package/dist/fire-event.d.ts +5 -4
- package/dist/fire-event.js +8 -8
- 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 +9 -2
- package/dist/user-event.js +49 -36
- package/dist/widget-text.js +2 -2
- package/package.json +4 -5
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
|
|
@@ -80,11 +81,11 @@ render(<App />, "com.example.counter");
|
|
|
80
81
|
|
|
81
82
|
Explore complete applications in the [`examples/`](./examples) directory:
|
|
82
83
|
|
|
83
|
-
- **[browser](./examples/browser)** — Simple browser using WebKitWebView
|
|
84
84
|
- **[gtk-demo](./examples/gtk-demo)** — Full replica of the official GTK demo app
|
|
85
85
|
- **[hello-world](./examples/hello-world)** — Minimal application showing a counter
|
|
86
86
|
- **[todo](./examples/todo)** — Full-featured todo application with Adwaita styling and testing
|
|
87
87
|
- **[x-showcase](./examples/x-showcase)** — Showcase of all x.\* virtual components
|
|
88
|
+
- **[browser](./examples/browser)** — Simple browser using WebKitWebView
|
|
88
89
|
- **[deploying](./examples/deploying)** — Example of packaging and distributing a GTKX app
|
|
89
90
|
|
|
90
91
|
## Documentation
|
package/dist/fire-event.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { Value } from "@gtkx/ffi/gobject";
|
|
1
2
|
import type * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
-
import type { Arg } from "@gtkx/native";
|
|
3
3
|
/**
|
|
4
4
|
* Emits a GTK signal on a widget or event controller.
|
|
5
5
|
*
|
|
@@ -8,20 +8,21 @@ import type { Arg } from "@gtkx/native";
|
|
|
8
8
|
*
|
|
9
9
|
* @param element - The widget or event controller to emit the signal on
|
|
10
10
|
* @param signalName - GTK signal name (e.g., "clicked", "activate", "drag-begin")
|
|
11
|
-
* @param args - Additional signal arguments
|
|
11
|
+
* @param args - Additional signal arguments as GValues
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```tsx
|
|
15
15
|
* import { fireEvent } from "@gtkx/testing";
|
|
16
|
+
* import { Value } from "@gtkx/ffi/gobject";
|
|
16
17
|
*
|
|
17
18
|
* // Emit signal on widget
|
|
18
19
|
* await fireEvent(widget, "clicked");
|
|
19
20
|
*
|
|
20
21
|
* // Emit signal on gesture controller
|
|
21
22
|
* const gesture = widget.observeControllers().getObject(0) as Gtk.GestureDrag;
|
|
22
|
-
* await fireEvent(gesture, "drag-begin",
|
|
23
|
+
* await fireEvent(gesture, "drag-begin", Value.newFromDouble(100), Value.newFromDouble(100));
|
|
23
24
|
* ```
|
|
24
25
|
*
|
|
25
26
|
* @see {@link userEvent} for high-level user interactions
|
|
26
27
|
*/
|
|
27
|
-
export declare const fireEvent: (element: Gtk.Widget | Gtk.EventController, signalName: string, ...args:
|
|
28
|
+
export declare const fireEvent: (element: Gtk.Widget | Gtk.EventController, signalName: string, ...args: Value[]) => Promise<void>;
|
package/dist/fire-event.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { signalEmitv, signalLookup, typeFromName, Value } from "@gtkx/ffi/gobject";
|
|
2
2
|
import { tick } from "./timing.js";
|
|
3
3
|
/**
|
|
4
4
|
* Emits a GTK signal on a widget or event controller.
|
|
@@ -8,27 +8,27 @@ import { tick } from "./timing.js";
|
|
|
8
8
|
*
|
|
9
9
|
* @param element - The widget or event controller to emit the signal on
|
|
10
10
|
* @param signalName - GTK signal name (e.g., "clicked", "activate", "drag-begin")
|
|
11
|
-
* @param args - Additional signal arguments
|
|
11
|
+
* @param args - Additional signal arguments as GValues
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```tsx
|
|
15
15
|
* import { fireEvent } from "@gtkx/testing";
|
|
16
|
+
* import { Value } from "@gtkx/ffi/gobject";
|
|
16
17
|
*
|
|
17
18
|
* // Emit signal on widget
|
|
18
19
|
* await fireEvent(widget, "clicked");
|
|
19
20
|
*
|
|
20
21
|
* // Emit signal on gesture controller
|
|
21
22
|
* const gesture = widget.observeControllers().getObject(0) as Gtk.GestureDrag;
|
|
22
|
-
* await fireEvent(gesture, "drag-begin",
|
|
23
|
+
* await fireEvent(gesture, "drag-begin", Value.newFromDouble(100), Value.newFromDouble(100));
|
|
23
24
|
* ```
|
|
24
25
|
*
|
|
25
26
|
* @see {@link userEvent} for high-level user interactions
|
|
26
27
|
*/
|
|
27
28
|
export const fireEvent = async (element, signalName, ...args) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
], { type: "undefined" });
|
|
29
|
+
const gtype = typeFromName(element.constructor.glibTypeName);
|
|
30
|
+
const signalId = signalLookup(signalName, gtype);
|
|
31
|
+
const instanceValue = Value.newFromObject(element);
|
|
32
|
+
signalEmitv([instanceValue, ...args], signalId, 0, null);
|
|
33
33
|
await tick();
|
|
34
34
|
};
|
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
|
@@ -6,6 +6,13 @@ export type TabOptions = {
|
|
|
6
6
|
/** Navigate backwards (Shift+Tab) instead of forwards */
|
|
7
7
|
shift?: boolean;
|
|
8
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* Pointer input actions for simulating mouse interactions.
|
|
11
|
+
*
|
|
12
|
+
* - `"click"` or `"[MouseLeft]"`: Full click (press + release)
|
|
13
|
+
* - `"down"` or `"[MouseLeft>]"`: Press and hold
|
|
14
|
+
* - `"up"` or `"[/MouseLeft]"`: Release
|
|
15
|
+
*/
|
|
9
16
|
export type PointerInput = "click" | "down" | "up" | "[MouseLeft]" | "[MouseLeft>]" | "[/MouseLeft]";
|
|
10
17
|
/**
|
|
11
18
|
* User interaction utilities for testing.
|
|
@@ -39,13 +46,13 @@ export declare const userEvent: {
|
|
|
39
46
|
/**
|
|
40
47
|
* Double-clicks a widget.
|
|
41
48
|
*
|
|
42
|
-
* Emits
|
|
49
|
+
* Emits pressed/released signals with n_press=1, then n_press=2.
|
|
43
50
|
*/
|
|
44
51
|
dblClick: (element: Gtk.Widget) => Promise<void>;
|
|
45
52
|
/**
|
|
46
53
|
* Triple-clicks a widget.
|
|
47
54
|
*
|
|
48
|
-
* Emits
|
|
55
|
+
* Emits pressed/released signals with n_press=1, 2, then 3. Useful for text selection.
|
|
49
56
|
*/
|
|
50
57
|
tripleClick: (element: Gtk.Widget) => Promise<void>;
|
|
51
58
|
/**
|
package/dist/user-event.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getNativeObject } from "@gtkx/ffi";
|
|
2
2
|
import * as Gdk from "@gtkx/ffi/gdk";
|
|
3
|
+
import { signalEmitv, signalLookup, typeFromName, Value } from "@gtkx/ffi/gobject";
|
|
3
4
|
import * as Gtk from "@gtkx/ffi/gtk";
|
|
4
|
-
import { call, createRef } from "@gtkx/native";
|
|
5
5
|
import { fireEvent } from "./fire-event.js";
|
|
6
6
|
import { tick } from "./timing.js";
|
|
7
7
|
import { isEditable } from "./widget.js";
|
|
@@ -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;
|
|
@@ -166,36 +177,18 @@ const getOrCreateController = (element, controllerType) => {
|
|
|
166
177
|
element.addController(controller);
|
|
167
178
|
return controller;
|
|
168
179
|
};
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
if (arg.type === "float") {
|
|
173
|
-
return { type: { type: "float", size: 64 }, value: arg.value };
|
|
174
|
-
}
|
|
175
|
-
return { type: { type: "int", size: 32, unsigned: true }, value: arg.value };
|
|
176
|
-
});
|
|
177
|
-
const ffiArgs = [
|
|
178
|
-
{ type: { type: "gobject", ownership: "borrowed" }, value: target.handle },
|
|
179
|
-
{ type: { type: "string", ownership: "borrowed" }, value: signalName },
|
|
180
|
-
...signalArgs,
|
|
181
|
-
];
|
|
182
|
-
if (SIGNALS_WITH_RETURN_VALUE.has(signalName)) {
|
|
183
|
-
const returnRef = createRef(0);
|
|
184
|
-
ffiArgs.push({
|
|
185
|
-
type: { type: "ref", innerType: { type: "int", size: 32, unsigned: false } },
|
|
186
|
-
value: returnRef,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
call("libgobject-2.0.so.0", "g_signal_emit_by_name", ffiArgs, { type: "undefined" });
|
|
180
|
+
const getSignalId = (target, signalName) => {
|
|
181
|
+
const gtype = typeFromName(target.constructor.glibTypeName);
|
|
182
|
+
return signalLookup(signalName, gtype);
|
|
190
183
|
};
|
|
191
184
|
const hover = async (element) => {
|
|
192
185
|
const controller = getOrCreateController(element, Gtk.EventControllerMotion);
|
|
193
|
-
|
|
186
|
+
signalEmitv([Value.newFromObject(controller), Value.newFromDouble(0), Value.newFromDouble(0)], getSignalId(controller, "enter"), 0, null);
|
|
194
187
|
await tick();
|
|
195
188
|
};
|
|
196
189
|
const unhover = async (element) => {
|
|
197
190
|
const controller = getOrCreateController(element, Gtk.EventControllerMotion);
|
|
198
|
-
|
|
191
|
+
signalEmitv([Value.newFromObject(controller)], getSignalId(controller, "leave"), 0, null);
|
|
199
192
|
await tick();
|
|
200
193
|
};
|
|
201
194
|
const KEY_MAP = {
|
|
@@ -256,12 +249,20 @@ const parseKeyboardInput = (input) => {
|
|
|
256
249
|
}
|
|
257
250
|
return actions;
|
|
258
251
|
};
|
|
252
|
+
let gdkModifierType = null;
|
|
259
253
|
const keyboard = async (element, input) => {
|
|
254
|
+
gdkModifierType ??= typeFromName("GdkModifierType");
|
|
260
255
|
const controller = getOrCreateController(element, Gtk.EventControllerKey);
|
|
261
256
|
const actions = parseKeyboardInput(input);
|
|
262
257
|
for (const action of actions) {
|
|
263
258
|
const signalName = action.press ? "key-pressed" : "key-released";
|
|
264
|
-
|
|
259
|
+
const returnValue = action.press ? Value.newFromBoolean(false) : null;
|
|
260
|
+
signalEmitv([
|
|
261
|
+
Value.newFromObject(controller),
|
|
262
|
+
Value.newFromUint(action.keyval),
|
|
263
|
+
Value.newFromUint(0),
|
|
264
|
+
Value.newFromFlags(gdkModifierType, 0),
|
|
265
|
+
], getSignalId(controller, signalName), 0, returnValue);
|
|
265
266
|
if (action.press && action.keyval === Gdk.KEY_Return && isEditable(element)) {
|
|
266
267
|
await fireEvent(element, "activate");
|
|
267
268
|
}
|
|
@@ -270,15 +271,27 @@ const keyboard = async (element, input) => {
|
|
|
270
271
|
};
|
|
271
272
|
const pointer = async (element, input) => {
|
|
272
273
|
const controller = getOrCreateController(element, Gtk.GestureClick);
|
|
274
|
+
const pressedArgs = [
|
|
275
|
+
Value.newFromObject(controller),
|
|
276
|
+
Value.newFromInt(1),
|
|
277
|
+
Value.newFromDouble(0),
|
|
278
|
+
Value.newFromDouble(0),
|
|
279
|
+
];
|
|
280
|
+
const releasedArgs = [
|
|
281
|
+
Value.newFromObject(controller),
|
|
282
|
+
Value.newFromInt(1),
|
|
283
|
+
Value.newFromDouble(0),
|
|
284
|
+
Value.newFromDouble(0),
|
|
285
|
+
];
|
|
273
286
|
if (input === "[MouseLeft]" || input === "click") {
|
|
274
|
-
|
|
275
|
-
|
|
287
|
+
signalEmitv(pressedArgs, getSignalId(controller, "pressed"), 0, null);
|
|
288
|
+
signalEmitv(releasedArgs, getSignalId(controller, "released"), 0, null);
|
|
276
289
|
}
|
|
277
290
|
else if (input === "[MouseLeft>]" || input === "down") {
|
|
278
|
-
|
|
291
|
+
signalEmitv(pressedArgs, getSignalId(controller, "pressed"), 0, null);
|
|
279
292
|
}
|
|
280
293
|
else if (input === "[/MouseLeft]" || input === "up") {
|
|
281
|
-
|
|
294
|
+
signalEmitv(releasedArgs, getSignalId(controller, "released"), 0, null);
|
|
282
295
|
}
|
|
283
296
|
await tick();
|
|
284
297
|
};
|
|
@@ -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,14 +36,13 @@
|
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@gtkx/ffi": "0.
|
|
40
|
-
"@gtkx/
|
|
41
|
-
"@gtkx/react": "0.14.0"
|
|
39
|
+
"@gtkx/ffi": "0.16.0",
|
|
40
|
+
"@gtkx/react": "0.16.0"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"@types/react-reconciler": "^0.32.3",
|
|
45
44
|
"react-reconciler": "^0.33.0",
|
|
46
|
-
"@gtkx/vitest": "0.
|
|
45
|
+
"@gtkx/vitest": "0.16.0"
|
|
47
46
|
},
|
|
48
47
|
"scripts": {
|
|
49
48
|
"build": "tsc -b && cp ../../README.md .",
|