@gtkx/testing 1.6.0 → 2.0.0-beta.10
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 +47 -44
- package/dist/accessible-native.d.ts +1 -1
- package/dist/accessible-native.d.ts.map +1 -1
- package/dist/accessible-native.js +29 -8
- package/dist/accessible-native.js.map +1 -1
- package/dist/build-queries.d.ts +9 -9
- package/dist/build-queries.d.ts.map +1 -1
- package/dist/build-queries.js +2 -1
- package/dist/build-queries.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -3
- package/dist/config.js.map +1 -1
- package/dist/fire-event.d.ts +3 -3
- package/dist/fire-event.d.ts.map +1 -1
- package/dist/fire-event.js +14 -4
- package/dist/fire-event.js.map +1 -1
- package/dist/matchers.d.ts +52 -56
- package/dist/matchers.d.ts.map +1 -1
- package/dist/matchers.js +4 -16
- package/dist/matchers.js.map +1 -1
- package/dist/queries.d.ts +37 -133
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +48 -136
- package/dist/queries.js.map +1 -1
- package/dist/query-helpers.d.ts +2 -2
- package/dist/query-helpers.d.ts.map +1 -1
- package/dist/query-helpers.js +10 -3
- package/dist/query-helpers.js.map +1 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +4 -0
- package/dist/render.js.map +1 -1
- package/dist/role-helpers.d.ts +1 -1
- package/dist/role-helpers.d.ts.map +1 -1
- package/dist/role-helpers.js +2 -1
- package/dist/role-helpers.js.map +1 -1
- package/dist/screenshot.d.ts +1 -1
- package/dist/screenshot.d.ts.map +1 -1
- package/dist/screenshot.js +26 -8
- package/dist/screenshot.js.map +1 -1
- package/dist/suggestions.d.ts +1 -1
- package/dist/suggestions.d.ts.map +1 -1
- package/dist/suggestions.js +3 -1
- package/dist/suggestions.js.map +1 -1
- package/dist/traversal.d.ts +4 -4
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +25 -7
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +10 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/adjustment.d.ts +2 -14
- package/dist/user-event/adjustment.d.ts.map +1 -1
- package/dist/user-event/adjustment.js +2 -14
- package/dist/user-event/adjustment.js.map +1 -1
- package/dist/user-event/click.d.ts +20 -45
- package/dist/user-event/click.d.ts.map +1 -1
- package/dist/user-event/click.js +31 -50
- package/dist/user-event/click.js.map +1 -1
- package/dist/user-event/controller.d.ts +5 -5
- package/dist/user-event/controller.d.ts.map +1 -1
- package/dist/user-event/controller.js +5 -2
- package/dist/user-event/controller.js.map +1 -1
- package/dist/user-event/gesture.d.ts +9 -43
- package/dist/user-event/gesture.d.ts.map +1 -1
- package/dist/user-event/gesture.js +9 -43
- package/dist/user-event/gesture.js.map +1 -1
- package/dist/user-event/index.d.ts +38 -107
- package/dist/user-event/index.d.ts.map +1 -1
- package/dist/user-event/index.js +29 -30
- package/dist/user-event/index.js.map +1 -1
- package/dist/user-event/keyboard.d.ts +1 -1
- package/dist/user-event/keyboard.d.ts.map +1 -1
- package/dist/user-event/keyboard.js +24 -3
- package/dist/user-event/keyboard.js.map +1 -1
- package/dist/user-event/list-row-click.d.ts +1 -1
- package/dist/user-event/list-row-click.d.ts.map +1 -1
- package/dist/user-event/list-row-click.js +2 -1
- package/dist/user-event/list-row-click.js.map +1 -1
- package/dist/user-event/pointer.d.ts.map +1 -1
- package/dist/user-event/pointer.js +9 -11
- package/dist/user-event/pointer.js.map +1 -1
- package/dist/user-event/selection.d.ts +4 -20
- package/dist/user-event/selection.d.ts.map +1 -1
- package/dist/user-event/selection.js +11 -23
- package/dist/user-event/selection.js.map +1 -1
- package/dist/user-event/text.d.ts +5 -34
- package/dist/user-event/text.d.ts.map +1 -1
- package/dist/user-event/text.js +5 -34
- package/dist/user-event/text.js.map +1 -1
- package/dist/wait-for.d.ts +2 -2
- package/dist/wait-for.d.ts.map +1 -1
- package/dist/wait-for.js +6 -4
- package/dist/wait-for.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +4 -3
- package/dist/widget-accessible-properties.d.ts.map +1 -1
- package/dist/widget-accessible-properties.js +38 -51
- package/dist/widget-accessible-properties.js.map +1 -1
- package/dist/widget-getters.d.ts +7 -9
- package/dist/widget-getters.d.ts.map +1 -1
- package/dist/widget-getters.js.map +1 -1
- package/dist/widget-target.d.ts +4 -0
- package/dist/widget-target.d.ts.map +1 -0
- package/dist/widget-target.js +9 -0
- package/dist/widget-target.js.map +1 -0
- package/package.json +17 -10
- package/src/accessible-native.ts +45 -9
- package/src/build-queries.ts +60 -30
- package/src/config.ts +1 -3
- package/src/fire-event.ts +32 -8
- package/src/matchers.ts +63 -85
- package/src/queries.ts +94 -156
- package/src/query-helpers.ts +17 -9
- package/src/render.tsx +7 -2
- package/src/role-helpers.ts +3 -1
- package/src/screenshot.ts +49 -8
- package/src/suggestions.ts +3 -1
- package/src/traversal.ts +35 -11
- package/src/types.ts +14 -10
- package/src/user-event/adjustment.ts +2 -14
- package/src/user-event/click.ts +40 -58
- package/src/user-event/controller.ts +8 -5
- package/src/user-event/gesture.ts +9 -43
- package/src/user-event/index.ts +149 -132
- package/src/user-event/keyboard.ts +33 -4
- package/src/user-event/list-row-click.ts +2 -2
- package/src/user-event/pointer.ts +11 -15
- package/src/user-event/selection.ts +15 -25
- package/src/user-event/text.ts +5 -34
- package/src/wait-for.ts +9 -6
- package/src/widget-accessible-properties.ts +61 -69
- package/src/widget-getters.ts +11 -13
- package/src/widget-target.ts +11 -0
package/src/user-event/index.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
2
|
import { delay } from "../timers.js";
|
|
3
|
+
import { requireWidget } from "../widget-target.js";
|
|
3
4
|
import { scroll, slide } from "./adjustment.js";
|
|
4
5
|
import { click, dblClick, tripleClick } from "./click.js";
|
|
5
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
drag,
|
|
8
|
+
dragAndDrop,
|
|
9
|
+
drop,
|
|
10
|
+
hover,
|
|
11
|
+
longPress,
|
|
12
|
+
rotate,
|
|
13
|
+
swipe,
|
|
14
|
+
unhover,
|
|
15
|
+
zoom,
|
|
16
|
+
} from "./gesture.js";
|
|
6
17
|
import { keyboard, tab } from "./keyboard.js";
|
|
7
18
|
import { pointer, type PointerInput } from "./pointer.js";
|
|
8
19
|
import { deselectOptions, selectOptions } from "./selection.js";
|
|
@@ -15,130 +26,132 @@ type UserEventOptions = {
|
|
|
15
26
|
delay?: number | null | undefined;
|
|
16
27
|
};
|
|
17
28
|
|
|
18
|
-
/**
|
|
19
|
-
* The set of user interaction helpers exposed by {@link userEvent}, covering clicks, typing,
|
|
20
|
-
* keyboard, pointer, gestures, selection, and scrolling.
|
|
21
|
-
*/
|
|
29
|
+
/** User interactions exposed by {@link userEvent}. */
|
|
22
30
|
type UserEvent = {
|
|
23
|
-
/**
|
|
24
|
-
* Returns a fresh instance whose helpers share one keyboard and pointer state, so held modifiers
|
|
25
|
-
* and buttons carry across its calls but not across instances.
|
|
26
|
-
*/
|
|
31
|
+
/** Creates an instance with shared keyboard and pointer state. */
|
|
27
32
|
setup: (options?: UserEventOptions) => UserEvent;
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Inserts the given text, or the clipboard's text, at an editable widget's cursor, deleting the
|
|
76
|
-
* text the widget has selected first, the way GTK4 does.
|
|
77
|
-
*/
|
|
78
|
-
paste: typeof paste;
|
|
79
|
-
/**
|
|
80
|
-
* Selects the items at those positions in a view or drop-down, or selects the indexed children of
|
|
81
|
-
* a list box or flow box through their container, without activating them.
|
|
82
|
-
*/
|
|
33
|
+
/** Activates or presses and releases a widget. */
|
|
34
|
+
click: (
|
|
35
|
+
widget: Gtk.Accessible,
|
|
36
|
+
...args: Parameters<typeof click> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
37
|
+
) => Promise<void>;
|
|
38
|
+
/** Delivers a double-click gesture. */
|
|
39
|
+
dblClick: (
|
|
40
|
+
widget: Gtk.Accessible,
|
|
41
|
+
...args: Parameters<typeof dblClick> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
42
|
+
) => Promise<void>;
|
|
43
|
+
/** Delivers a triple-click gesture. */
|
|
44
|
+
tripleClick: (
|
|
45
|
+
widget: Gtk.Accessible,
|
|
46
|
+
...args: Parameters<typeof tripleClick> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
47
|
+
) => Promise<void>;
|
|
48
|
+
/** Moves focus forward or backward within the root. */
|
|
49
|
+
tab: (
|
|
50
|
+
widget: Gtk.Accessible,
|
|
51
|
+
...args: Parameters<typeof tab> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
52
|
+
) => Promise<void>;
|
|
53
|
+
/** Types into an editable widget. */
|
|
54
|
+
type: (
|
|
55
|
+
widget: Gtk.Accessible,
|
|
56
|
+
...args: Parameters<typeof type> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
57
|
+
) => Promise<void>;
|
|
58
|
+
/** Deletes all text from an editable widget. */
|
|
59
|
+
clear: (
|
|
60
|
+
widget: Gtk.Accessible,
|
|
61
|
+
...args: Parameters<typeof clear> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
62
|
+
) => Promise<void>;
|
|
63
|
+
/** Copies the current selection. */
|
|
64
|
+
copy: (
|
|
65
|
+
widget: Gtk.Accessible,
|
|
66
|
+
...args: Parameters<typeof copy> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
67
|
+
) => Promise<void>;
|
|
68
|
+
/** Cuts the current selection. */
|
|
69
|
+
cut: (
|
|
70
|
+
widget: Gtk.Accessible,
|
|
71
|
+
...args: Parameters<typeof cut> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
72
|
+
) => Promise<void>;
|
|
73
|
+
/** Pastes text or clipboard contents. */
|
|
74
|
+
paste: (
|
|
75
|
+
widget: Gtk.Accessible,
|
|
76
|
+
...args: Parameters<typeof paste> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
77
|
+
) => Promise<void>;
|
|
78
|
+
/** Selects positions without activating them. */
|
|
83
79
|
selectOptions: typeof selectOptions;
|
|
84
|
-
/** Unselects
|
|
80
|
+
/** Unselects positions without activating them. */
|
|
85
81
|
deselectOptions: typeof deselectOptions;
|
|
86
82
|
/** Emits a motion `enter` on the widget, adding a motion controller when it has none. */
|
|
87
|
-
hover:
|
|
83
|
+
hover: (
|
|
84
|
+
widget: Gtk.Accessible,
|
|
85
|
+
...args: Parameters<typeof hover> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
86
|
+
) => Promise<void>;
|
|
88
87
|
/** Emits a motion `leave` on the widget, adding a motion controller when it has none. */
|
|
89
|
-
unhover:
|
|
88
|
+
unhover: (
|
|
89
|
+
widget: Gtk.Accessible,
|
|
90
|
+
...args: Parameters<typeof unhover> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
91
|
+
) => Promise<void>;
|
|
90
92
|
/** Emits `angle-changed` on the widget's rotate gestures. */
|
|
91
|
-
rotate:
|
|
93
|
+
rotate: (
|
|
94
|
+
widget: Gtk.Accessible,
|
|
95
|
+
...args: Parameters<typeof rotate> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
96
|
+
) => Promise<void>;
|
|
92
97
|
/** Emits `scale-changed` on the widget's zoom gestures. */
|
|
93
|
-
zoom:
|
|
98
|
+
zoom: (
|
|
99
|
+
widget: Gtk.Accessible,
|
|
100
|
+
...args: Parameters<typeof zoom> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
101
|
+
) => Promise<void>;
|
|
94
102
|
/** Emits `swipe` with the given velocity on the widget's swipe gestures. */
|
|
95
|
-
swipe:
|
|
103
|
+
swipe: (
|
|
104
|
+
widget: Gtk.Accessible,
|
|
105
|
+
...args: Parameters<typeof swipe> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
106
|
+
) => Promise<void>;
|
|
96
107
|
/** Emits `pressed` at the given point on the widget's long-press gestures. */
|
|
97
|
-
longPress:
|
|
108
|
+
longPress: (
|
|
109
|
+
widget: Gtk.Accessible,
|
|
110
|
+
...args: Parameters<typeof longPress> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
111
|
+
) => Promise<void>;
|
|
98
112
|
/** Runs a begin, update, and end sequence on the widget's drag gestures, ending at the given offset. */
|
|
99
|
-
drag:
|
|
113
|
+
drag: (
|
|
114
|
+
widget: Gtk.Accessible,
|
|
115
|
+
...args: Parameters<typeof drag> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
116
|
+
) => Promise<void>;
|
|
100
117
|
/** Emits `drop` with the given content on the widget's drop targets. */
|
|
101
|
-
drop:
|
|
118
|
+
drop: (
|
|
119
|
+
widget: Gtk.Accessible,
|
|
120
|
+
...args: Parameters<typeof drop> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
121
|
+
) => Promise<void>;
|
|
102
122
|
/** Requires a drag source on the source widget, then emits `drop` with the content on the target's drop targets. */
|
|
103
|
-
dragAndDrop:
|
|
123
|
+
dragAndDrop: (
|
|
124
|
+
source: Gtk.Accessible,
|
|
125
|
+
target: Gtk.Accessible,
|
|
126
|
+
...args: Parameters<typeof dragAndDrop> extends [Gtk.Widget, Gtk.Widget, ...infer Args] ? Args : never
|
|
127
|
+
) => Promise<void>;
|
|
104
128
|
/** Emits a jump `change-value` on a Gtk.Range so it moves to the given value. */
|
|
105
|
-
slide:
|
|
129
|
+
slide: (
|
|
130
|
+
widget: Gtk.Accessible,
|
|
131
|
+
...args: Parameters<typeof slide> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
132
|
+
) => Promise<void>;
|
|
106
133
|
/** Adds the delta to the adjustments of the widget itself, or of its nearest scrollable ancestor. */
|
|
107
|
-
scroll:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
* instance, so the delegate stands ahead of the widget in the chain. A shortcut controller whose
|
|
116
|
-
* scope is not local runs where it registered instead, the root for a global one and the nearest
|
|
117
|
-
* `Gtk.ShortcutManager` for a managed one, so it fires wherever focus sits inside that subtree
|
|
118
|
-
* and never at its own widget, while a shortcut whose widget is insensitive or unmapped stays
|
|
119
|
-
* inert wherever it sits. The first controller that handles a press ends the chain, and a
|
|
120
|
-
* `Gdk.KEY_Return` press none of them handled reaches an editable widget's activate handler.
|
|
121
|
-
* Built-in key bindings take part, since GTK4 carries them on a shortcut controller: a
|
|
122
|
-
* `Gtk.Text`'s arrow keys or a `Gtk.TextView`'s undo can consume a press before an ancestor
|
|
123
|
-
* sees it. Key controllers GTK4 attaches itself are the exception, since they read a GDK event
|
|
124
|
-
* that off-screen synthesis cannot produce, so only the key controllers the tree connected a
|
|
125
|
-
* `key-pressed` or `key-released` handler to take part. Held modifiers carry across calls.
|
|
126
|
-
*/
|
|
127
|
-
keyboard: (widget: Gtk.Widget, input: string) => Promise<void>;
|
|
128
|
-
/**
|
|
129
|
-
* Applies a pointer token to the click gestures the widget already carries, tracking whether the
|
|
130
|
-
* left button is held across calls. On a widget whose click GTK4 implements itself, the release
|
|
131
|
-
* also applies GTK's own outcome, the way {@link UserEvent.click} does, and a column-view cell
|
|
132
|
-
* or the row carrying the column headers passes the token to the row or view behind it.
|
|
133
|
-
*/
|
|
134
|
-
pointer: (widget: Gtk.Widget, input: PointerInput) => Promise<void>;
|
|
134
|
+
scroll: (
|
|
135
|
+
widget: Gtk.Accessible,
|
|
136
|
+
...args: Parameters<typeof scroll> extends [Gtk.Widget, ...infer Args] ? Args : never
|
|
137
|
+
) => Promise<void>;
|
|
138
|
+
/** Sends a key sequence through GTK's propagation chain. */
|
|
139
|
+
keyboard: (widget: Gtk.Accessible, input: string) => Promise<void>;
|
|
140
|
+
/** Applies a pointer token while preserving held-button state. */
|
|
141
|
+
pointer: (widget: Gtk.Accessible, input: PointerInput) => Promise<void>;
|
|
135
142
|
};
|
|
136
143
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
const onWidget =
|
|
145
|
+
<Args extends unknown[]>(helper: (widget: Gtk.Widget, ...args: Args) => Promise<void>) =>
|
|
146
|
+
(target: Gtk.Accessible, ...args: Args): Promise<void> =>
|
|
147
|
+
helper(requireWidget(target), ...args);
|
|
148
|
+
|
|
149
|
+
const onWidgetPair =
|
|
150
|
+
<Args extends unknown[]>(helper: (source: Gtk.Widget, target: Gtk.Widget, ...args: Args) => Promise<void>) =>
|
|
151
|
+
(source: Gtk.Accessible, target: Gtk.Accessible, ...args: Args): Promise<void> =>
|
|
152
|
+
helper(requireWidget(source), requireWidget(target), ...args);
|
|
153
|
+
|
|
154
|
+
/** User interactions that dispatch GTK events and gestures. */
|
|
142
155
|
const userEvent: UserEvent = {
|
|
143
156
|
...createInstance(createInitialState(), {}),
|
|
144
157
|
setup: (options?: UserEventOptions): UserEvent => createInstance(createInitialState(), options ?? {}),
|
|
@@ -162,30 +175,34 @@ function createInstance(state: UserEventState, options: UserEventOptions): UserE
|
|
|
162
175
|
|
|
163
176
|
return {
|
|
164
177
|
setup: (overrides?: UserEventOptions): UserEvent => createInstance(state, { ...options, ...overrides }),
|
|
165
|
-
click: after(click),
|
|
166
|
-
dblClick: after(dblClick),
|
|
167
|
-
tripleClick: after(tripleClick),
|
|
168
|
-
tab: after(tab),
|
|
169
|
-
type: after(type),
|
|
170
|
-
clear: after(clear),
|
|
171
|
-
copy: after(copy),
|
|
172
|
-
cut: after(cut),
|
|
173
|
-
paste: after(paste),
|
|
174
|
-
selectOptions: after(selectOptions),
|
|
175
|
-
deselectOptions: after(deselectOptions),
|
|
176
|
-
hover: after(hover),
|
|
177
|
-
unhover: after(unhover),
|
|
178
|
-
rotate: after(rotate),
|
|
179
|
-
zoom: after(zoom),
|
|
180
|
-
swipe: after(swipe),
|
|
181
|
-
longPress: after(longPress),
|
|
182
|
-
drag: after(drag),
|
|
183
|
-
drop: after(drop),
|
|
184
|
-
dragAndDrop: after(dragAndDrop),
|
|
185
|
-
slide: after(slide),
|
|
186
|
-
scroll: after(scroll),
|
|
187
|
-
keyboard: after(
|
|
188
|
-
|
|
178
|
+
click: after(onWidget(click)),
|
|
179
|
+
dblClick: after(onWidget(dblClick)),
|
|
180
|
+
tripleClick: after(onWidget(tripleClick)),
|
|
181
|
+
tab: after(onWidget(tab)),
|
|
182
|
+
type: after(onWidget(type)),
|
|
183
|
+
clear: after(onWidget(clear)),
|
|
184
|
+
copy: after(onWidget(copy)),
|
|
185
|
+
cut: after(onWidget(cut)),
|
|
186
|
+
paste: after(onWidget(paste)),
|
|
187
|
+
selectOptions: after(onWidget(selectOptions)),
|
|
188
|
+
deselectOptions: after(onWidget(deselectOptions)),
|
|
189
|
+
hover: after(onWidget(hover)),
|
|
190
|
+
unhover: after(onWidget(unhover)),
|
|
191
|
+
rotate: after(onWidget(rotate)),
|
|
192
|
+
zoom: after(onWidget(zoom)),
|
|
193
|
+
swipe: after(onWidget(swipe)),
|
|
194
|
+
longPress: after(onWidget(longPress)),
|
|
195
|
+
drag: after(onWidget(drag)),
|
|
196
|
+
drop: after(onWidget(drop)),
|
|
197
|
+
dragAndDrop: after(onWidgetPair(dragAndDrop)),
|
|
198
|
+
slide: after(onWidget(slide)),
|
|
199
|
+
scroll: after(onWidget(scroll)),
|
|
200
|
+
keyboard: after(
|
|
201
|
+
onWidget((widget: Gtk.Widget, input: string): Promise<void> => keyboard(state, widget, input)),
|
|
202
|
+
),
|
|
203
|
+
pointer: after(
|
|
204
|
+
onWidget((widget: Gtk.Widget, input: PointerInput): Promise<void> => pointer(state, widget, input)),
|
|
205
|
+
),
|
|
189
206
|
};
|
|
190
207
|
}
|
|
191
208
|
|
|
@@ -18,6 +18,7 @@ type KeyAction = { keyval: number; isPress: boolean };
|
|
|
18
18
|
type ParseStep = { actions: KeyAction[]; next: number };
|
|
19
19
|
type KeyStopController = Gtk.EventControllerKey | Gtk.ShortcutController;
|
|
20
20
|
type KeyStop = { widget: Gtk.Widget; controller: KeyStopController };
|
|
21
|
+
type KeyTarget = { root: Gtk.Root | null; focus: Gtk.Widget | null };
|
|
21
22
|
|
|
22
23
|
const KEY_MAP: Record<string, number> = {
|
|
23
24
|
Enter: Gdk.KEY_Return,
|
|
@@ -65,7 +66,7 @@ const MODIFIER_KEYVAL_TO_MASK: Record<number, number> = {
|
|
|
65
66
|
[Gdk.KEY_Meta_R]: Gdk.ModifierType.META_MASK,
|
|
66
67
|
};
|
|
67
68
|
|
|
68
|
-
/** Moves focus within the widget's root
|
|
69
|
+
/** Moves focus within the widget's root. */
|
|
69
70
|
const tab = (widget: Gtk.Widget, options?: TabOptions): Promise<void> =>
|
|
70
71
|
wrapEvent(widget, () => {
|
|
71
72
|
const direction = options?.isShiftHeld ? Gtk.DirectionType.TAB_BACKWARD : Gtk.DirectionType.TAB_FORWARD;
|
|
@@ -366,9 +367,37 @@ const didStopHandlePress = (stop: KeyStop, keyval: number, modifiers: Gdk.Modifi
|
|
|
366
367
|
return controller.emit("key-pressed", keyval, 0, modifiers);
|
|
367
368
|
};
|
|
368
369
|
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
370
|
+
const keyTargetFor = (widget: Gtk.Widget): KeyTarget => {
|
|
371
|
+
const root = widget.getRoot();
|
|
372
|
+
|
|
373
|
+
return { root, focus: root instanceof Gtk.Window ? root.getFocus() : null };
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
const isKeyTargetInvalidated = (widget: Gtk.Widget, target: KeyTarget): boolean => {
|
|
377
|
+
const current = keyTargetFor(widget);
|
|
378
|
+
|
|
379
|
+
return current.root !== target.root || current.focus !== target.focus || !widget.getMapped();
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
const didHandlePress = (widget: Gtk.Widget, keyval: number, modifiers: Gdk.ModifierType): boolean => {
|
|
383
|
+
const target = keyTargetFor(widget);
|
|
384
|
+
|
|
385
|
+
if (didDispatchApplicationAccels(widget, keyval, modifiers)) {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (isKeyTargetInvalidated(widget, target)) {
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
for (const stop of keyPropagationChain(widget)) {
|
|
394
|
+
if (didStopHandlePress(stop, keyval, modifiers) || isKeyTargetInvalidated(widget, target)) {
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return false;
|
|
400
|
+
};
|
|
372
401
|
|
|
373
402
|
const emitKeyReleased = (widget: Gtk.Widget, keyval: number, modifiers: Gdk.ModifierType): void => {
|
|
374
403
|
for (const stop of keyPropagationChain(widget)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
1
|
import * as GLib from "@gtkx/gi/glib";
|
|
2
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
3
3
|
import { ancestors } from "../traversal.js";
|
|
4
4
|
import { callBooleanGetter, hasWidgetMethod } from "../widget-getters.js";
|
|
5
5
|
|
|
@@ -41,7 +41,7 @@ const applyRowPress = (row: Gtk.Widget, press: number): void => {
|
|
|
41
41
|
selectRow(row);
|
|
42
42
|
|
|
43
43
|
if (isRowActivatedByPress(row, press)) {
|
|
44
|
-
|
|
44
|
+
Gtk.Widget.prototype.activate.call(row);
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
-
import type { NativeClick } from "./native-click.js";
|
|
3
2
|
import type { UserEventState } from "./state.js";
|
|
4
|
-
import {
|
|
3
|
+
import { type DirectClick, directClickFor, emitSitePhase } from "./click.js";
|
|
5
4
|
import { wrapEvent } from "./event-wrapper.js";
|
|
6
|
-
import { isClickTransparent
|
|
5
|
+
import { isClickTransparent } from "./native-click.js";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* A pointer action token: a full click (`click`, `[MouseLeft]`), a button press (`down`,
|
|
10
9
|
* `[MouseLeft>]`), or a button release (`up`, `[/MouseLeft]`).
|
|
11
10
|
*/
|
|
12
11
|
type PointerInput = "click" | "down" | "up" | "[MouseLeft]" | "[MouseLeft>]" | "[/MouseLeft]";
|
|
13
|
-
type PointerTarget = { widget: Gtk.Widget;
|
|
12
|
+
type PointerTarget = { widget: Gtk.Widget; click: DirectClick };
|
|
14
13
|
|
|
15
14
|
const PRESS_INPUTS: Set<PointerInput> = new Set(["[MouseLeft>]", "down"]);
|
|
16
15
|
const RELEASE_INPUTS: Set<PointerInput> = new Set(["[/MouseLeft]", "up"]);
|
|
@@ -32,26 +31,23 @@ const pointerWidgetFor = (widget: Gtk.Widget): Gtk.Widget => {
|
|
|
32
31
|
return current;
|
|
33
32
|
};
|
|
34
33
|
|
|
35
|
-
const pointerGesturesFor = (widget: Gtk.Widget, native: NativeClick | null): Gtk.GestureClick[] =>
|
|
36
|
-
native === null ? clickGestures(widget) : getAuthoredClickGestures(widget);
|
|
37
|
-
|
|
38
34
|
const pointerTargetFor = (widget: Gtk.Widget): PointerTarget => {
|
|
39
35
|
const target = pointerWidgetFor(widget);
|
|
40
|
-
const native = nativeClickFor(target, true);
|
|
41
36
|
|
|
42
|
-
return { widget: target,
|
|
37
|
+
return { widget: target, click: directClickFor(target) };
|
|
43
38
|
};
|
|
44
39
|
|
|
45
|
-
const pressPointer = ({
|
|
46
|
-
|
|
40
|
+
const pressPointer = ({ click }: PointerTarget): void => {
|
|
41
|
+
emitSitePhase(click.sites, 1, "pressed");
|
|
47
42
|
};
|
|
48
43
|
|
|
49
|
-
const releasePointer = ({ widget,
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
const releasePointer = ({ widget, click }: PointerTarget): void => {
|
|
45
|
+
emitSitePhase(click.sites, 1, "released");
|
|
46
|
+
click.outcome?.(widget, 1);
|
|
52
47
|
};
|
|
53
48
|
|
|
54
|
-
const isPointerPressable = (target: PointerTarget): boolean =>
|
|
49
|
+
const isPointerPressable = (target: PointerTarget): boolean =>
|
|
50
|
+
target.click.outcome !== null || target.click.sites.some((site) => site.gestures.length > 0);
|
|
55
51
|
|
|
56
52
|
const applyPointerInput = (widget: Gtk.Widget, state: UserEventState, input: PointerInput): void => {
|
|
57
53
|
const target = pointerTargetFor(widget);
|
|
@@ -19,9 +19,7 @@ const SELECTABLE_ROLES: Set<Gtk.AccessibleRole> = new Set([
|
|
|
19
19
|
Gtk.AccessibleRole.LIST,
|
|
20
20
|
]);
|
|
21
21
|
|
|
22
|
-
const isSelectable = (widget: Gtk.Widget): boolean =>
|
|
23
|
-
return SELECTABLE_ROLES.has(widget.getAccessibleRole());
|
|
24
|
-
};
|
|
22
|
+
const isSelectable = (widget: Gtk.Widget): boolean => SELECTABLE_ROLES.has(widget.getAccessibleRole());
|
|
25
23
|
|
|
26
24
|
const selectListViewItems = (
|
|
27
25
|
selectionModel: Gtk.SelectionModel,
|
|
@@ -155,18 +153,17 @@ const runSelectionEvent = (
|
|
|
155
153
|
byRole(widget, valueArray);
|
|
156
154
|
});
|
|
157
155
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
runSelectionEvent(widget, values, selectInListView, selectByRole);
|
|
156
|
+
const requireWidget = (target: Gtk.Accessible): Gtk.Widget => {
|
|
157
|
+
if (!(target instanceof Gtk.Widget)) {
|
|
158
|
+
throw new TypeError("Cannot select options on a non-widget accessible");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return target;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/** Selects positions without activating them. */
|
|
165
|
+
const selectOptions = (widget: Gtk.Accessible, values: number | number[]): Promise<void> =>
|
|
166
|
+
runSelectionEvent(requireWidget(widget), values, selectInListView, selectByRole);
|
|
170
167
|
|
|
171
168
|
const deselectInListView = (widget: Gtk.ListView | Gtk.GridView | Gtk.ColumnView, valueArray: number[]): void => {
|
|
172
169
|
const selectionModel = requireSelectionModel(widget, "deselect");
|
|
@@ -186,15 +183,8 @@ const deselectByRole = (widget: Gtk.Widget, valueArray: number[]): void => {
|
|
|
186
183
|
applyIndexedChildren(widget, valueArray, unselectChildRow);
|
|
187
184
|
};
|
|
188
185
|
|
|
189
|
-
/**
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
* is left alone, and no child is activated.
|
|
193
|
-
*
|
|
194
|
-
* @throws When a view has no selection model, when the widget's role is none of COMBO_BOX, GRID, or
|
|
195
|
-
* LIST, or when it exposes no indexed children.
|
|
196
|
-
*/
|
|
197
|
-
const deselectOptions = (widget: Gtk.Widget, values: number | number[]): Promise<void> =>
|
|
198
|
-
runSelectionEvent(widget, values, deselectInListView, deselectByRole);
|
|
186
|
+
/** Unselects positions without activating them. */
|
|
187
|
+
const deselectOptions = (widget: Gtk.Accessible, values: number | number[]): Promise<void> =>
|
|
188
|
+
runSelectionEvent(requireWidget(widget), values, deselectInListView, deselectByRole);
|
|
199
189
|
|
|
200
190
|
export { selectOptions, deselectOptions };
|
package/src/user-event/text.ts
CHANGED
|
@@ -198,15 +198,7 @@ const runEditableEvent = (
|
|
|
198
198
|
action(widget);
|
|
199
199
|
});
|
|
200
200
|
|
|
201
|
-
/**
|
|
202
|
-
* Focuses the widget unless `shouldFocus` is false, applies any initial selection, and inserts the
|
|
203
|
-
* text at the cursor, deleting the text the widget has selected first, the way typing over a
|
|
204
|
-
* selection does in GTK4. Focusing works the way clicking into the widget does, leaving its text
|
|
205
|
-
* unselected: a `Gtk.Editable` takes its caret to the end of its text, a `Gtk.TextView` keeps the
|
|
206
|
-
* caret where it stands, and the replaced text stays on the widget's undo stack either way.
|
|
207
|
-
*
|
|
208
|
-
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
209
|
-
*/
|
|
201
|
+
/** Types into an editable widget. */
|
|
210
202
|
const type = (widget: Gtk.Widget, text: string, options?: TypeOptions): Promise<void> =>
|
|
211
203
|
runEditableEvent(widget, "Cannot type into element", (editable) => {
|
|
212
204
|
if (options?.shouldFocus ?? true) {
|
|
@@ -286,45 +278,24 @@ const clearEditable = (editable: EditableTarget): void => {
|
|
|
286
278
|
}
|
|
287
279
|
};
|
|
288
280
|
|
|
289
|
-
/**
|
|
290
|
-
* Focuses an editable widget and deletes its whole text through the widget's own editing API, so the
|
|
291
|
-
* deletion emits the signals an edit made by hand emits. Text a tag protects is detected before the
|
|
292
|
-
* deletion runs, leaving such a widget untouched. A widget that writes a new value back in response
|
|
293
|
-
* to the deletion, as an input mask does, is cleared successfully and keeps whatever it wrote.
|
|
294
|
-
*
|
|
295
|
-
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView, when it refuses edits, when
|
|
296
|
-
* a tag protects part of its text, or when a handler blocks the deletion.
|
|
297
|
-
*/
|
|
281
|
+
/** Deletes all text from an editable widget. */
|
|
298
282
|
const clear = (widget: Gtk.Widget): Promise<void> =>
|
|
299
283
|
runEditableEvent(widget, "Cannot clear element", clearEditable);
|
|
300
284
|
|
|
301
|
-
/**
|
|
302
|
-
* Writes an editable widget's selected text to its clipboard, or the empty string when nothing is selected.
|
|
303
|
-
*
|
|
304
|
-
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
305
|
-
*/
|
|
285
|
+
/** Copies the current selection. */
|
|
306
286
|
const copy = (widget: Gtk.Widget): Promise<void> =>
|
|
307
287
|
runEditableEvent(widget, "Cannot copy", (editable) => {
|
|
308
288
|
writeClipboardText(editable, readSelection(editable));
|
|
309
289
|
});
|
|
310
290
|
|
|
311
|
-
/**
|
|
312
|
-
* Writes an editable widget's selected text to its clipboard, then deletes that selection.
|
|
313
|
-
*
|
|
314
|
-
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
315
|
-
*/
|
|
291
|
+
/** Cuts the current selection. */
|
|
316
292
|
const cut = (widget: Gtk.Widget): Promise<void> =>
|
|
317
293
|
runEditableEvent(widget, "Cannot cut", (editable) => {
|
|
318
294
|
writeClipboardText(editable, readSelection(editable));
|
|
319
295
|
deleteSelection(editable);
|
|
320
296
|
});
|
|
321
297
|
|
|
322
|
-
/**
|
|
323
|
-
* Inserts the given text at an editable widget's cursor, reading the clipboard instead when no text
|
|
324
|
-
* is given, and deleting the text the widget has selected first, the way a paste does in GTK4.
|
|
325
|
-
*
|
|
326
|
-
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
327
|
-
*/
|
|
298
|
+
/** Pastes text or clipboard contents. */
|
|
328
299
|
const paste = async (widget: Gtk.Widget, text?: string): Promise<void> => {
|
|
329
300
|
if (!isEditable(widget)) {
|
|
330
301
|
throw new Error(`Cannot paste: ${EDITABLE_REQUIRED}`);
|
package/src/wait-for.ts
CHANGED
|
@@ -4,12 +4,13 @@ import { runWithActEnvironment } from "./act.js";
|
|
|
4
4
|
import { getConfig } from "./config.js";
|
|
5
5
|
import { timeoutError } from "./errors.js";
|
|
6
6
|
import { advanceFakeClock, delay, now } from "./timers.js";
|
|
7
|
+
import { requireWidget } from "./widget-target.js";
|
|
7
8
|
|
|
8
9
|
type PollResult<T> = { status: "resolved"; value: T } | { status: "timedout"; lastError: Error | null };
|
|
9
10
|
/** Widgets watched for removal; null counts as already removed. */
|
|
10
|
-
type RemovalTarget = Gtk.
|
|
11
|
+
type RemovalTarget = Gtk.Accessible | Gtk.Accessible[] | null;
|
|
11
12
|
/** The widgets to watch for removal, or a function re-read on every poll to locate them. */
|
|
12
|
-
type ElementOrCallback = Gtk.
|
|
13
|
+
type ElementOrCallback = Gtk.Accessible | Gtk.Accessible[] | (() => RemovalTarget);
|
|
13
14
|
|
|
14
15
|
const DEFAULT_INTERVAL = 50;
|
|
15
16
|
const ELEMENT_NOT_REMOVED = new Error("Element not yet removed");
|
|
@@ -102,10 +103,8 @@ const waitFor = <T>(callback: () => T | Promise<T>, options?: WaitForOptions): P
|
|
|
102
103
|
const getTarget = (elementOrCallback: ElementOrCallback): RemovalTarget =>
|
|
103
104
|
typeof elementOrCallback === "function" ? elementOrCallback() : elementOrCallback;
|
|
104
105
|
|
|
105
|
-
const isWidgetRemoved = (
|
|
106
|
-
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
106
|
+
const isWidgetRemoved = (target: Gtk.Accessible): boolean => {
|
|
107
|
+
const widget = requireWidget(target);
|
|
109
108
|
|
|
110
109
|
try {
|
|
111
110
|
return widget.getRoot() === null;
|
|
@@ -115,6 +114,10 @@ const isWidgetRemoved = (widget: Gtk.Widget | null): boolean => {
|
|
|
115
114
|
};
|
|
116
115
|
|
|
117
116
|
const isTargetRemoved = (target: RemovalTarget): boolean => {
|
|
117
|
+
if (target === null) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
118
121
|
if (Array.isArray(target)) {
|
|
119
122
|
return target.every((widget) => isWidgetRemoved(widget));
|
|
120
123
|
}
|