@gtkx/testing 1.0.0-rc.2 → 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/bound-queries.d.ts +2 -3
- package/dist/bound-queries.d.ts.map +1 -1
- package/dist/bound-queries.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/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/matchers.d.ts +125 -21
- package/dist/matchers.d.ts.map +1 -1
- package/dist/matchers.js +258 -21
- package/dist/matchers.js.map +1 -1
- package/dist/normalize.d.ts +10 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +20 -0
- package/dist/normalize.js.map +1 -0
- 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 +4 -21
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +46 -59
- package/dist/queries.js.map +1 -1
- package/dist/render.js +3 -3
- 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 +69 -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 +31 -1
- package/dist/user-event/controller.d.ts.map +1 -1
- package/dist/user-event/controller.js +36 -1
- 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 +28 -2
- package/dist/widget-accessible-properties.d.ts.map +1 -1
- package/dist/widget-accessible-properties.js +129 -10
- package/dist/widget-accessible-properties.js.map +1 -1
- package/dist/within.js.map +1 -1
- package/package.json +7 -7
- package/src/act.ts +2 -0
- package/src/bound-queries.ts +2 -3
- package/src/build-queries.ts +20 -8
- package/src/config.ts +4 -3
- package/src/errors.ts +2 -2
- package/src/index.ts +11 -2
- package/src/matchers.ts +500 -53
- package/src/normalize.ts +28 -0
- package/src/pretty-widget.ts +5 -4
- package/src/queries.ts +79 -105
- package/src/render.tsx +3 -3
- package/src/suggestions.ts +3 -0
- package/src/traversal.ts +5 -0
- package/src/types.ts +88 -4
- package/src/user-event/adjustment.ts +13 -0
- package/src/user-event/click.ts +7 -0
- package/src/user-event/controller.ts +50 -1
- 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 +188 -10
- package/src/within.ts +1 -1
|
@@ -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,9 +11,18 @@ type WidgetValue = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
type ValueTriplet = { now: number | null; min: number | null; max: number | null };
|
|
14
|
+
type CheckedState = "checked" | "unchecked" | "mixed";
|
|
14
15
|
|
|
15
16
|
const DEFAULT_TEXT_GETTERS = ["getLabel", "getText", "getTitle"] as const;
|
|
16
17
|
|
|
18
|
+
const SELECTABLE_ROLES: Set<Gtk.AccessibleRole> = new Set<Gtk.AccessibleRole>([
|
|
19
|
+
Gtk.AccessibleRole.ROW,
|
|
20
|
+
Gtk.AccessibleRole.LIST_ITEM,
|
|
21
|
+
Gtk.AccessibleRole.GRID_CELL,
|
|
22
|
+
Gtk.AccessibleRole.OPTION,
|
|
23
|
+
Gtk.AccessibleRole.TREE_ITEM,
|
|
24
|
+
]);
|
|
25
|
+
|
|
17
26
|
const callStringGetter = (widget: Gtk.Widget, method: string): string | null => {
|
|
18
27
|
const fn: unknown = Reflect.get(widget, method);
|
|
19
28
|
|
|
@@ -129,6 +138,55 @@ const getWidgetLabelText = (widget: Gtk.Widget): string | null => {
|
|
|
129
138
|
return getLabelText(widget);
|
|
130
139
|
};
|
|
131
140
|
|
|
141
|
+
const getChildren = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {
|
|
142
|
+
let child = widget.getFirstChild();
|
|
143
|
+
|
|
144
|
+
while (child) {
|
|
145
|
+
yield child;
|
|
146
|
+
child = child.getNextSibling();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const textContentParts = (widget: Gtk.Widget): string[] => {
|
|
151
|
+
const own = getWidgetNodeText(widget);
|
|
152
|
+
|
|
153
|
+
if (own !== null) {
|
|
154
|
+
return [own];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return [...getChildren(widget)].flatMap((child) => textContentParts(child));
|
|
158
|
+
};
|
|
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
|
+
*/
|
|
166
|
+
const getWidgetTextContent = (widget: Gtk.Widget): string | null => {
|
|
167
|
+
const parts = textContentParts(widget);
|
|
168
|
+
|
|
169
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const isComboBoxFaceCandidate = (widget: Gtk.Widget): boolean =>
|
|
173
|
+
!(widget instanceof Gtk.Popover) && widget.getChildVisible();
|
|
174
|
+
|
|
175
|
+
const comboBoxChildFaceText = (child: Gtk.Widget): string | null =>
|
|
176
|
+
isComboBoxFaceCandidate(child) ? getWidgetLabelText(child) ?? comboBoxFaceText(child) : null;
|
|
177
|
+
|
|
178
|
+
const comboBoxFaceText = (widget: Gtk.Widget): string | null => {
|
|
179
|
+
for (const child of getChildren(widget)) {
|
|
180
|
+
const text = comboBoxChildFaceText(child);
|
|
181
|
+
|
|
182
|
+
if (text !== null) {
|
|
183
|
+
return text;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return null;
|
|
188
|
+
};
|
|
189
|
+
|
|
132
190
|
const tabPanelTitle = (widget: Gtk.Widget): string | null => {
|
|
133
191
|
const parent = widget.getParent();
|
|
134
192
|
|
|
@@ -146,6 +204,12 @@ const getWidgetAccessibleName = (widget: Gtk.Widget): string | null => {
|
|
|
146
204
|
return tabPanelTitle(widget);
|
|
147
205
|
}
|
|
148
206
|
|
|
207
|
+
const labelledByText = getWidgetLabelledByText(widget);
|
|
208
|
+
|
|
209
|
+
if (labelledByText) {
|
|
210
|
+
return labelledByText;
|
|
211
|
+
}
|
|
212
|
+
|
|
149
213
|
const accessibleLabel = readAccessibleString(widget, "accessibleLabel");
|
|
150
214
|
|
|
151
215
|
if (accessibleLabel) {
|
|
@@ -176,7 +240,15 @@ const getWidgetPlaceholderText = (widget: Gtk.Widget): string | null => {
|
|
|
176
240
|
return null;
|
|
177
241
|
}
|
|
178
242
|
|
|
179
|
-
|
|
243
|
+
const fromGetter = callStringGetter(widget, "getPlaceholderText");
|
|
244
|
+
|
|
245
|
+
if (fromGetter !== null) {
|
|
246
|
+
return fromGetter;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const fromAccessor: unknown = Reflect.get(widget, "placeholderText");
|
|
250
|
+
|
|
251
|
+
return typeof fromAccessor === "string" && fromAccessor !== "" ? fromAccessor : null;
|
|
180
252
|
};
|
|
181
253
|
|
|
182
254
|
const getWidgetDisplayValue = (widget: Gtk.Widget): string | null => {
|
|
@@ -184,25 +256,89 @@ const getWidgetDisplayValue = (widget: Gtk.Widget): string | null => {
|
|
|
184
256
|
return readEditableText(widget);
|
|
185
257
|
}
|
|
186
258
|
|
|
259
|
+
if (widget.getAccessibleRole() === Gtk.AccessibleRole.COMBO_BOX) {
|
|
260
|
+
return comboBoxFaceText(widget);
|
|
261
|
+
}
|
|
262
|
+
|
|
187
263
|
return null;
|
|
188
264
|
};
|
|
189
265
|
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
266
|
+
const hasDisplayValue = (widget: Gtk.Widget): boolean => {
|
|
267
|
+
const role = widget.getAccessibleRole();
|
|
268
|
+
|
|
269
|
+
return (EDITABLE_ROLES.has(role) && isEditable(widget)) || role === Gtk.AccessibleRole.COMBO_BOX;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const isWidgetDisabled = (widget: Gtk.Widget): boolean => !widget.isSensitive();
|
|
273
|
+
|
|
274
|
+
const hasZeroOpacityAncestor = (widget: Gtk.Widget): boolean => {
|
|
275
|
+
let current: Gtk.Widget | null = widget;
|
|
276
|
+
|
|
277
|
+
while (current) {
|
|
278
|
+
if (current.getOpacity() === 0) {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
current = current.getParent();
|
|
193
283
|
}
|
|
194
284
|
|
|
195
|
-
|
|
196
|
-
|
|
285
|
+
return false;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const isWidgetVisible = (widget: Gtk.Widget): boolean => widget.isVisible() && !hasZeroOpacityAncestor(widget);
|
|
289
|
+
|
|
290
|
+
const getWidgetRequiredState = (widget: Gtk.Widget): boolean | null =>
|
|
291
|
+
readAccessibleBoolean(widget, "accessibleRequired");
|
|
292
|
+
|
|
293
|
+
const readTextViewSelection = (view: Gtk.TextView): string | null => {
|
|
294
|
+
const buffer = view.getBuffer();
|
|
295
|
+
const [hasSelection, start, end] = buffer.getSelectionBounds();
|
|
296
|
+
|
|
297
|
+
return hasSelection ? buffer.getText(start, end, true) : null;
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const readEditableSelection = (editable: Gtk.Editable): string | null => {
|
|
301
|
+
const [hasSelection, start, end] = editable.getSelectionBounds();
|
|
302
|
+
|
|
303
|
+
return hasSelection ? editable.getChars(start, end) : null;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const getWidgetSelection = (widget: Gtk.Widget): string | null => {
|
|
307
|
+
if (widget instanceof Gtk.TextView) {
|
|
308
|
+
return readTextViewSelection(widget);
|
|
197
309
|
}
|
|
198
310
|
|
|
199
|
-
if (widget instanceof Gtk.
|
|
200
|
-
return widget
|
|
311
|
+
if (widget instanceof Gtk.Editable) {
|
|
312
|
+
return readEditableSelection(widget);
|
|
201
313
|
}
|
|
202
314
|
|
|
203
315
|
return null;
|
|
204
316
|
};
|
|
205
317
|
|
|
318
|
+
const checkedFromActive = (isActive: boolean): CheckedState => (isActive ? "checked" : "unchecked");
|
|
319
|
+
|
|
320
|
+
const isCheckableToggle = (widget: Gtk.Widget): boolean =>
|
|
321
|
+
widget instanceof Gtk.Switch ||
|
|
322
|
+
(widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO);
|
|
323
|
+
|
|
324
|
+
const getWidgetCheckedState = (widget: Gtk.Widget): CheckedState | null => {
|
|
325
|
+
if (widget instanceof Gtk.CheckButton) {
|
|
326
|
+
return widget.getInconsistent() ? "mixed" : checkedFromActive(widget.getActive());
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (isCheckableToggle(widget)) {
|
|
330
|
+
return checkedFromActive(Reflect.get(widget, "active") === true);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return null;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const isWidgetChecked = (widget: Gtk.Widget): boolean | null => {
|
|
337
|
+
const state = getWidgetCheckedState(widget);
|
|
338
|
+
|
|
339
|
+
return state === null || state === "mixed" ? null : state === "checked";
|
|
340
|
+
};
|
|
341
|
+
|
|
206
342
|
const getWidgetPressedState = (widget: Gtk.Widget): boolean | null => {
|
|
207
343
|
if (widget instanceof Gtk.ToggleButton) {
|
|
208
344
|
return widget.getActive();
|
|
@@ -224,11 +360,11 @@ const getWidgetExpandedState = (widget: Gtk.Widget): boolean | null => {
|
|
|
224
360
|
};
|
|
225
361
|
|
|
226
362
|
const getWidgetSelectedState = (widget: Gtk.Widget): boolean | null => {
|
|
227
|
-
if (widget instanceof Gtk.ListBoxRow) {
|
|
363
|
+
if (widget instanceof Gtk.ListBoxRow || widget instanceof Gtk.FlowBoxChild) {
|
|
228
364
|
return widget.isSelected();
|
|
229
365
|
}
|
|
230
366
|
|
|
231
|
-
if (widget.getAccessibleRole()
|
|
367
|
+
if (SELECTABLE_ROLES.has(widget.getAccessibleRole())) {
|
|
232
368
|
return (widget.getStateFlags() & Gtk.StateFlags.SELECTED) !== 0;
|
|
233
369
|
}
|
|
234
370
|
|
|
@@ -239,12 +375,23 @@ const getWidgetLevel = (widget: Gtk.Widget): number | null => {
|
|
|
239
375
|
return readAccessibleNumber(widget, "accessibleLevel");
|
|
240
376
|
};
|
|
241
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
|
+
*/
|
|
242
383
|
const getWidgetInvalidState = (widget: Gtk.Widget): Gtk.AccessibleInvalidState | null => {
|
|
243
384
|
const value = readAccessibleNumber(widget, "accessibleInvalid");
|
|
244
385
|
|
|
245
386
|
return value ?? null;
|
|
246
387
|
};
|
|
247
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
|
+
*/
|
|
248
395
|
const getWidgetErrorMessage = (widget: Gtk.Widget): Gtk.Widget[] | null =>
|
|
249
396
|
readAccessibleWidgets(widget, "accessibleErrorMessage");
|
|
250
397
|
|
|
@@ -346,6 +493,28 @@ const getWidgetLabelledByText = (widget: Gtk.Widget): string | null => {
|
|
|
346
493
|
return texts.length > 0 ? texts.join(" ") : null;
|
|
347
494
|
};
|
|
348
495
|
|
|
496
|
+
const isTooltipUsedAsName = (widget: Gtk.Widget): boolean =>
|
|
497
|
+
readAccessibleString(widget, "accessibleLabel") === null &&
|
|
498
|
+
getWidgetNodeText(widget) === null &&
|
|
499
|
+
collectLabels(widget).length === 0;
|
|
500
|
+
|
|
501
|
+
const getWidgetDescribedByText = (widget: Gtk.Widget): string | null => {
|
|
502
|
+
const targets = readAccessibleWidgets(widget, "accessibleDescribedBy");
|
|
503
|
+
const texts = targets === null ? [] : collectAccessibleNames(targets);
|
|
504
|
+
|
|
505
|
+
if (texts.length > 0) {
|
|
506
|
+
return texts.join(" ");
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const description = readAccessibleString(widget, "accessibleDescription");
|
|
510
|
+
|
|
511
|
+
if (description !== null) {
|
|
512
|
+
return description;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return isTooltipUsedAsName(widget) ? null : callStringGetter(widget, "getTooltipText");
|
|
516
|
+
};
|
|
517
|
+
|
|
349
518
|
const isInaccessible = (widget: Gtk.Widget): boolean => {
|
|
350
519
|
let current: Gtk.Widget | null = widget;
|
|
351
520
|
|
|
@@ -366,12 +535,20 @@ const isInaccessible = (widget: Gtk.Widget): boolean => {
|
|
|
366
535
|
|
|
367
536
|
export {
|
|
368
537
|
getWidgetNodeText,
|
|
538
|
+
getWidgetTextContent,
|
|
369
539
|
getWidgetLabelText,
|
|
370
540
|
getWidgetAccessibleName,
|
|
371
541
|
getWidgetName,
|
|
372
542
|
getWidgetPlaceholderText,
|
|
373
543
|
getWidgetDisplayValue,
|
|
544
|
+
hasDisplayValue,
|
|
545
|
+
isWidgetDisabled,
|
|
546
|
+
isWidgetVisible,
|
|
547
|
+
getWidgetRequiredState,
|
|
548
|
+
getWidgetSelection,
|
|
549
|
+
getWidgetDescribedByText,
|
|
374
550
|
getWidgetCheckedState,
|
|
551
|
+
isWidgetChecked,
|
|
375
552
|
getWidgetPressedState,
|
|
376
553
|
getWidgetExpandedState,
|
|
377
554
|
getWidgetSelectedState,
|
|
@@ -384,5 +561,6 @@ export {
|
|
|
384
561
|
getWidgetOwnLabel,
|
|
385
562
|
getWidgetLabelledByText,
|
|
386
563
|
isInaccessible,
|
|
564
|
+
type CheckedState,
|
|
387
565
|
type WidgetValue,
|
|
388
566
|
};
|
package/src/within.ts
CHANGED
|
@@ -26,7 +26,7 @@ const within = <Q extends QueryMap = Record<never, never>>(
|
|
|
26
26
|
container: Container,
|
|
27
27
|
queries?: Q,
|
|
28
28
|
): BoundQueries & BoundCustomQueries<Q> => ({
|
|
29
|
-
...bindCustomQueries(builtinQueries, container),
|
|
29
|
+
...(bindCustomQueries(builtinQueries, container) as BoundQueries),
|
|
30
30
|
...(queries ? bindCustomQueries(queries, container) : ({} as BoundCustomQueries<Q>)),
|
|
31
31
|
});
|
|
32
32
|
|