@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/queries.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { multipleFoundError, notFoundError } from "./errors.js";
|
|
|
12
12
|
import { getDefaultNormalizer } from "./normalize.js";
|
|
13
13
|
import { type Container, findAll, traverse } from "./traversal.js";
|
|
14
14
|
import {
|
|
15
|
+
buildInaccessibilityCheck,
|
|
15
16
|
getWidgetAccessibleName,
|
|
16
17
|
getWidgetBusyState,
|
|
17
18
|
getWidgetDescription,
|
|
@@ -26,7 +27,6 @@ import {
|
|
|
26
27
|
getWidgetPressedState,
|
|
27
28
|
getWidgetSelectedState,
|
|
28
29
|
getWidgetValueText,
|
|
29
|
-
isInaccessible,
|
|
30
30
|
isWidgetChecked,
|
|
31
31
|
isWidgetValueMatch,
|
|
32
32
|
namingLabelText,
|
|
@@ -39,7 +39,7 @@ type BuiltinQueries = QueryFamilies<[container: Container]>;
|
|
|
39
39
|
const roleQueries = nameQueryFamily(
|
|
40
40
|
"Role",
|
|
41
41
|
queryAllByRole,
|
|
42
|
-
buildQueries<[role: Gtk.AccessibleRole, options?: ByRoleOptions]>(
|
|
42
|
+
buildQueries<[role: Gtk.AccessibleRole, options?: ByRoleOptions<Gtk.Widget>], Gtk.Widget>(
|
|
43
43
|
queryAllByRole,
|
|
44
44
|
(container, matches, role, options) =>
|
|
45
45
|
multipleFoundError(container, { queryType: "role", role, options }, matches),
|
|
@@ -50,7 +50,7 @@ const roleQueries = nameQueryFamily(
|
|
|
50
50
|
const labelTextQueries = nameQueryFamily(
|
|
51
51
|
"LabelText",
|
|
52
52
|
queryAllByLabelText,
|
|
53
|
-
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
53
|
+
buildQueries<[text: Matcher, options?: MatcherOptions<Gtk.Widget>], Gtk.Widget>(
|
|
54
54
|
queryAllByLabelText,
|
|
55
55
|
(container, matches, text) => multipleFoundError(container, { queryType: "labelText", text }, matches),
|
|
56
56
|
(container, text) => notFoundError(container, { queryType: "labelText", text }),
|
|
@@ -60,7 +60,7 @@ const labelTextQueries = nameQueryFamily(
|
|
|
60
60
|
const textQueries = nameQueryFamily(
|
|
61
61
|
"Text",
|
|
62
62
|
queryAllByText,
|
|
63
|
-
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
63
|
+
buildQueries<[text: Matcher, options?: MatcherOptions<Gtk.Widget>], Gtk.Widget>(
|
|
64
64
|
queryAllByText,
|
|
65
65
|
(container, matches, text) => multipleFoundError(container, { queryType: "text", text }, matches),
|
|
66
66
|
(container, text) => notFoundError(container, { queryType: "text", text }),
|
|
@@ -70,7 +70,7 @@ const textQueries = nameQueryFamily(
|
|
|
70
70
|
const nameQueries = nameQueryFamily(
|
|
71
71
|
"Name",
|
|
72
72
|
queryAllByName,
|
|
73
|
-
buildQueries<[name: Matcher, options?: MatcherOptions]>(
|
|
73
|
+
buildQueries<[name: Matcher, options?: MatcherOptions<Gtk.Widget>], Gtk.Widget>(
|
|
74
74
|
queryAllByName,
|
|
75
75
|
(container, matches, name) => multipleFoundError(container, { queryType: "name", name }, matches),
|
|
76
76
|
(container, name) => notFoundError(container, { queryType: "name", name }),
|
|
@@ -80,7 +80,7 @@ const nameQueries = nameQueryFamily(
|
|
|
80
80
|
const placeholderTextQueries = nameQueryFamily(
|
|
81
81
|
"PlaceholderText",
|
|
82
82
|
queryAllByPlaceholderText,
|
|
83
|
-
buildQueries<[text: Matcher, options?: MatcherOptions]>(
|
|
83
|
+
buildQueries<[text: Matcher, options?: MatcherOptions<Gtk.Widget>], Gtk.Widget>(
|
|
84
84
|
queryAllByPlaceholderText,
|
|
85
85
|
(container, matches, text) => multipleFoundError(container, { queryType: "placeholderText", text }, matches),
|
|
86
86
|
(container, text) => notFoundError(container, { queryType: "placeholderText", text }),
|
|
@@ -90,7 +90,7 @@ const placeholderTextQueries = nameQueryFamily(
|
|
|
90
90
|
const displayValueQueries = nameQueryFamily(
|
|
91
91
|
"DisplayValue",
|
|
92
92
|
queryAllByDisplayValue,
|
|
93
|
-
buildQueries<[value: Matcher, options?: MatcherOptions]>(
|
|
93
|
+
buildQueries<[value: Matcher, options?: MatcherOptions<Gtk.Widget>], Gtk.Widget>(
|
|
94
94
|
queryAllByDisplayValue,
|
|
95
95
|
(container, matches, value) => multipleFoundError(container, { queryType: "displayValue", value }, matches),
|
|
96
96
|
(container, value) => notFoundError(container, { queryType: "displayValue", value }),
|
|
@@ -106,161 +106,65 @@ const builtinQueries = {
|
|
|
106
106
|
...displayValueQueries,
|
|
107
107
|
} as BuiltinQueries;
|
|
108
108
|
|
|
109
|
-
/**
|
|
110
|
-
* Returns the single mapped widget with a matching accessible role and options, or null when none
|
|
111
|
-
* match. Widgets that are not mapped are never matched. Throws when more than one matches.
|
|
112
|
-
*/
|
|
109
|
+
/** Queries one mapped widget by accessible role. */
|
|
113
110
|
const queryByRole: BuiltinQueries["queryByRole"] = builtinQueries.queryByRole;
|
|
114
|
-
/**
|
|
115
|
-
* Returns every mapped widget with a matching accessible role and options. Widgets that are not
|
|
116
|
-
* mapped are never matched. Throws when none match.
|
|
117
|
-
*/
|
|
111
|
+
/** Gets all mapped widgets with an accessible role. */
|
|
118
112
|
const getAllByRole: BuiltinQueries["getAllByRole"] = builtinQueries.getAllByRole;
|
|
119
|
-
/**
|
|
120
|
-
* Returns the single mapped widget with a matching accessible role and options. Widgets that are not
|
|
121
|
-
* mapped are never matched. Throws when none or more than one matches.
|
|
122
|
-
*/
|
|
113
|
+
/** Gets one mapped widget by accessible role. */
|
|
123
114
|
const getByRole: BuiltinQueries["getByRole"] = builtinQueries.getByRole;
|
|
124
|
-
/**
|
|
125
|
-
* Waits for and returns every mapped widget with a matching accessible role and options, retrying
|
|
126
|
-
* until at least one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
127
|
-
*/
|
|
115
|
+
/** Finds all mapped widgets with an accessible role. */
|
|
128
116
|
const findAllByRole: BuiltinQueries["findAllByRole"] = builtinQueries.findAllByRole;
|
|
129
|
-
/**
|
|
130
|
-
* Waits for and returns the single mapped widget with a matching accessible role and options,
|
|
131
|
-
* retrying until it appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
132
|
-
* Rejects when none or more than one matches.
|
|
133
|
-
*/
|
|
117
|
+
/** Finds one mapped widget by accessible role. */
|
|
134
118
|
const findByRole: BuiltinQueries["findByRole"] = builtinQueries.findByRole;
|
|
135
|
-
/**
|
|
136
|
-
* Returns the single mapped widget with matching associated label text, or null when none match.
|
|
137
|
-
* Widgets that are not mapped are never matched. Throws when more than one matches.
|
|
138
|
-
*/
|
|
119
|
+
/** Queries one mapped widget by label text. */
|
|
139
120
|
const queryByLabelText: BuiltinQueries["queryByLabelText"] = builtinQueries.queryByLabelText;
|
|
140
|
-
/**
|
|
141
|
-
* Returns every mapped widget with matching associated label text. Widgets that are not mapped are
|
|
142
|
-
* never matched. Throws when none match.
|
|
143
|
-
*/
|
|
121
|
+
/** Gets all mapped widgets with label text. */
|
|
144
122
|
const getAllByLabelText: BuiltinQueries["getAllByLabelText"] = builtinQueries.getAllByLabelText;
|
|
145
|
-
/**
|
|
146
|
-
* Returns the single mapped widget with matching associated label text. Widgets that are not mapped
|
|
147
|
-
* are never matched. Throws when none or more than one matches.
|
|
148
|
-
*/
|
|
123
|
+
/** Gets one mapped widget by label text. */
|
|
149
124
|
const getByLabelText: BuiltinQueries["getByLabelText"] = builtinQueries.getByLabelText;
|
|
150
|
-
/**
|
|
151
|
-
* Waits for and returns every mapped widget with matching associated label text, retrying until at
|
|
152
|
-
* least one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
153
|
-
*/
|
|
125
|
+
/** Finds all mapped widgets with label text. */
|
|
154
126
|
const findAllByLabelText: BuiltinQueries["findAllByLabelText"] = builtinQueries.findAllByLabelText;
|
|
155
|
-
/**
|
|
156
|
-
* Waits for and returns the single mapped widget with matching associated label text, retrying until
|
|
157
|
-
* it appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when
|
|
158
|
-
* none or more than one matches.
|
|
159
|
-
*/
|
|
127
|
+
/** Finds one mapped widget by label text. */
|
|
160
128
|
const findByLabelText: BuiltinQueries["findByLabelText"] = builtinQueries.findByLabelText;
|
|
161
|
-
/**
|
|
162
|
-
* Returns the single mapped widget with matching rendered text content, or null when none match.
|
|
163
|
-
* Widgets that are not mapped are never matched. Throws when more than one matches.
|
|
164
|
-
*/
|
|
129
|
+
/** Queries one mapped widget by rendered text. */
|
|
165
130
|
const queryByText: BuiltinQueries["queryByText"] = builtinQueries.queryByText;
|
|
166
|
-
/**
|
|
167
|
-
* Returns every mapped widget with matching rendered text content. Widgets that are not mapped are
|
|
168
|
-
* never matched. Throws when none match.
|
|
169
|
-
*/
|
|
131
|
+
/** Gets all mapped widgets with rendered text. */
|
|
170
132
|
const getAllByText: BuiltinQueries["getAllByText"] = builtinQueries.getAllByText;
|
|
171
|
-
/**
|
|
172
|
-
* Returns the single mapped widget with matching rendered text content. Widgets that are not mapped
|
|
173
|
-
* are never matched. Throws when none or more than one matches.
|
|
174
|
-
*/
|
|
133
|
+
/** Gets one mapped widget by rendered text. */
|
|
175
134
|
const getByText: BuiltinQueries["getByText"] = builtinQueries.getByText;
|
|
176
|
-
/**
|
|
177
|
-
* Waits for and returns every mapped widget with matching rendered text content, retrying until at
|
|
178
|
-
* least one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
179
|
-
*/
|
|
135
|
+
/** Finds all mapped widgets with rendered text. */
|
|
180
136
|
const findAllByText: BuiltinQueries["findAllByText"] = builtinQueries.findAllByText;
|
|
181
|
-
/**
|
|
182
|
-
* Waits for and returns the single mapped widget with matching rendered text content, retrying until
|
|
183
|
-
* it appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when
|
|
184
|
-
* none or more than one matches.
|
|
185
|
-
*/
|
|
137
|
+
/** Finds one mapped widget by rendered text. */
|
|
186
138
|
const findByText: BuiltinQueries["findByText"] = builtinQueries.findByText;
|
|
187
|
-
/**
|
|
188
|
-
* Returns the single mapped widget with a matching widget name, or null when none match. Widgets
|
|
189
|
-
* that are not mapped are never matched. Throws when more than one matches.
|
|
190
|
-
*/
|
|
139
|
+
/** Queries one mapped widget by GTK name. */
|
|
191
140
|
const queryByName: BuiltinQueries["queryByName"] = builtinQueries.queryByName;
|
|
192
|
-
/**
|
|
193
|
-
* Returns every mapped widget with a matching widget name. Widgets that are not mapped are never
|
|
194
|
-
* matched. Throws when none match.
|
|
195
|
-
*/
|
|
141
|
+
/** Gets all mapped widgets with a GTK name. */
|
|
196
142
|
const getAllByName: BuiltinQueries["getAllByName"] = builtinQueries.getAllByName;
|
|
197
|
-
/**
|
|
198
|
-
* Returns the single mapped widget with a matching widget name. Widgets that are not mapped are
|
|
199
|
-
* never matched. Throws when none or more than one matches.
|
|
200
|
-
*/
|
|
143
|
+
/** Gets one mapped widget by GTK name. */
|
|
201
144
|
const getByName: BuiltinQueries["getByName"] = builtinQueries.getByName;
|
|
202
|
-
/**
|
|
203
|
-
* Waits for and returns every mapped widget with a matching widget name, retrying until at least one
|
|
204
|
-
* appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
205
|
-
*/
|
|
145
|
+
/** Finds all mapped widgets with a GTK name. */
|
|
206
146
|
const findAllByName: BuiltinQueries["findAllByName"] = builtinQueries.findAllByName;
|
|
207
|
-
/**
|
|
208
|
-
* Waits for and returns the single mapped widget with a matching widget name, retrying until it
|
|
209
|
-
* appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when none
|
|
210
|
-
* or more than one matches.
|
|
211
|
-
*/
|
|
147
|
+
/** Finds one mapped widget by GTK name. */
|
|
212
148
|
const findByName: BuiltinQueries["findByName"] = builtinQueries.findByName;
|
|
213
|
-
/**
|
|
214
|
-
* Returns the single mapped widget with matching placeholder text, or null when none match. Widgets
|
|
215
|
-
* that are not mapped are never matched. Throws when more than one matches.
|
|
216
|
-
*/
|
|
149
|
+
/** Queries one mapped widget by placeholder text. */
|
|
217
150
|
const queryByPlaceholderText: BuiltinQueries["queryByPlaceholderText"] = builtinQueries.queryByPlaceholderText;
|
|
218
|
-
/**
|
|
219
|
-
* Returns every mapped widget with matching placeholder text. Widgets that are not mapped are never
|
|
220
|
-
* matched. Throws when none match.
|
|
221
|
-
*/
|
|
151
|
+
/** Gets all mapped widgets with placeholder text. */
|
|
222
152
|
const getAllByPlaceholderText: BuiltinQueries["getAllByPlaceholderText"] = builtinQueries.getAllByPlaceholderText;
|
|
223
|
-
/**
|
|
224
|
-
* Returns the single mapped widget with matching placeholder text. Widgets that are not mapped are
|
|
225
|
-
* never matched. Throws when none or more than one matches.
|
|
226
|
-
*/
|
|
153
|
+
/** Gets one mapped widget by placeholder text. */
|
|
227
154
|
const getByPlaceholderText: BuiltinQueries["getByPlaceholderText"] = builtinQueries.getByPlaceholderText;
|
|
228
|
-
/**
|
|
229
|
-
* Waits for and returns every mapped widget with matching placeholder text, retrying until at least
|
|
230
|
-
* one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
231
|
-
*/
|
|
155
|
+
/** Finds all mapped widgets with placeholder text. */
|
|
232
156
|
const findAllByPlaceholderText: BuiltinQueries["findAllByPlaceholderText"] = builtinQueries.findAllByPlaceholderText;
|
|
233
|
-
/**
|
|
234
|
-
* Waits for and returns the single mapped widget with matching placeholder text, retrying until it
|
|
235
|
-
* appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when none
|
|
236
|
-
* or more than one matches.
|
|
237
|
-
*/
|
|
157
|
+
/** Finds one mapped widget by placeholder text. */
|
|
238
158
|
const findByPlaceholderText: BuiltinQueries["findByPlaceholderText"] = builtinQueries.findByPlaceholderText;
|
|
239
|
-
/**
|
|
240
|
-
* Returns the single mapped widget with a matching display value, or null when none match. Widgets
|
|
241
|
-
* that are not mapped are never matched. Throws when more than one matches.
|
|
242
|
-
*/
|
|
159
|
+
/** Queries one mapped widget by display value. */
|
|
243
160
|
const queryByDisplayValue: BuiltinQueries["queryByDisplayValue"] = builtinQueries.queryByDisplayValue;
|
|
244
|
-
/**
|
|
245
|
-
* Returns every mapped widget with a matching display value. Widgets that are not mapped are never
|
|
246
|
-
* matched. Throws when none match.
|
|
247
|
-
*/
|
|
161
|
+
/** Gets all mapped widgets with a display value. */
|
|
248
162
|
const getAllByDisplayValue: BuiltinQueries["getAllByDisplayValue"] = builtinQueries.getAllByDisplayValue;
|
|
249
|
-
/**
|
|
250
|
-
* Returns the single mapped widget with a matching display value. Widgets that are not mapped are
|
|
251
|
-
* never matched. Throws when none or more than one matches.
|
|
252
|
-
*/
|
|
163
|
+
/** Gets one mapped widget by display value. */
|
|
253
164
|
const getByDisplayValue: BuiltinQueries["getByDisplayValue"] = builtinQueries.getByDisplayValue;
|
|
254
|
-
/**
|
|
255
|
-
* Waits for and returns every mapped widget with a matching display value, retrying until at least
|
|
256
|
-
* one appears or the timeout elapses. Widgets that are not mapped are never matched.
|
|
257
|
-
*/
|
|
165
|
+
/** Finds all mapped widgets with a display value. */
|
|
258
166
|
const findAllByDisplayValue: BuiltinQueries["findAllByDisplayValue"] = builtinQueries.findAllByDisplayValue;
|
|
259
|
-
/**
|
|
260
|
-
* Waits for and returns the single mapped widget with a matching display value, retrying until it
|
|
261
|
-
* appears or the timeout elapses. Widgets that are not mapped are never matched. Rejects when none
|
|
262
|
-
* or more than one matches.
|
|
263
|
-
*/
|
|
167
|
+
/** Finds one mapped widget by display value. */
|
|
264
168
|
const findByDisplayValue: BuiltinQueries["findByDisplayValue"] = builtinQueries.findByDisplayValue;
|
|
265
169
|
|
|
266
170
|
const buildNormalizer = (options?: MatcherOptions): NormalizerFn => {
|
|
@@ -380,25 +284,27 @@ const hasMatchingAccessibleStates = (widget: Gtk.Widget, options: ByRoleOptions)
|
|
|
380
284
|
hasMatchingDescriptionState(widget, options) &&
|
|
381
285
|
hasMatchingValueState(widget, options);
|
|
382
286
|
|
|
383
|
-
const isMatchingWidgetType =
|
|
287
|
+
const isMatchingWidgetType = <T extends Gtk.Accessible>(
|
|
288
|
+
widget: Gtk.Widget,
|
|
289
|
+
options?: MatcherOptions<T>,
|
|
290
|
+
): widget is Gtk.Widget & T =>
|
|
384
291
|
options?.as === undefined || widget instanceof options.as;
|
|
385
292
|
|
|
386
|
-
const
|
|
293
|
+
const hasMatchingAccessibleOptions = (widget: Gtk.Widget, options?: ByRoleOptions): boolean => {
|
|
387
294
|
if (!options) {
|
|
388
295
|
return true;
|
|
389
296
|
}
|
|
390
297
|
|
|
391
298
|
return (
|
|
392
|
-
isMatchingWidgetType(widget, options) &&
|
|
393
299
|
hasMatchingAccessibleName(widget, options) &&
|
|
394
300
|
hasMatchingAccessibleStates(widget, options)
|
|
395
301
|
);
|
|
396
302
|
};
|
|
397
303
|
|
|
398
|
-
function nameQueryFamily<Args extends unknown[]>(
|
|
304
|
+
function nameQueryFamily<Args extends unknown[], Element extends Gtk.Accessible>(
|
|
399
305
|
suffix: string,
|
|
400
|
-
queryAllBy: QueryAllBy<Args>,
|
|
401
|
-
built: BuiltQueries<Args>,
|
|
306
|
+
queryAllBy: QueryAllBy<Args, Element>,
|
|
307
|
+
built: BuiltQueries<Args, Element>,
|
|
402
308
|
): Record<string, unknown> {
|
|
403
309
|
const [queryBy, getAllBy, getBy, findAllBy, findBy] = built;
|
|
404
310
|
|
|
@@ -421,22 +327,30 @@ function nameQueryFamily<Args extends unknown[]>(
|
|
|
421
327
|
* @param options Additional accessible name, state, and value constraints.
|
|
422
328
|
* @returns Every matching widget, or an empty array when none match.
|
|
423
329
|
*/
|
|
424
|
-
function queryAllByRole(
|
|
330
|
+
function queryAllByRole<T extends Gtk.Accessible = Gtk.Widget>(
|
|
425
331
|
container: Container,
|
|
426
332
|
role: Gtk.AccessibleRole,
|
|
427
|
-
options?: ByRoleOptions
|
|
428
|
-
):
|
|
429
|
-
|
|
333
|
+
options?: ByRoleOptions<T>,
|
|
334
|
+
): T[] {
|
|
335
|
+
const isInaccessible = buildInaccessibilityCheck();
|
|
336
|
+
|
|
337
|
+
const matches = findAll(container, (widget) => {
|
|
430
338
|
if (widget.getAccessibleRole() !== role) {
|
|
431
339
|
return false;
|
|
432
340
|
}
|
|
433
341
|
|
|
342
|
+
if (!isMatchingWidgetType(widget, options)) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
|
|
434
346
|
if (!options?.hidden && isInaccessible(widget)) {
|
|
435
347
|
return false;
|
|
436
348
|
}
|
|
437
349
|
|
|
438
|
-
return
|
|
350
|
+
return hasMatchingAccessibleOptions(widget, options);
|
|
439
351
|
});
|
|
352
|
+
|
|
353
|
+
return matches.filter((widget): widget is Gtk.Widget & T => isMatchingWidgetType(widget, options));
|
|
440
354
|
}
|
|
441
355
|
|
|
442
356
|
const collectMnemonicMatch = (
|
|
@@ -490,14 +404,18 @@ const collectLabelMatches = (
|
|
|
490
404
|
* @param options Text matching options.
|
|
491
405
|
* @returns Every matching widget, or an empty array when none match.
|
|
492
406
|
*/
|
|
493
|
-
function queryAllByLabelText
|
|
407
|
+
function queryAllByLabelText<T extends Gtk.Accessible = Gtk.Widget>(
|
|
408
|
+
container: Container,
|
|
409
|
+
text: Matcher,
|
|
410
|
+
options?: MatcherOptions<T>,
|
|
411
|
+
): T[] {
|
|
494
412
|
const results: Set<Gtk.Widget> = new Set();
|
|
495
413
|
|
|
496
414
|
for (const widget of traverse(container)) {
|
|
497
415
|
collectLabelMatches(results, widget, text, options);
|
|
498
416
|
}
|
|
499
417
|
|
|
500
|
-
return [...results].filter((widget) => isMatchingWidgetType(widget, options));
|
|
418
|
+
return [...results].filter((widget): widget is Gtk.Widget & T => isMatchingWidgetType(widget, options));
|
|
501
419
|
}
|
|
502
420
|
|
|
503
421
|
/**
|
|
@@ -507,12 +425,18 @@ function queryAllByLabelText(container: Container, text: Matcher, options?: Matc
|
|
|
507
425
|
* @param options Text matching options.
|
|
508
426
|
* @returns Every matching widget, or an empty array when none match.
|
|
509
427
|
*/
|
|
510
|
-
function queryAllByText
|
|
511
|
-
|
|
428
|
+
function queryAllByText<T extends Gtk.Accessible = Gtk.Widget>(
|
|
429
|
+
container: Container,
|
|
430
|
+
text: Matcher,
|
|
431
|
+
options?: MatcherOptions<T>,
|
|
432
|
+
): T[] {
|
|
433
|
+
const matches = findAll(
|
|
512
434
|
container,
|
|
513
435
|
(widget) =>
|
|
514
436
|
isMatchingWidgetType(widget, options) && isTextMatch(getWidgetLabelText(widget), text, widget, options),
|
|
515
437
|
);
|
|
438
|
+
|
|
439
|
+
return matches.filter((widget): widget is Gtk.Widget & T => isMatchingWidgetType(widget, options));
|
|
516
440
|
}
|
|
517
441
|
|
|
518
442
|
/**
|
|
@@ -522,11 +446,17 @@ function queryAllByText(container: Container, text: Matcher, options?: MatcherOp
|
|
|
522
446
|
* @param options Text matching options.
|
|
523
447
|
* @returns Every matching widget, or an empty array when none match.
|
|
524
448
|
*/
|
|
525
|
-
function queryAllByName
|
|
526
|
-
|
|
449
|
+
function queryAllByName<T extends Gtk.Accessible = Gtk.Widget>(
|
|
450
|
+
container: Container,
|
|
451
|
+
name: Matcher,
|
|
452
|
+
options?: MatcherOptions<T>,
|
|
453
|
+
): T[] {
|
|
454
|
+
const matches = findAll(
|
|
527
455
|
container,
|
|
528
456
|
(widget) => isMatchingWidgetType(widget, options) && isTextMatch(getWidgetName(widget), name, widget, options),
|
|
529
457
|
);
|
|
458
|
+
|
|
459
|
+
return matches.filter((widget): widget is Gtk.Widget & T => isMatchingWidgetType(widget, options));
|
|
530
460
|
}
|
|
531
461
|
|
|
532
462
|
/**
|
|
@@ -536,17 +466,19 @@ function queryAllByName(container: Container, name: Matcher, options?: MatcherOp
|
|
|
536
466
|
* @param options Text matching options.
|
|
537
467
|
* @returns Every matching widget, or an empty array when none match.
|
|
538
468
|
*/
|
|
539
|
-
function queryAllByPlaceholderText(
|
|
469
|
+
function queryAllByPlaceholderText<T extends Gtk.Accessible = Gtk.Widget>(
|
|
540
470
|
container: Container,
|
|
541
471
|
text: Matcher,
|
|
542
|
-
options?: MatcherOptions
|
|
543
|
-
):
|
|
544
|
-
|
|
472
|
+
options?: MatcherOptions<T>,
|
|
473
|
+
): T[] {
|
|
474
|
+
const matches = findAll(
|
|
545
475
|
container,
|
|
546
476
|
(widget) =>
|
|
547
477
|
isMatchingWidgetType(widget, options) &&
|
|
548
478
|
isTextMatch(getWidgetPlaceholderText(widget), text, widget, options),
|
|
549
479
|
);
|
|
480
|
+
|
|
481
|
+
return matches.filter((widget): widget is Gtk.Widget & T => isMatchingWidgetType(widget, options));
|
|
550
482
|
}
|
|
551
483
|
|
|
552
484
|
/**
|
|
@@ -556,13 +488,19 @@ function queryAllByPlaceholderText(
|
|
|
556
488
|
* @param options Text matching options.
|
|
557
489
|
* @returns Every matching widget, or an empty array when none match.
|
|
558
490
|
*/
|
|
559
|
-
function queryAllByDisplayValue
|
|
560
|
-
|
|
491
|
+
function queryAllByDisplayValue<T extends Gtk.Accessible = Gtk.Widget>(
|
|
492
|
+
container: Container,
|
|
493
|
+
value: Matcher,
|
|
494
|
+
options?: MatcherOptions<T>,
|
|
495
|
+
): T[] {
|
|
496
|
+
const matches = findAll(
|
|
561
497
|
container,
|
|
562
498
|
(widget) =>
|
|
563
499
|
isMatchingWidgetType(widget, options) &&
|
|
564
500
|
isTextMatch(getWidgetDisplayValue(widget), value, widget, options),
|
|
565
501
|
);
|
|
502
|
+
|
|
503
|
+
return matches.filter((widget): widget is Gtk.Widget & T => isMatchingWidgetType(widget, options));
|
|
566
504
|
}
|
|
567
505
|
|
|
568
506
|
export {
|
package/src/query-helpers.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
-
import {
|
|
2
|
+
import { getProperty } from "@gtkx/gi/gobject";
|
|
3
3
|
import type { Matcher, MatcherOptions } from "./types.js";
|
|
4
4
|
import { buildQueries } from "./build-queries.js";
|
|
5
5
|
import { getElementError } from "./errors.js";
|
|
@@ -27,7 +27,13 @@ const queryHelpers: QueryHelpers = {
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
const readObjectProperty = (widget: Gtk.Widget, property: string): string | null => {
|
|
30
|
-
|
|
30
|
+
let value: unknown;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
value = Reflect.apply(getProperty, undefined, [widget, property]);
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
31
37
|
|
|
32
38
|
if (typeof value === "string") {
|
|
33
39
|
return value;
|
|
@@ -51,18 +57,20 @@ const readObjectProperty = (widget: Gtk.Widget, property: string): string | null
|
|
|
51
57
|
* @param options Text matching options.
|
|
52
58
|
* @returns Every matching widget, or an empty array when none match.
|
|
53
59
|
*/
|
|
54
|
-
function queryAllByObjectProperty(
|
|
60
|
+
function queryAllByObjectProperty<T extends Gtk.Accessible = Gtk.Widget>(
|
|
55
61
|
property: string,
|
|
56
62
|
container: Container,
|
|
57
63
|
text: Matcher,
|
|
58
|
-
options?: MatcherOptions
|
|
59
|
-
):
|
|
60
|
-
|
|
64
|
+
options?: MatcherOptions<T>,
|
|
65
|
+
): T[] {
|
|
66
|
+
const matches = findAll(
|
|
61
67
|
container,
|
|
62
68
|
(widget) =>
|
|
63
69
|
isMatchingWidgetType(widget, options) &&
|
|
64
70
|
isTextMatch(readObjectProperty(widget, property), text, widget, options),
|
|
65
71
|
);
|
|
72
|
+
|
|
73
|
+
return matches.filter((widget): widget is Gtk.Widget & T => isMatchingWidgetType(widget, options));
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
/**
|
|
@@ -76,12 +84,12 @@ function queryAllByObjectProperty(
|
|
|
76
84
|
* @returns The matching widget, or null when none match.
|
|
77
85
|
* @throws When more than one widget matches.
|
|
78
86
|
*/
|
|
79
|
-
function queryByObjectProperty(
|
|
87
|
+
function queryByObjectProperty<T extends Gtk.Accessible = Gtk.Widget>(
|
|
80
88
|
property: string,
|
|
81
89
|
container: Container,
|
|
82
90
|
text: Matcher,
|
|
83
|
-
options?: MatcherOptions
|
|
84
|
-
):
|
|
91
|
+
options?: MatcherOptions<T>,
|
|
92
|
+
): T | null {
|
|
85
93
|
const matches = queryAllByObjectProperty(property, container, text, options);
|
|
86
94
|
|
|
87
95
|
if (matches.length > 1) {
|
package/src/render.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RootElement } from "@gtkx/react";
|
|
1
|
+
import type { CaughtErrorInfo, RootElement } from "@gtkx/react";
|
|
2
2
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
3
3
|
import {
|
|
4
4
|
createReconcilerRoot,
|
|
@@ -21,6 +21,7 @@ import { clearScreen, setScreen } from "./screen.js";
|
|
|
21
21
|
import { captureScreen } from "./screenshot.js";
|
|
22
22
|
import { type Container, roots, TOPLEVELS } from "./traversal.js";
|
|
23
23
|
import { resetClipboard } from "./user-event/index.js";
|
|
24
|
+
import { requireWidget } from "./widget-target.js";
|
|
24
25
|
import { findPresentedWindowFailure, findRenderedWindowFailure, mappedToplevels } from "./window-state.js";
|
|
25
26
|
import { within } from "./within.js";
|
|
26
27
|
|
|
@@ -125,6 +126,10 @@ const resolveContainer = (container: RenderOptions["container"]): ResolvedContai
|
|
|
125
126
|
return { containerInfo: container, window: null };
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
if (container !== undefined) {
|
|
130
|
+
requireWidget(container);
|
|
131
|
+
}
|
|
132
|
+
|
|
128
133
|
const window = createHarnessWindow();
|
|
129
134
|
window.setDecorated(false);
|
|
130
135
|
|
|
@@ -188,7 +193,7 @@ const settleRender = async (
|
|
|
188
193
|
|
|
189
194
|
const renderErrorHandlers = <Q extends QueryMap>(options: RenderOptions<Q> | undefined) => ({
|
|
190
195
|
onUncaughtError: handleError,
|
|
191
|
-
onCaughtError: (error: unknown, errorInfo:
|
|
196
|
+
onCaughtError: (error: unknown, errorInfo: CaughtErrorInfo): void => {
|
|
192
197
|
handleError(error);
|
|
193
198
|
options?.onCaughtError?.(error, errorInfo);
|
|
194
199
|
},
|
package/src/role-helpers.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { sortStringsBy } from "@gtkx/utils";
|
|
|
3
3
|
import { type Container, traverse } from "./traversal.js";
|
|
4
4
|
import { getWidgetAccessibleName, getWidgetLevel } from "./widget-accessible-properties.js";
|
|
5
5
|
import { getTypeTag } from "./widget-getters.js";
|
|
6
|
+
import { requireWidget } from "./widget-target.js";
|
|
6
7
|
|
|
7
8
|
const ROLE_NAMES_BY_VALUE = enumNamesByValue(Gtk.AccessibleRole);
|
|
8
9
|
|
|
@@ -125,6 +126,7 @@ const logRoles = (container: Container): void => {
|
|
|
125
126
|
*
|
|
126
127
|
* @param widget The widget to read the level from.
|
|
127
128
|
*/
|
|
128
|
-
const computeHeadingLevel = (widget: Gtk.
|
|
129
|
+
const computeHeadingLevel = (widget: Gtk.Accessible): number | undefined =>
|
|
130
|
+
getWidgetLevel(requireWidget(widget)) ?? undefined;
|
|
129
131
|
|
|
130
132
|
export { computeHeadingLevel, formatRole, formatRoleList, getRoles, prettyRoles, logRoles };
|
package/src/screenshot.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { getConfig } from "./config.js";
|
|
|
9
9
|
import { now } from "./timers.js";
|
|
10
10
|
import { descendants } from "./traversal.js";
|
|
11
11
|
import { waitFor } from "./wait-for.js";
|
|
12
|
+
import { requireWidget } from "./widget-target.js";
|
|
12
13
|
import { activeToplevel, mappedToplevels } from "./window-state.js";
|
|
13
14
|
|
|
14
15
|
type FrameProbe = {
|
|
@@ -31,6 +32,20 @@ type CaptureOutcome =
|
|
|
31
32
|
{ status: "captured"; result: ScreenshotResult } |
|
|
32
33
|
{ status: "stalled"; failure: CaptureFailure };
|
|
33
34
|
|
|
35
|
+
type BackgroundSnapshot = {
|
|
36
|
+
renderBackground(...args: [context: object, x: number, y: number, width: number, height: number]): void;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type StyledWidget = {
|
|
40
|
+
getStyleContext(): object;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type RenderSize = {
|
|
44
|
+
scale: number;
|
|
45
|
+
width: number;
|
|
46
|
+
height: number;
|
|
47
|
+
};
|
|
48
|
+
|
|
34
49
|
const DEFAULT_SCREENSHOT_INTERVAL = 10;
|
|
35
50
|
const PRESENTATION_PROBE_MS = 250;
|
|
36
51
|
|
|
@@ -47,9 +62,7 @@ const OTHER_FAILURE_HINT =
|
|
|
47
62
|
|
|
48
63
|
const NOTHING_ON_SCREEN_MESSAGE = "Nothing is on screen to capture: no toplevel window is mapped";
|
|
49
64
|
|
|
50
|
-
const bytesToBase64 = (bytes: Uint8Array | number[]): string =>
|
|
51
|
-
return Buffer.from(bytes).toString("base64");
|
|
52
|
-
};
|
|
65
|
+
const bytesToBase64 = (bytes: Uint8Array | number[]): string => Buffer.from(bytes).toString("base64");
|
|
53
66
|
|
|
54
67
|
const describeWidgetState = (widget: Gtk.Widget): string =>
|
|
55
68
|
`realized=${String(widget.getRealized())} mapped=${String(widget.getMapped())} ` +
|
|
@@ -181,16 +194,43 @@ const getChildrenNode = (widget: Gtk.Widget, scale: number): Gsk.RenderNode | nu
|
|
|
181
194
|
return snapshot.toNode();
|
|
182
195
|
};
|
|
183
196
|
|
|
197
|
+
const addWindowBackground = (
|
|
198
|
+
widget: Gtk.Widget,
|
|
199
|
+
node: Gsk.RenderNode,
|
|
200
|
+
{ scale, width, height }: RenderSize,
|
|
201
|
+
): Gsk.RenderNode => {
|
|
202
|
+
if (!(widget instanceof Gtk.Window)) {
|
|
203
|
+
return node;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const snapshot = new Gtk.Snapshot();
|
|
207
|
+
const backgroundSnapshot: BackgroundSnapshot = snapshot;
|
|
208
|
+
const styledWidget: StyledWidget = widget;
|
|
209
|
+
snapshot.save();
|
|
210
|
+
snapshot.scale(scale, scale);
|
|
211
|
+
backgroundSnapshot.renderBackground(styledWidget.getStyleContext(), 0, 0, width, height);
|
|
212
|
+
snapshot.restore();
|
|
213
|
+
snapshot.appendNode(node);
|
|
214
|
+
|
|
215
|
+
return snapshot.toNode() ?? node;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const getFallbackNode = (widget: Gtk.Widget, size: RenderSize): Gsk.RenderNode | null => {
|
|
219
|
+
const content = getChildrenNode(widget, size.scale);
|
|
220
|
+
|
|
221
|
+
return content === null ? null : addWindowBackground(widget, content, size);
|
|
222
|
+
};
|
|
223
|
+
|
|
184
224
|
const getRenderNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {
|
|
185
|
-
const
|
|
225
|
+
const content = getPaintableNode(widget, scale, width, height);
|
|
186
226
|
|
|
187
|
-
if (
|
|
188
|
-
return
|
|
227
|
+
if (content) {
|
|
228
|
+
return content;
|
|
189
229
|
}
|
|
190
230
|
|
|
191
231
|
allocateRoot(widget);
|
|
192
232
|
|
|
193
|
-
return getPaintableNode(widget, scale, width, height) ??
|
|
233
|
+
return getPaintableNode(widget, scale, width, height) ?? getFallbackNode(widget, { scale, width, height });
|
|
194
234
|
};
|
|
195
235
|
|
|
196
236
|
const renderToPng = (widget: Gtk.Widget, node: Gsk.RenderNode, width: number, height: number): ScreenshotResult => {
|
|
@@ -303,7 +343,8 @@ const captureUntilPaintable = (
|
|
|
303
343
|
* @param options Optional scale, timeout, retry interval, and output path.
|
|
304
344
|
* @returns The base64-encoded PNG data along with its mime type and dimensions.
|
|
305
345
|
*/
|
|
306
|
-
const screenshot = async (
|
|
346
|
+
const screenshot = async (target: Gtk.Accessible, options?: ScreenshotOptions): Promise<ScreenshotResult> => {
|
|
347
|
+
const widget = requireWidget(target);
|
|
307
348
|
const scale = options?.scale ?? 1;
|
|
308
349
|
|
|
309
350
|
if (!Number.isFinite(scale) || scale <= 0) {
|
package/src/suggestions.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getWidgetOwnLabel,
|
|
10
10
|
getWidgetPlaceholderText,
|
|
11
11
|
} from "./widget-accessible-properties.js";
|
|
12
|
+
import { requireWidget } from "./widget-target.js";
|
|
12
13
|
|
|
13
14
|
/** The query variant a suggestion targets. */
|
|
14
15
|
type Variant = "get" | "getAll" | "query" | "queryAll" | "find" | "findAll";
|
|
@@ -75,10 +76,11 @@ const textSuggestion = (queryName: Method, variant: Variant, value: string | nul
|
|
|
75
76
|
* @returns The best available suggestion, or undefined when no query applies.
|
|
76
77
|
*/
|
|
77
78
|
const getSuggestedQuery = (
|
|
78
|
-
|
|
79
|
+
target: Gtk.Accessible,
|
|
79
80
|
variant: Variant = "get",
|
|
80
81
|
method?: Method,
|
|
81
82
|
): Suggestion | undefined => {
|
|
83
|
+
const widget = requireWidget(target);
|
|
82
84
|
const builders: Record<Method, () => Suggestion | undefined> = {
|
|
83
85
|
Role: () => roleSuggestion(widget, variant),
|
|
84
86
|
LabelText: () =>
|