@gtkx/testing 1.0.0-rc.3 → 1.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/dist/act.d.ts +2 -0
- package/dist/act.d.ts.map +1 -1
- package/dist/act.js.map +1 -1
- package/dist/build-queries.d.ts.map +1 -1
- package/dist/build-queries.js +18 -7
- package/dist/build-queries.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/matchers.d.ts +44 -0
- package/dist/matchers.d.ts.map +1 -1
- package/dist/matchers.js.map +1 -1
- package/dist/pretty-widget.d.ts +2 -1
- package/dist/pretty-widget.d.ts.map +1 -1
- package/dist/pretty-widget.js +3 -3
- package/dist/pretty-widget.js.map +1 -1
- package/dist/queries.d.ts +1 -0
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js.map +1 -1
- package/dist/render.js +2 -2
- package/dist/render.js.map +1 -1
- package/dist/suggestions.d.ts +3 -0
- package/dist/suggestions.d.ts.map +1 -1
- package/dist/suggestions.js.map +1 -1
- package/dist/traversal.d.ts +5 -0
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +1 -0
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +43 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/adjustment.d.ts +13 -0
- package/dist/user-event/adjustment.d.ts.map +1 -1
- package/dist/user-event/adjustment.js +11 -0
- package/dist/user-event/adjustment.js.map +1 -1
- package/dist/user-event/click.d.ts +7 -0
- package/dist/user-event/click.d.ts.map +1 -1
- package/dist/user-event/click.js +7 -0
- package/dist/user-event/click.js.map +1 -1
- package/dist/user-event/controller.d.ts +29 -0
- package/dist/user-event/controller.d.ts.map +1 -1
- package/dist/user-event/controller.js +28 -0
- package/dist/user-event/controller.js.map +1 -1
- package/dist/user-event/gesture.d.ts +51 -0
- package/dist/user-event/gesture.d.ts.map +1 -1
- package/dist/user-event/gesture.js +47 -4
- package/dist/user-event/gesture.js.map +1 -1
- package/dist/user-event/index.d.ts +27 -0
- package/dist/user-event/index.d.ts.map +1 -1
- package/dist/user-event/index.js.map +1 -1
- package/dist/user-event/keyboard.d.ts +4 -2
- package/dist/user-event/keyboard.d.ts.map +1 -1
- package/dist/user-event/keyboard.js +13 -12
- package/dist/user-event/keyboard.js.map +1 -1
- package/dist/user-event/pointer.js +5 -5
- package/dist/user-event/pointer.js.map +1 -1
- package/dist/user-event/selection.d.ts +15 -0
- package/dist/user-event/selection.d.ts.map +1 -1
- package/dist/user-event/selection.js +15 -0
- package/dist/user-event/selection.js.map +1 -1
- package/dist/user-event/state.d.ts +1 -1
- package/dist/user-event/state.d.ts.map +1 -1
- package/dist/user-event/state.js +1 -1
- package/dist/user-event/state.js.map +1 -1
- package/dist/user-event/text.d.ts +30 -3
- package/dist/user-event/text.d.ts.map +1 -1
- package/dist/user-event/text.js +28 -1
- package/dist/user-event/text.js.map +1 -1
- package/dist/wait-for.d.ts +2 -0
- package/dist/wait-for.d.ts.map +1 -1
- package/dist/wait-for.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +17 -1
- package/dist/widget-accessible-properties.d.ts.map +1 -1
- package/dist/widget-accessible-properties.js +17 -0
- package/dist/widget-accessible-properties.js.map +1 -1
- package/package.json +7 -7
- package/src/act.ts +2 -0
- package/src/build-queries.ts +20 -8
- package/src/config.ts +4 -3
- package/src/errors.ts +2 -2
- package/src/matchers.ts +44 -0
- package/src/pretty-widget.ts +5 -4
- package/src/queries.ts +1 -0
- package/src/render.tsx +2 -2
- package/src/suggestions.ts +3 -0
- package/src/traversal.ts +5 -0
- package/src/types.ts +43 -5
- package/src/user-event/adjustment.ts +13 -0
- package/src/user-event/click.ts +7 -0
- package/src/user-event/controller.ts +29 -0
- package/src/user-event/gesture.ts +57 -6
- package/src/user-event/index.ts +27 -0
- package/src/user-event/keyboard.ts +18 -16
- package/src/user-event/pointer.ts +5 -5
- package/src/user-event/selection.ts +15 -0
- package/src/user-event/state.ts +2 -2
- package/src/user-event/text.ts +31 -4
- package/src/wait-for.ts +2 -0
- package/src/widget-accessible-properties.ts +17 -1
|
@@ -9,13 +9,17 @@ type DropContent = string | number | boolean | GObject.Value;
|
|
|
9
9
|
|
|
10
10
|
/** Options for a drop: the drop coordinates within the target. */
|
|
11
11
|
type DropOptions = {
|
|
12
|
+
/** Horizontal drop coordinate within the target, in pixels. */
|
|
12
13
|
x?: number;
|
|
14
|
+
/** Vertical drop coordinate within the target, in pixels. */
|
|
13
15
|
y?: number;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
/** A drag offset relative to the drag start point. */
|
|
17
19
|
type DragOffset = {
|
|
20
|
+
/** Horizontal distance from the drag start point, in pixels. */
|
|
18
21
|
x: number;
|
|
22
|
+
/** Vertical distance from the drag start point, in pixels. */
|
|
19
23
|
y: number;
|
|
20
24
|
};
|
|
21
25
|
|
|
@@ -24,9 +28,13 @@ type DragOffset = {
|
|
|
24
28
|
* explicit intermediate offsets emitted before the final one.
|
|
25
29
|
*/
|
|
26
30
|
type DragOptions = {
|
|
31
|
+
/** Horizontal coordinate the drag begins at; defaults to 0. */
|
|
27
32
|
startX?: number;
|
|
33
|
+
/** Vertical coordinate the drag begins at; defaults to 0. */
|
|
28
34
|
startY?: number;
|
|
35
|
+
/** Number of evenly interpolated drag updates, the last of which is the requested offset; defaults to 2. */
|
|
29
36
|
steps?: number;
|
|
37
|
+
/** Explicit intermediate offsets emitted before the requested one, used instead of `steps`. */
|
|
30
38
|
offsets?: DragOffset[];
|
|
31
39
|
};
|
|
32
40
|
|
|
@@ -37,8 +45,8 @@ type DragInstancePatch = {
|
|
|
37
45
|
|
|
38
46
|
type SavedDragState = {
|
|
39
47
|
instance: DragInstancePatch;
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
hasOwnStartPoint: boolean;
|
|
49
|
+
hasOwnOffset: boolean;
|
|
42
50
|
previousStartPoint: DragInstancePatch["getStartPoint"];
|
|
43
51
|
previousOffset: DragInstancePatch["getOffset"];
|
|
44
52
|
};
|
|
@@ -65,32 +73,56 @@ const buildDropValue = (content: DropContent): GObject.Value => {
|
|
|
65
73
|
});
|
|
66
74
|
};
|
|
67
75
|
|
|
76
|
+
/** Emits `enter` at the widget's origin on its motion controllers, adding one when it has none. */
|
|
68
77
|
const hover = (widget: Gtk.Widget): Promise<void> =>
|
|
69
78
|
dispatchOnOrCreateControllers(widget, Gtk.EventControllerMotion, (controller) => {
|
|
70
79
|
controller.emit("enter", 0, 0);
|
|
71
80
|
});
|
|
72
81
|
|
|
82
|
+
/** Emits `leave` on the widget's motion controllers, adding one when it has none. */
|
|
73
83
|
const unhover = (widget: Gtk.Widget): Promise<void> =>
|
|
74
84
|
dispatchOnOrCreateControllers(widget, Gtk.EventControllerMotion, (controller) => {
|
|
75
85
|
controller.emit("leave");
|
|
76
86
|
});
|
|
77
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Emits `angle-changed` on the widget's rotate gestures.
|
|
90
|
+
*
|
|
91
|
+
* @param angle Current angle, in radians.
|
|
92
|
+
* @param deltaAngle Difference from the angle the gesture started at; defaults to `angle`.
|
|
93
|
+
* @throws When the widget has no Gtk.GestureRotate.
|
|
94
|
+
*/
|
|
78
95
|
const rotate = (widget: Gtk.Widget, angle: number, deltaAngle: number = angle): Promise<void> =>
|
|
79
96
|
dispatchOnControllers(widget, Gtk.GestureRotate, (controller) => {
|
|
80
97
|
controller.emit("angle-changed", angle, deltaAngle);
|
|
81
98
|
},
|
|
82
99
|
);
|
|
83
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Emits `scale-changed` with the given scale delta on the widget's zoom gestures.
|
|
103
|
+
*
|
|
104
|
+
* @throws When the widget has no Gtk.GestureZoom.
|
|
105
|
+
*/
|
|
84
106
|
const zoom = (widget: Gtk.Widget, scale: number): Promise<void> =>
|
|
85
107
|
dispatchOnControllers(widget, Gtk.GestureZoom, (controller) => {
|
|
86
108
|
controller.emit("scale-changed", scale);
|
|
87
109
|
});
|
|
88
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Emits `swipe` with the given per-axis velocity, in pixels per second, on the widget's swipe gestures.
|
|
113
|
+
*
|
|
114
|
+
* @throws When the widget has no Gtk.GestureSwipe.
|
|
115
|
+
*/
|
|
89
116
|
const swipe = (widget: Gtk.Widget, velocityX: number, velocityY: number): Promise<void> =>
|
|
90
117
|
dispatchOnControllers(widget, Gtk.GestureSwipe, (controller) => {
|
|
91
118
|
controller.emit("swipe", velocityX, velocityY);
|
|
92
119
|
});
|
|
93
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Emits `pressed` at the given point in widget coordinates on the widget's long-press gestures.
|
|
123
|
+
*
|
|
124
|
+
* @throws When the widget has no Gtk.GestureLongPress.
|
|
125
|
+
*/
|
|
94
126
|
const longPress = (widget: Gtk.Widget, x = 0, y = 0): Promise<void> =>
|
|
95
127
|
dispatchOnControllers(widget, Gtk.GestureLongPress, (controller) => {
|
|
96
128
|
controller.emit("pressed", x, y);
|
|
@@ -99,13 +131,13 @@ const longPress = (widget: Gtk.Widget, x = 0, y = 0): Promise<void> =>
|
|
|
99
131
|
const restoreDragState = (saved: SavedDragState): void => {
|
|
100
132
|
const { instance } = saved;
|
|
101
133
|
|
|
102
|
-
if (saved.
|
|
134
|
+
if (saved.hasOwnStartPoint) {
|
|
103
135
|
instance.getStartPoint = saved.previousStartPoint;
|
|
104
136
|
} else {
|
|
105
137
|
delete instance.getStartPoint;
|
|
106
138
|
}
|
|
107
139
|
|
|
108
|
-
if (saved.
|
|
140
|
+
if (saved.hasOwnOffset) {
|
|
109
141
|
instance.getOffset = saved.previousOffset;
|
|
110
142
|
} else {
|
|
111
143
|
delete instance.getOffset;
|
|
@@ -117,8 +149,8 @@ const patchDragState = (controller: Gtk.GestureDrag, start: DragOffset, offset:
|
|
|
117
149
|
|
|
118
150
|
const saved: SavedDragState = {
|
|
119
151
|
instance,
|
|
120
|
-
|
|
121
|
-
|
|
152
|
+
hasOwnStartPoint: Object.hasOwn(instance, "getStartPoint"),
|
|
153
|
+
hasOwnOffset: Object.hasOwn(instance, "getOffset"),
|
|
122
154
|
previousStartPoint: instance.getStartPoint,
|
|
123
155
|
previousOffset: instance.getOffset,
|
|
124
156
|
};
|
|
@@ -177,6 +209,14 @@ const resolveDragUpdates = (dx: number, dy: number, options: DragOptions): DragO
|
|
|
177
209
|
return updates;
|
|
178
210
|
};
|
|
179
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Runs a `drag-begin`, `drag-update`, `drag-end` sequence ending at the offset `dx`, `dy` on the
|
|
214
|
+
* widget's drag gestures, overriding each gesture's start point and offset for the duration so
|
|
215
|
+
* handlers read the simulated values back.
|
|
216
|
+
*
|
|
217
|
+
* @throws When the widget is a Gtk.Range, whose slider reads pointer coordinates from the display,
|
|
218
|
+
* or when it has no Gtk.GestureDrag.
|
|
219
|
+
*/
|
|
180
220
|
const drag = async (widget: Gtk.Widget, dx: number, dy: number, options: DragOptions = {}): Promise<void> => {
|
|
181
221
|
if (widget instanceof Gtk.Range) {
|
|
182
222
|
throw new TypeError(
|
|
@@ -202,11 +242,22 @@ const emitDrop = (target: Gtk.Widget, content: DropContent, options: DropOptions
|
|
|
202
242
|
}
|
|
203
243
|
};
|
|
204
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Emits `drop` with the given content on every drop target attached to the widget.
|
|
247
|
+
*
|
|
248
|
+
* @throws When the widget has no Gtk.DropTarget.
|
|
249
|
+
*/
|
|
205
250
|
const drop = (widget: Gtk.Widget, content: DropContent, options: DropOptions = {}): Promise<void> =>
|
|
206
251
|
wrapEvent(widget, () => {
|
|
207
252
|
emitDrop(widget, content, options);
|
|
208
253
|
});
|
|
209
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Emits `drop` with the given content on the target's drop targets, after checking that the source
|
|
257
|
+
* carries a drag source.
|
|
258
|
+
*
|
|
259
|
+
* @throws When the source has no Gtk.DragSource, or the target no Gtk.DropTarget.
|
|
260
|
+
*/
|
|
210
261
|
const dragAndDrop = async (
|
|
211
262
|
source: Gtk.Widget,
|
|
212
263
|
target: Gtk.Widget,
|
package/src/user-event/index.ts
CHANGED
|
@@ -13,29 +13,56 @@ import { clear, copy, cut, paste, type } from "./text.js";
|
|
|
13
13
|
* keyboard, pointer, gestures, selection, and scrolling.
|
|
14
14
|
*/
|
|
15
15
|
type UserEvent = {
|
|
16
|
+
/**
|
|
17
|
+
* Clicks a button, toggles a switch, and otherwise activates the widget, falling back to a click
|
|
18
|
+
* gesture on its nearest clickable ancestor when activation does nothing.
|
|
19
|
+
*/
|
|
16
20
|
click: typeof click;
|
|
21
|
+
/** Emits a two-press click gesture on the widget. */
|
|
17
22
|
dblClick: typeof dblClick;
|
|
23
|
+
/** Emits a three-press click gesture on the widget. */
|
|
18
24
|
tripleClick: typeof tripleClick;
|
|
25
|
+
/** Moves focus within the widget's root, forward by default and backward with `isShiftHeld`. */
|
|
19
26
|
tab: typeof tab;
|
|
27
|
+
/** Focuses an editable widget, applies any initial selection, and inserts the text at the cursor. */
|
|
20
28
|
type: typeof type;
|
|
29
|
+
/** Empties an editable widget's text. */
|
|
21
30
|
clear: typeof clear;
|
|
31
|
+
/** Writes an editable widget's current selection to the clipboard. */
|
|
22
32
|
copy: typeof copy;
|
|
33
|
+
/** Writes an editable widget's current selection to the clipboard and deletes it. */
|
|
23
34
|
cut: typeof cut;
|
|
35
|
+
/** Inserts the given text, or the clipboard's text, at an editable widget's cursor. */
|
|
24
36
|
paste: typeof paste;
|
|
37
|
+
/** Selects the items at the given positions in a list view, drop-down, combo box, or list box. */
|
|
25
38
|
selectOptions: typeof selectOptions;
|
|
39
|
+
/** Deselects the items at the given positions in a list view or list box. */
|
|
26
40
|
deselectOptions: typeof deselectOptions;
|
|
41
|
+
/** Emits a motion `enter` on the widget, adding a motion controller when it has none. */
|
|
27
42
|
hover: typeof hover;
|
|
43
|
+
/** Emits a motion `leave` on the widget, adding a motion controller when it has none. */
|
|
28
44
|
unhover: typeof unhover;
|
|
45
|
+
/** Emits `angle-changed` on the widget's rotate gestures. */
|
|
29
46
|
rotate: typeof rotate;
|
|
47
|
+
/** Emits `scale-changed` on the widget's zoom gestures. */
|
|
30
48
|
zoom: typeof zoom;
|
|
49
|
+
/** Emits `swipe` with the given velocity on the widget's swipe gestures. */
|
|
31
50
|
swipe: typeof swipe;
|
|
51
|
+
/** Emits `pressed` at the given point on the widget's long-press gestures. */
|
|
32
52
|
longPress: typeof longPress;
|
|
53
|
+
/** Runs a begin, update, and end sequence on the widget's drag gestures, ending at the given offset. */
|
|
33
54
|
drag: typeof drag;
|
|
55
|
+
/** Emits `drop` with the given content on the widget's drop targets. */
|
|
34
56
|
drop: typeof drop;
|
|
57
|
+
/** Requires a drag source on the source widget, then emits `drop` with the content on the target's drop targets. */
|
|
35
58
|
dragAndDrop: typeof dragAndDrop;
|
|
59
|
+
/** Emits a jump `change-value` on a Gtk.Range so it moves to the given value. */
|
|
36
60
|
slide: typeof slide;
|
|
61
|
+
/** Adds the delta to the adjustments of the widget itself, or of its nearest scrollable ancestor. */
|
|
37
62
|
scroll: typeof scroll;
|
|
63
|
+
/** Sends a key sequence, dispatching matching shortcuts and tracking held modifiers across calls. */
|
|
38
64
|
keyboard: (widget: Gtk.Widget, input: string) => Promise<void>;
|
|
65
|
+
/** Applies a pointer token, tracking whether the left button is held across calls. */
|
|
39
66
|
pointer: (widget: Gtk.Widget, input: PointerInput) => Promise<void>;
|
|
40
67
|
};
|
|
41
68
|
|
|
@@ -6,12 +6,13 @@ import { fireEvent } from "../fire-event.js";
|
|
|
6
6
|
import { getOrCreateControllers } from "./controller.js";
|
|
7
7
|
import { wrapEvent } from "./event-wrapper.js";
|
|
8
8
|
|
|
9
|
-
/** Options for
|
|
9
|
+
/** Options for `userEvent.tab`. */
|
|
10
10
|
type TabOptions = {
|
|
11
|
-
|
|
11
|
+
/** Move focus backward instead of forward. */
|
|
12
|
+
isShiftHeld?: boolean;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
|
-
type KeyAction = { keyval: number;
|
|
15
|
+
type KeyAction = { keyval: number; isPress: boolean };
|
|
15
16
|
type ParseStep = { actions: KeyAction[]; next: number };
|
|
16
17
|
|
|
17
18
|
const KEY_MAP: Record<string, number> = {
|
|
@@ -58,9 +59,10 @@ const MODIFIER_KEYVAL_TO_MASK: Record<number, number> = {
|
|
|
58
59
|
[Gdk.KEY_Meta_R]: Gdk.ModifierType.META_MASK,
|
|
59
60
|
};
|
|
60
61
|
|
|
62
|
+
/** Moves focus within the widget's root, forward by default and backward when `isShiftHeld` is set. */
|
|
61
63
|
const tab = (widget: Gtk.Widget, options?: TabOptions): Promise<void> =>
|
|
62
64
|
wrapEvent(widget, () => {
|
|
63
|
-
const direction = options?.
|
|
65
|
+
const direction = options?.isShiftHeld ? Gtk.DirectionType.TAB_BACKWARD : Gtk.DirectionType.TAB_FORWARD;
|
|
64
66
|
const root = widget.getRoot();
|
|
65
67
|
|
|
66
68
|
if (root) {
|
|
@@ -68,7 +70,7 @@ const tab = (widget: Gtk.Widget, options?: TabOptions): Promise<void> =>
|
|
|
68
70
|
}
|
|
69
71
|
});
|
|
70
72
|
|
|
71
|
-
const parseKeyToken = (token: string): { keyval: number;
|
|
73
|
+
const parseKeyToken = (token: string): { keyval: number; isPress: boolean; isRelease: boolean } => {
|
|
72
74
|
let keyName = token;
|
|
73
75
|
let isPress = true;
|
|
74
76
|
let isRelease = true;
|
|
@@ -87,7 +89,7 @@ const parseKeyToken = (token: string): { keyval: number; press: boolean; release
|
|
|
87
89
|
throw new Error(`Unknown key: {${keyName}}`);
|
|
88
90
|
}
|
|
89
91
|
|
|
90
|
-
return { keyval,
|
|
92
|
+
return { keyval, isPress, isRelease };
|
|
91
93
|
};
|
|
92
94
|
|
|
93
95
|
const parseCharAt = (input: string, i: number): ParseStep => {
|
|
@@ -95,8 +97,8 @@ const parseCharAt = (input: string, i: number): ParseStep => {
|
|
|
95
97
|
|
|
96
98
|
return {
|
|
97
99
|
actions: [
|
|
98
|
-
{ keyval,
|
|
99
|
-
{ keyval,
|
|
100
|
+
{ keyval, isPress: true },
|
|
101
|
+
{ keyval, isPress: false },
|
|
100
102
|
],
|
|
101
103
|
next: i + 1,
|
|
102
104
|
};
|
|
@@ -109,15 +111,15 @@ const parseBraceAt = (input: string, i: number): ParseStep | null => {
|
|
|
109
111
|
return null;
|
|
110
112
|
}
|
|
111
113
|
|
|
112
|
-
const { keyval,
|
|
114
|
+
const { keyval, isPress, isRelease } = parseKeyToken(input.slice(i + 1, endBrace));
|
|
113
115
|
const actions: KeyAction[] = [];
|
|
114
116
|
|
|
115
|
-
if (
|
|
116
|
-
actions.push({ keyval,
|
|
117
|
+
if (isPress) {
|
|
118
|
+
actions.push({ keyval, isPress: true });
|
|
117
119
|
}
|
|
118
120
|
|
|
119
|
-
if (
|
|
120
|
-
actions.push({ keyval,
|
|
121
|
+
if (isRelease) {
|
|
122
|
+
actions.push({ keyval, isPress: false });
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
return { actions, next: endBrace + 1 };
|
|
@@ -151,7 +153,7 @@ const updateModifierState = (state: UserEventState, action: KeyAction): void =>
|
|
|
151
153
|
return;
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
if (action.
|
|
156
|
+
if (action.isPress) {
|
|
155
157
|
state.modifierState |= mask;
|
|
156
158
|
} else {
|
|
157
159
|
state.modifierState &= ~mask;
|
|
@@ -267,13 +269,13 @@ const applyKeyAction = async (
|
|
|
267
269
|
action: KeyAction,
|
|
268
270
|
): Promise<void> => {
|
|
269
271
|
updateModifierState(state, action);
|
|
270
|
-
const signalName = action.
|
|
272
|
+
const signalName = action.isPress ? "key-pressed" : "key-released";
|
|
271
273
|
|
|
272
274
|
for (const controller of controllers) {
|
|
273
275
|
controller.emit(signalName, action.keyval, 0, state.modifierState);
|
|
274
276
|
}
|
|
275
277
|
|
|
276
|
-
if (action.
|
|
278
|
+
if (action.isPress) {
|
|
277
279
|
await handleKeyPress(widget, action.keyval, state.modifierState);
|
|
278
280
|
}
|
|
279
281
|
};
|
|
@@ -20,21 +20,21 @@ const applyPointerInput = (widget: Gtk.Widget, state: UserEventState, input: Poi
|
|
|
20
20
|
if (CLICK_INPUTS.has(input)) {
|
|
21
21
|
emitPress(widget, controllers, 1);
|
|
22
22
|
emitRelease(widget, controllers, 1);
|
|
23
|
-
state.
|
|
23
|
+
state.isMouseLeftDown = false;
|
|
24
24
|
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
if (PRESS_INPUTS.has(input) && !state.
|
|
28
|
+
if (PRESS_INPUTS.has(input) && !state.isMouseLeftDown) {
|
|
29
29
|
emitPress(widget, controllers, 1);
|
|
30
|
-
state.
|
|
30
|
+
state.isMouseLeftDown = true;
|
|
31
31
|
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
if (RELEASE_INPUTS.has(input) && state.
|
|
35
|
+
if (RELEASE_INPUTS.has(input) && state.isMouseLeftDown) {
|
|
36
36
|
emitRelease(widget, controllers, 1);
|
|
37
|
-
state.
|
|
37
|
+
state.isMouseLeftDown = false;
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
|
|
@@ -134,6 +134,14 @@ const runSelectionEvent = (
|
|
|
134
134
|
byRole(widget, valueArray);
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Selects the items at the given positions through a list, grid, or column view's selection model,
|
|
139
|
+
* by setting the active item of a drop-down or combo box, or by selecting list box rows. An empty
|
|
140
|
+
* array clears a view's selection.
|
|
141
|
+
*
|
|
142
|
+
* @throws When a view has no selection model, when a combo box is given more than one position, or
|
|
143
|
+
* when the widget is neither a view nor something with the combo box or list role.
|
|
144
|
+
*/
|
|
137
145
|
const selectOptions = (widget: Gtk.Widget, values: number | number[]): Promise<void> =>
|
|
138
146
|
runSelectionEvent(widget, values, selectInListView, selectByRole);
|
|
139
147
|
|
|
@@ -153,6 +161,13 @@ const deselectByRole = (widget: Gtk.Widget, valueArray: number[]): void => {
|
|
|
153
161
|
applyListBoxRows(widget, valueArray, unselectListBoxRow);
|
|
154
162
|
};
|
|
155
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Unselects the items at the given positions in a list, grid, or column view, or the rows at those
|
|
166
|
+
* indices in a Gtk.ListBox.
|
|
167
|
+
*
|
|
168
|
+
* @throws When a view has no selection model, or when the widget is neither one of those views nor
|
|
169
|
+
* a Gtk.ListBox.
|
|
170
|
+
*/
|
|
156
171
|
const deselectOptions = (widget: Gtk.Widget, values: number | number[]): Promise<void> =>
|
|
157
172
|
runSelectionEvent(widget, values, deselectInListView, deselectByRole);
|
|
158
173
|
|
package/src/user-event/state.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
type UserEventState = {
|
|
2
2
|
modifierState: number;
|
|
3
|
-
|
|
3
|
+
isMouseLeftDown: boolean;
|
|
4
4
|
};
|
|
5
5
|
|
|
6
|
-
const createInitialState = (): UserEventState => ({ modifierState: 0,
|
|
6
|
+
const createInitialState = (): UserEventState => ({ modifierState: 0, isMouseLeftDown: false });
|
|
7
7
|
|
|
8
8
|
export { createInitialState, type UserEventState };
|
package/src/user-event/text.ts
CHANGED
|
@@ -5,10 +5,10 @@ import { EDITABLE_ROLES, type EditableTarget, getEditableDelegate, isEditable }
|
|
|
5
5
|
import { formatRoleList } from "../role-helpers.js";
|
|
6
6
|
import { wrapEvent } from "./event-wrapper.js";
|
|
7
7
|
|
|
8
|
-
/** Options for
|
|
8
|
+
/** Options for `userEvent.type`. */
|
|
9
9
|
type TypeOptions = {
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/** Focus the widget before typing; defaults to true. */
|
|
11
|
+
shouldFocus?: boolean | undefined;
|
|
12
12
|
/** Select from this offset before typing, replacing the selected range with the typed text. */
|
|
13
13
|
initialSelectionStart?: number | undefined;
|
|
14
14
|
/** End offset of the initial selection (defaults to the start offset). */
|
|
@@ -131,9 +131,15 @@ const runEditableEvent = (
|
|
|
131
131
|
action(widget);
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Focuses the widget unless `shouldFocus` is false, applies any initial selection, and inserts the text
|
|
136
|
+
* at the cursor.
|
|
137
|
+
*
|
|
138
|
+
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
139
|
+
*/
|
|
134
140
|
const type = (widget: Gtk.Widget, text: string, options?: TypeOptions): Promise<void> =>
|
|
135
141
|
runEditableEvent(widget, "Cannot type into element", (editable) => {
|
|
136
|
-
if (
|
|
142
|
+
if (options?.shouldFocus ?? true) {
|
|
137
143
|
editable.grabFocus();
|
|
138
144
|
}
|
|
139
145
|
|
|
@@ -141,22 +147,43 @@ const type = (widget: Gtk.Widget, text: string, options?: TypeOptions): Promise<
|
|
|
141
147
|
insertEditableText(editable, text);
|
|
142
148
|
});
|
|
143
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Replaces an editable widget's text with the empty string.
|
|
152
|
+
*
|
|
153
|
+
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
154
|
+
*/
|
|
144
155
|
const clear = (widget: Gtk.Widget): Promise<void> =>
|
|
145
156
|
runEditableEvent(widget, "Cannot clear element", (editable) => {
|
|
146
157
|
setEditableText(editable, "");
|
|
147
158
|
});
|
|
148
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Writes an editable widget's selected text to its clipboard, or the empty string when nothing is selected.
|
|
162
|
+
*
|
|
163
|
+
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
164
|
+
*/
|
|
149
165
|
const copy = (widget: Gtk.Widget): Promise<void> =>
|
|
150
166
|
runEditableEvent(widget, "Cannot copy", (editable) => {
|
|
151
167
|
writeClipboardText(editable, readSelection(editable));
|
|
152
168
|
});
|
|
153
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Writes an editable widget's selected text to its clipboard, then deletes that selection.
|
|
172
|
+
*
|
|
173
|
+
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
174
|
+
*/
|
|
154
175
|
const cut = (widget: Gtk.Widget): Promise<void> =>
|
|
155
176
|
runEditableEvent(widget, "Cannot cut", (editable) => {
|
|
156
177
|
writeClipboardText(editable, readSelection(editable));
|
|
157
178
|
deleteSelection(editable);
|
|
158
179
|
});
|
|
159
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Inserts the given text at an editable widget's cursor, reading the clipboard instead when no text
|
|
183
|
+
* is given.
|
|
184
|
+
*
|
|
185
|
+
* @throws When the widget is neither a Gtk.Editable nor a Gtk.TextView.
|
|
186
|
+
*/
|
|
160
187
|
const paste = async (widget: Gtk.Widget, text?: string): Promise<void> => {
|
|
161
188
|
if (!isEditable(widget)) {
|
|
162
189
|
throw new Error(`Cannot paste: ${EDITABLE_REQUIRED}`);
|
package/src/wait-for.ts
CHANGED
|
@@ -5,7 +5,9 @@ import { getConfig } from "./config.js";
|
|
|
5
5
|
import { timeoutError } from "./errors.js";
|
|
6
6
|
|
|
7
7
|
type PollResult<T> = { status: "resolved"; value: T } | { status: "timedout"; lastError: Error | null };
|
|
8
|
+
/** Widgets watched for removal; null counts as already removed. */
|
|
8
9
|
type RemovalTarget = Gtk.Widget | Gtk.Widget[] | null;
|
|
10
|
+
/** The widgets to watch for removal, or a function re-read on every poll to locate them. */
|
|
9
11
|
type ElementOrCallback = Gtk.Widget | Gtk.Widget[] | (() => RemovalTarget);
|
|
10
12
|
|
|
11
13
|
const DEFAULT_INTERVAL = 50;
|
|
@@ -11,7 +11,6 @@ type WidgetValue = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
type ValueTriplet = { now: number | null; min: number | null; max: number | null };
|
|
14
|
-
/** A widget's checked state: on, off, or the mixed state of an inconsistent check button. */
|
|
15
14
|
type CheckedState = "checked" | "unchecked" | "mixed";
|
|
16
15
|
|
|
17
16
|
const DEFAULT_TEXT_GETTERS = ["getLabel", "getText", "getTitle"] as const;
|
|
@@ -158,6 +157,12 @@ const textContentParts = (widget: Gtk.Widget): string[] => {
|
|
|
158
157
|
return [...getChildren(widget)].flatMap((child) => textContentParts(child));
|
|
159
158
|
};
|
|
160
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Returns a widget's own text, or the space-joined text of its descendants when it has none of its
|
|
162
|
+
* own, or null when neither produces a value.
|
|
163
|
+
*
|
|
164
|
+
* @param widget The widget whose subtree is read.
|
|
165
|
+
*/
|
|
161
166
|
const getWidgetTextContent = (widget: Gtk.Widget): string | null => {
|
|
162
167
|
const parts = textContentParts(widget);
|
|
163
168
|
|
|
@@ -370,12 +375,23 @@ const getWidgetLevel = (widget: Gtk.Widget): number | null => {
|
|
|
370
375
|
return readAccessibleNumber(widget, "accessibleLevel");
|
|
371
376
|
};
|
|
372
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Returns the accessible invalid state declared on a widget, or null when it declares none.
|
|
380
|
+
*
|
|
381
|
+
* @param widget The widget to read the state from.
|
|
382
|
+
*/
|
|
373
383
|
const getWidgetInvalidState = (widget: Gtk.Widget): Gtk.AccessibleInvalidState | null => {
|
|
374
384
|
const value = readAccessibleNumber(widget, "accessibleInvalid");
|
|
375
385
|
|
|
376
386
|
return value ?? null;
|
|
377
387
|
};
|
|
378
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Returns the widgets a widget's accessible error-message relation points at, or null when it
|
|
391
|
+
* declares none.
|
|
392
|
+
*
|
|
393
|
+
* @param widget The widget to read the relation from.
|
|
394
|
+
*/
|
|
379
395
|
const getWidgetErrorMessage = (widget: Gtk.Widget): Gtk.Widget[] | null =>
|
|
380
396
|
readAccessibleWidgets(widget, "accessibleErrorMessage");
|
|
381
397
|
|